implements PR028
This commit is contained in:
parent
bb5cc05c0b
commit
5c29efcbda
@ -1,52 +0,0 @@
|
|||||||
# PR-027 - PBS Builtin Metadata Extraction and IR Lowering Admission
|
|
||||||
|
|
||||||
## Briefing
|
|
||||||
|
|
||||||
Com interface modules e SDK minimo ativos, precisamos fechar a fronteira entre metadata reservada e lowering frontend (`IRBackend`), sem degradacao silenciosa.
|
|
||||||
|
|
||||||
## Motivation
|
|
||||||
|
|
||||||
As specs exigem que metadata reservada seja compilacao-only e consumivel por lowering posterior.
|
|
||||||
Tambem exigem rejeicao deterministica quando suporte ainda nao cobre algum caso.
|
|
||||||
|
|
||||||
## Target
|
|
||||||
|
|
||||||
- Extracao de metadata de attributes reservadas no grafo de interface.
|
|
||||||
- Regras de admissao/rejeicao no lowering frontend (`IRBackend` boundary).
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
- Extrair e armazenar canonical metadata de `Host`, `BuiltinType`, `IntrinsicCall`, `Slot`, `BuiltinConst`.
|
|
||||||
- Preservar informacao minima necessaria no contrato de lowering frontend.
|
|
||||||
- Emitir diagnostico deterministico para formas nao suportadas pela fronteira atual.
|
|
||||||
|
|
||||||
## Method
|
|
||||||
|
|
||||||
- Introduzir modelo interno de metadata reservada desacoplado da sintaxe bruta.
|
|
||||||
- Atualizar contrato de admissao do frontend para recusar deterministicamente casos fora da fatia implementada.
|
|
||||||
- Garantir fase/codigo/template/attribution estaveis nos diagnosticos de rejeicao.
|
|
||||||
|
|
||||||
## Acceptance Criteria
|
|
||||||
|
|
||||||
- Metadata reservada valida e acessivel apos parse+semantica+linking.
|
|
||||||
- Nenhum caso nao suportado passa silenciosamente para `IRBackend` com comportamento alterado.
|
|
||||||
- Rejeicoes de lowering frontend sao deterministicas e rastreaveis.
|
|
||||||
|
|
||||||
## Tests
|
|
||||||
|
|
||||||
- Fixtures positivas para extracao de metadata de `Color`/`Gfx`.
|
|
||||||
- Fixtures negativas com metadata invalida e rejeicao deterministica.
|
|
||||||
- Asserts de contrato diagnostico (phase, code, templateId, span).
|
|
||||||
|
|
||||||
## Non-Goals
|
|
||||||
|
|
||||||
- Implementar `IRBackend -> IRVM`.
|
|
||||||
- Definir encoding final de artifact/PBX.
|
|
||||||
|
|
||||||
## Affected Documents
|
|
||||||
|
|
||||||
- `docs/pbs/specs/12. Diagnostics Specification.md`
|
|
||||||
- `docs/pbs/specs/13. Lowering IRBackend Specification.md`
|
|
||||||
- `docs/pbs/specs/6.1. Intrinsics and Builtin Types Specification.md`
|
|
||||||
- `docs/pbs/specs/6.2. Host ABI Binding and Loader Resolution Specification.md`
|
|
||||||
|
|
||||||
@ -0,0 +1,353 @@
|
|||||||
|
package p.studio.compiler.pbs;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
|
import p.studio.compiler.messages.BuildingIssueSink;
|
||||||
|
import p.studio.compiler.messages.FrontendPhaseContext;
|
||||||
|
import p.studio.compiler.models.BuildStack;
|
||||||
|
import p.studio.compiler.models.IRBackend;
|
||||||
|
import p.studio.compiler.models.ProjectDescriptor;
|
||||||
|
import p.studio.compiler.models.SourceHandle;
|
||||||
|
import p.studio.compiler.models.SourceKind;
|
||||||
|
import p.studio.compiler.pbs.ast.PbsAst;
|
||||||
|
import p.studio.compiler.pbs.lexer.PbsLexer;
|
||||||
|
import p.studio.compiler.pbs.linking.PbsLinkErrors;
|
||||||
|
import p.studio.compiler.pbs.linking.PbsModuleVisibilityValidator;
|
||||||
|
import p.studio.compiler.pbs.parser.ParseErrors;
|
||||||
|
import p.studio.compiler.pbs.parser.PbsBarrelParser;
|
||||||
|
import p.studio.compiler.pbs.parser.PbsParser;
|
||||||
|
import p.studio.compiler.pbs.semantics.PbsSemanticsErrors;
|
||||||
|
import p.studio.compiler.services.PBSFrontendPhaseService;
|
||||||
|
import p.studio.compiler.source.diagnostics.Diagnostic;
|
||||||
|
import p.studio.compiler.source.diagnostics.DiagnosticPhase;
|
||||||
|
import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
||||||
|
import p.studio.compiler.source.identifiers.FileId;
|
||||||
|
import p.studio.compiler.source.identifiers.ProjectId;
|
||||||
|
import p.studio.compiler.source.tables.FileTable;
|
||||||
|
import p.studio.compiler.source.tables.ProjectTable;
|
||||||
|
import p.studio.compiler.utilities.SourceProviderFactory;
|
||||||
|
import p.studio.utilities.logs.LogAggregator;
|
||||||
|
import p.studio.utilities.structures.ReadOnlyList;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
class PbsGateUSdkInterfaceConformanceTest {
|
||||||
|
|
||||||
|
@TempDir
|
||||||
|
Path tempDir;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void gateU_shouldClassifySourceKindForInterfaceDeclarations() {
|
||||||
|
final var source = """
|
||||||
|
[BuiltinType(name = "Color", version = 1)]
|
||||||
|
declare builtin type Color(
|
||||||
|
[Slot(index = 0)] pub r: int
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
declare host Gfx {
|
||||||
|
[Host(module = "gfx", name = "draw_pixel", version = 1)]
|
||||||
|
fn draw_pixel(x: int, y: int, color: Color) -> void;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
final var projectDiagnostics = DiagnosticSink.empty();
|
||||||
|
final var projectBackend = new PbsFrontendCompiler().compileFile(
|
||||||
|
new FileId(10),
|
||||||
|
source,
|
||||||
|
projectDiagnostics,
|
||||||
|
SourceKind.PROJECT);
|
||||||
|
assertTrue(projectDiagnostics.stream().anyMatch(d ->
|
||||||
|
d.getCode().equals(ParseErrors.E_PARSE_ATTRIBUTES_NOT_ALLOWED.name())
|
||||||
|
|| d.getCode().equals(ParseErrors.E_PARSE_RESERVED_DECLARATION.name())));
|
||||||
|
assertEquals(0, projectBackend.functions().size());
|
||||||
|
|
||||||
|
final var sdkDiagnostics = DiagnosticSink.empty();
|
||||||
|
final var sdkBackend = new PbsFrontendCompiler().compileFile(
|
||||||
|
new FileId(11),
|
||||||
|
source,
|
||||||
|
sdkDiagnostics,
|
||||||
|
SourceKind.SDK_INTERFACE);
|
||||||
|
assertFalse(sdkDiagnostics.hasErrors());
|
||||||
|
assertEquals(0, sdkBackend.functions().size());
|
||||||
|
assertEquals(1, sdkBackend.reservedMetadata().builtinTypeSurfaces().size());
|
||||||
|
assertEquals(1, sdkBackend.reservedMetadata().hostMethodBindings().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void gateU_shouldResolveReservedImportsAndRejectMissingReservedModuleDeterministically() throws IOException {
|
||||||
|
final var positive = compileWorkspaceModule(
|
||||||
|
tempDir.resolve("gate-u-reserved-import-positive"),
|
||||||
|
"""
|
||||||
|
import { Color } from @core:color;
|
||||||
|
import { Gfx } from @sdk:gfx;
|
||||||
|
|
||||||
|
declare contract Renderer {
|
||||||
|
fn render(gfx: Gfx, color: Color) -> void;
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"pub contract Renderer;",
|
||||||
|
1,
|
||||||
|
null);
|
||||||
|
assertFalse(positive.diagnostics().stream().anyMatch(d ->
|
||||||
|
d.getCode().equals(PbsLinkErrors.E_LINK_IMPORT_MODULE_NOT_FOUND.name())));
|
||||||
|
assertFalse(positive.diagnostics().stream().anyMatch(d ->
|
||||||
|
d.getCode().equals(PbsLinkErrors.E_LINK_IMPORT_SYMBOL_UNRESOLVED.name())));
|
||||||
|
assertTrue(positive.irBackend().getReservedMetadata().builtinTypeSurfaces().stream()
|
||||||
|
.anyMatch(t -> t.sourceTypeName().equals("Color")));
|
||||||
|
assertTrue(positive.irBackend().getReservedMetadata().hostMethodBindings().stream()
|
||||||
|
.anyMatch(h -> h.ownerName().equals("Gfx")));
|
||||||
|
|
||||||
|
final var negative = compileWorkspaceModule(
|
||||||
|
tempDir.resolve("gate-u-reserved-import-negative"),
|
||||||
|
"""
|
||||||
|
import { Missing } from @sdk:missing;
|
||||||
|
fn run() -> int { return 1; }
|
||||||
|
""",
|
||||||
|
"pub fn run() -> int;",
|
||||||
|
1,
|
||||||
|
d -> d.getCode().equals(PbsLinkErrors.E_LINK_IMPORT_MODULE_NOT_FOUND.name()));
|
||||||
|
final var missingModule = firstDiagnostic(negative.diagnostics(),
|
||||||
|
d -> d.getCode().equals(PbsLinkErrors.E_LINK_IMPORT_MODULE_NOT_FOUND.name()));
|
||||||
|
assertStableDiagnosticIdentity(missingModule, PbsLinkErrors.E_LINK_IMPORT_MODULE_NOT_FOUND.name(), DiagnosticPhase.LINKING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void gateU_shouldParseReservedDeclarationsInInterfaceModeOnly() {
|
||||||
|
final var source = """
|
||||||
|
declare host Gfx {
|
||||||
|
fn draw_pixel(x: int, y: int) -> void;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
final var interfaceDiagnostics = DiagnosticSink.empty();
|
||||||
|
final var interfaceAst = PbsParser.parse(
|
||||||
|
PbsLexer.lex(source, new FileId(20), interfaceDiagnostics),
|
||||||
|
new FileId(20),
|
||||||
|
interfaceDiagnostics,
|
||||||
|
PbsParser.ParseMode.INTERFACE_MODULE);
|
||||||
|
assertFalse(interfaceDiagnostics.hasErrors());
|
||||||
|
assertEquals(1, interfaceAst.topDecls().size());
|
||||||
|
assertInstanceOf(PbsAst.HostDecl.class, interfaceAst.topDecls().getFirst());
|
||||||
|
|
||||||
|
final var ordinaryDiagnostics = DiagnosticSink.empty();
|
||||||
|
PbsParser.parse(
|
||||||
|
PbsLexer.lex(source, new FileId(21), ordinaryDiagnostics),
|
||||||
|
new FileId(21),
|
||||||
|
ordinaryDiagnostics,
|
||||||
|
PbsParser.ParseMode.ORDINARY);
|
||||||
|
final var reservedDeclDiagnostic = firstDiagnostic(ordinaryDiagnostics,
|
||||||
|
d -> d.getCode().equals(ParseErrors.E_PARSE_RESERVED_DECLARATION.name()));
|
||||||
|
assertStableDiagnosticIdentity(reservedDeclDiagnostic, ParseErrors.E_PARSE_RESERVED_DECLARATION.name(), DiagnosticPhase.SYNTAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void gateU_shouldValidateAndLinkHostBuiltinShellsWithDeterministicFailures() {
|
||||||
|
final var sourceId = new FileId(30);
|
||||||
|
final var barrelId = new FileId(31);
|
||||||
|
final var source = """
|
||||||
|
[BuiltinType(name = "Color", version = 1)]
|
||||||
|
declare builtin type Color(
|
||||||
|
[Slot(index = 0)] pub r: int
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
declare host Gfx {
|
||||||
|
[Host(module = "gfx", name = "draw_pixel", version = 1)]
|
||||||
|
fn draw_pixel(x: int, y: int, color: Color) -> void;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
final var semanticsDiagnostics = DiagnosticSink.empty();
|
||||||
|
new PbsFrontendCompiler().compileFile(sourceId, source, semanticsDiagnostics, SourceKind.SDK_INTERFACE);
|
||||||
|
assertFalse(semanticsDiagnostics.hasErrors());
|
||||||
|
|
||||||
|
final var linkDiagnostics = DiagnosticSink.empty();
|
||||||
|
final var sourceAst = PbsParser.parse(
|
||||||
|
PbsLexer.lex(source, sourceId, linkDiagnostics),
|
||||||
|
sourceId,
|
||||||
|
linkDiagnostics,
|
||||||
|
PbsParser.ParseMode.INTERFACE_MODULE);
|
||||||
|
final var validBarrelAst = PbsBarrelParser.parse(
|
||||||
|
PbsLexer.lex("pub struct Color;\npub host Gfx;\n", barrelId, linkDiagnostics),
|
||||||
|
barrelId,
|
||||||
|
linkDiagnostics);
|
||||||
|
final var validModule = new PbsModuleVisibilityValidator.ModuleUnit(
|
||||||
|
new PbsModuleVisibilityValidator.ModuleCoordinates("sdk", ReadOnlyList.wrap(List.of("gfx"))),
|
||||||
|
ReadOnlyList.wrap(List.of(new PbsModuleVisibilityValidator.SourceFile(sourceId, sourceAst))),
|
||||||
|
ReadOnlyList.wrap(List.of(new PbsModuleVisibilityValidator.BarrelFile(barrelId, validBarrelAst))));
|
||||||
|
new PbsModuleVisibilityValidator().validate(ReadOnlyList.wrap(List.of(validModule)), linkDiagnostics);
|
||||||
|
assertFalse(linkDiagnostics.stream().anyMatch(d ->
|
||||||
|
d.getCode().equals(PbsLinkErrors.E_LINK_UNRESOLVED_BARREL_ENTRY.name())));
|
||||||
|
|
||||||
|
final var negativeSemanticsDiagnostics = DiagnosticSink.empty();
|
||||||
|
new PbsFrontendCompiler().compileFile(
|
||||||
|
new FileId(32),
|
||||||
|
"fn run() -> int { return 1; }",
|
||||||
|
negativeSemanticsDiagnostics,
|
||||||
|
SourceKind.SDK_INTERFACE);
|
||||||
|
final var nonDeclarative = firstDiagnostic(negativeSemanticsDiagnostics,
|
||||||
|
d -> d.getCode().equals(PbsSemanticsErrors.E_SEM_INTERFACE_NON_DECLARATIVE_DECLARATION.name()));
|
||||||
|
assertStableDiagnosticIdentity(nonDeclarative, PbsSemanticsErrors.E_SEM_INTERFACE_NON_DECLARATIVE_DECLARATION.name(), DiagnosticPhase.STATIC_SEMANTICS);
|
||||||
|
|
||||||
|
final var negativeLinkDiagnostics = DiagnosticSink.empty();
|
||||||
|
final var invalidBarrelAst = PbsBarrelParser.parse(
|
||||||
|
PbsLexer.lex("pub host Missing;", new FileId(33), negativeLinkDiagnostics),
|
||||||
|
new FileId(33),
|
||||||
|
negativeLinkDiagnostics);
|
||||||
|
final var invalidModule = new PbsModuleVisibilityValidator.ModuleUnit(
|
||||||
|
new PbsModuleVisibilityValidator.ModuleCoordinates("sdk", ReadOnlyList.wrap(List.of("gfx"))),
|
||||||
|
ReadOnlyList.wrap(List.of(new PbsModuleVisibilityValidator.SourceFile(sourceId, sourceAst))),
|
||||||
|
ReadOnlyList.wrap(List.of(new PbsModuleVisibilityValidator.BarrelFile(new FileId(33), invalidBarrelAst))));
|
||||||
|
new PbsModuleVisibilityValidator().validate(ReadOnlyList.wrap(List.of(invalidModule)), negativeLinkDiagnostics);
|
||||||
|
final var unresolvedBarrel = firstDiagnostic(negativeLinkDiagnostics,
|
||||||
|
d -> d.getCode().equals(PbsLinkErrors.E_LINK_UNRESOLVED_BARREL_ENTRY.name()));
|
||||||
|
assertStableDiagnosticIdentity(unresolvedBarrel, PbsLinkErrors.E_LINK_UNRESOLVED_BARREL_ENTRY.name(), DiagnosticPhase.LINKING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void gateU_shouldExposeReservedMetadataAndRejectUnsupportedLoadAdmission() {
|
||||||
|
final var validSource = """
|
||||||
|
[BuiltinType(name = "Color", version = 1)]
|
||||||
|
declare builtin type Color(
|
||||||
|
[Slot(index = 0)] pub r: int,
|
||||||
|
[Slot(index = 1)] pub g: int
|
||||||
|
) {
|
||||||
|
[IntrinsicCall(name = "core.color.pack", version = 1)]
|
||||||
|
fn pack() -> int;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare host Gfx {
|
||||||
|
[Host(module = "gfx", name = "draw_pixel", version = 1)]
|
||||||
|
fn draw_pixel(x: int, y: int, color: Color) -> void;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BuiltinConst(target = "Color", name = "white", version = 1)]
|
||||||
|
declare const WHITE: Color;
|
||||||
|
""";
|
||||||
|
final var validDiagnostics = DiagnosticSink.empty();
|
||||||
|
final var validBackend = new PbsFrontendCompiler().compileFile(
|
||||||
|
new FileId(40),
|
||||||
|
validSource,
|
||||||
|
validDiagnostics,
|
||||||
|
SourceKind.SDK_INTERFACE);
|
||||||
|
assertFalse(validDiagnostics.hasErrors());
|
||||||
|
assertEquals(1, validBackend.reservedMetadata().builtinTypeSurfaces().size());
|
||||||
|
assertEquals(1, validBackend.reservedMetadata().hostMethodBindings().size());
|
||||||
|
assertEquals(1, validBackend.reservedMetadata().builtinConstSurfaces().size());
|
||||||
|
|
||||||
|
final var invalidSource = """
|
||||||
|
[BuiltinType(name = "Color", version = 1)]
|
||||||
|
declare builtin type Color(
|
||||||
|
pub r: int
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
final var invalidDiagnostics = DiagnosticSink.empty();
|
||||||
|
new PbsFrontendCompiler().compileFile(
|
||||||
|
new FileId(41),
|
||||||
|
invalidSource,
|
||||||
|
invalidDiagnostics,
|
||||||
|
SourceKind.SDK_INTERFACE);
|
||||||
|
final var unsupportedLoad = firstDiagnostic(invalidDiagnostics,
|
||||||
|
d -> d.getCode().equals(PbsLoadErrors.E_LOAD_UNSUPPORTED_RESERVED_METADATA_SURFACE.name()));
|
||||||
|
assertStableDiagnosticIdentity(unsupportedLoad, PbsLoadErrors.E_LOAD_UNSUPPORTED_RESERVED_METADATA_SURFACE.name(), DiagnosticPhase.LOAD_FACING_REJECTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
private WorkspaceCompileResult compileWorkspaceModule(
|
||||||
|
final Path projectRoot,
|
||||||
|
final String sourceContent,
|
||||||
|
final String barrelContent,
|
||||||
|
final int stdlibVersion,
|
||||||
|
final Predicate<Diagnostic> awaitedDiagnostic) throws IOException {
|
||||||
|
final var sourceRoot = projectRoot.resolve("src");
|
||||||
|
final var modulePath = sourceRoot.resolve("app");
|
||||||
|
Files.createDirectories(modulePath);
|
||||||
|
|
||||||
|
final var sourceFile = modulePath.resolve("source.pbs");
|
||||||
|
final var barrelFile = modulePath.resolve("mod.barrel");
|
||||||
|
Files.writeString(sourceFile, sourceContent);
|
||||||
|
Files.writeString(barrelFile, barrelContent);
|
||||||
|
|
||||||
|
final var projectTable = new ProjectTable();
|
||||||
|
final var fileTable = new FileTable(1);
|
||||||
|
final var projectId = projectTable.register(ProjectDescriptor.builder()
|
||||||
|
.rootPath(projectRoot)
|
||||||
|
.name("app")
|
||||||
|
.version("1.0.0")
|
||||||
|
.sourceRoots(ReadOnlyList.wrap(List.of(sourceRoot)))
|
||||||
|
.build());
|
||||||
|
|
||||||
|
registerFile(projectId, projectRoot, sourceFile, fileTable);
|
||||||
|
registerFile(projectId, projectRoot, barrelFile, fileTable);
|
||||||
|
|
||||||
|
final var context = new FrontendPhaseContext(
|
||||||
|
projectTable,
|
||||||
|
fileTable,
|
||||||
|
new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
|
||||||
|
stdlibVersion);
|
||||||
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
|
|
||||||
|
final var irBackend = new PBSFrontendPhaseService().compile(
|
||||||
|
context,
|
||||||
|
diagnostics,
|
||||||
|
LogAggregator.empty(),
|
||||||
|
BuildingIssueSink.empty());
|
||||||
|
|
||||||
|
if (awaitedDiagnostic != null) {
|
||||||
|
assertTrue(diagnostics.stream().anyMatch(awaitedDiagnostic));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new WorkspaceCompileResult(irBackend, diagnostics);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerFile(
|
||||||
|
final ProjectId projectId,
|
||||||
|
final Path projectRoot,
|
||||||
|
final Path file,
|
||||||
|
final FileTable fileTable) throws IOException {
|
||||||
|
final BasicFileAttributes attributes = Files.readAttributes(file, BasicFileAttributes.class);
|
||||||
|
fileTable.register(new SourceHandle(
|
||||||
|
projectId,
|
||||||
|
projectRoot.relativize(file),
|
||||||
|
file,
|
||||||
|
attributes.size(),
|
||||||
|
attributes.lastModifiedTime().toMillis(),
|
||||||
|
SourceProviderFactory.filesystem()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Diagnostic firstDiagnostic(
|
||||||
|
final DiagnosticSink diagnostics,
|
||||||
|
final Predicate<Diagnostic> filter) {
|
||||||
|
final Optional<Diagnostic> match = diagnostics.stream().filter(filter).findFirst();
|
||||||
|
assertTrue(match.isPresent());
|
||||||
|
return match.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertStableDiagnosticIdentity(
|
||||||
|
final Diagnostic diagnostic,
|
||||||
|
final String code,
|
||||||
|
final DiagnosticPhase phase) {
|
||||||
|
assertNotNull(diagnostic);
|
||||||
|
assertEquals(code, diagnostic.getCode());
|
||||||
|
assertEquals(phase, diagnostic.getPhase());
|
||||||
|
assertEquals(code, diagnostic.getTemplateId());
|
||||||
|
assertNotNull(diagnostic.getSpan());
|
||||||
|
assertNotNull(diagnostic.getSpan().getFileId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private record WorkspaceCompileResult(
|
||||||
|
IRBackend irBackend,
|
||||||
|
DiagnosticSink diagnostics) {
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user