propagates PBS global visibility from barrel exports

This commit is contained in:
bQUARKz 2026-03-26 20:11:10 +00:00
parent ce55cf6405
commit 928ea53eb8
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
6 changed files with 66 additions and 9 deletions

View File

@ -31,6 +31,7 @@ import p.studio.utilities.structures.ReadOnlyList;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map;
public final class PbsFrontendCompiler { public final class PbsFrontendCompiler {
private final PbsFlowSemanticsValidator flowSemanticsValidator = new PbsFlowSemanticsValidator(); private final PbsFlowSemanticsValidator flowSemanticsValidator = new PbsFlowSemanticsValidator();
@ -103,7 +104,8 @@ public final class PbsFrontendCompiler {
ReadOnlyList.empty(), ReadOnlyList.empty(),
ReadOnlyList.empty(), ReadOnlyList.empty(),
ReadOnlyList.empty(), ReadOnlyList.empty(),
IRReservedMetadata.empty()); IRReservedMetadata.empty(),
Map.of());
} }
public IRBackendFile compileParsedFile( public IRBackendFile compileParsedFile(
@ -118,7 +120,8 @@ public final class PbsFrontendCompiler {
final ReadOnlyList<PbsAst.TopDecl> supplementalTopDecls, final ReadOnlyList<PbsAst.TopDecl> supplementalTopDecls,
final ReadOnlyList<ImportedCallableSurface> importedCallables, final ReadOnlyList<ImportedCallableSurface> importedCallables,
final ReadOnlyList<ImportedGlobalSurface> importedGlobals, final ReadOnlyList<ImportedGlobalSurface> importedGlobals,
final IRReservedMetadata importedReservedMetadata) { final IRReservedMetadata importedReservedMetadata,
final Map<String, IRGlobalVisibility> declaredGlobalVisibilityByName) {
final var effectiveModuleId = moduleId == null ? ModuleId.none() : moduleId; final var effectiveModuleId = moduleId == null ? ModuleId.none() : moduleId;
final var effectiveModulePool = modulePool == null ? ReadOnlyList.<ModuleReference>empty() : modulePool; final var effectiveModulePool = modulePool == null ? ReadOnlyList.<ModuleReference>empty() : modulePool;
final var effectiveNameTable = nameTable == null ? new NameTable() : nameTable; final var effectiveNameTable = nameTable == null ? new NameTable() : nameTable;
@ -134,6 +137,9 @@ public final class PbsFrontendCompiler {
final var effectiveImportedReservedMetadata = importedReservedMetadata == null final var effectiveImportedReservedMetadata = importedReservedMetadata == null
? IRReservedMetadata.empty() ? IRReservedMetadata.empty()
: importedReservedMetadata; : importedReservedMetadata;
final var effectiveDeclaredGlobalVisibilityByName = declaredGlobalVisibilityByName == null
? Map.<String, IRGlobalVisibility>of()
: Map.copyOf(declaredGlobalVisibilityByName);
final var semanticsErrorBaseline = diagnostics.errorCount(); final var semanticsErrorBaseline = diagnostics.errorCount();
new PbsDeclarationSemanticsValidator(effectiveNameTable).validate( new PbsDeclarationSemanticsValidator(effectiveNameTable).validate(
ast, ast,
@ -164,7 +170,7 @@ public final class PbsFrontendCompiler {
: lowerSyntheticFunctions(fileId, effectiveModuleId, ast); : lowerSyntheticFunctions(fileId, effectiveModuleId, ast);
final ReadOnlyList<IRGlobal> globals = sourceKind == SourceKind.SDK_INTERFACE final ReadOnlyList<IRGlobal> globals = sourceKind == SourceKind.SDK_INTERFACE
? ReadOnlyList.empty() ? ReadOnlyList.empty()
: lowerGlobals(fileId, effectiveModuleId, ast); : lowerGlobals(fileId, effectiveModuleId, ast, effectiveDeclaredGlobalVisibilityByName);
final var loweringErrorBaseline = diagnostics.errorCount(); final var loweringErrorBaseline = diagnostics.errorCount();
final var executableLowering = executableLoweringService.lower( final var executableLowering = executableLoweringService.lower(
fileId, fileId,
@ -243,7 +249,8 @@ public final class PbsFrontendCompiler {
private ReadOnlyList<IRGlobal> lowerGlobals( private ReadOnlyList<IRGlobal> lowerGlobals(
final FileId fileId, final FileId fileId,
final ModuleId moduleId, final ModuleId moduleId,
final PbsAst.File ast) { final PbsAst.File ast,
final Map<String, IRGlobalVisibility> declaredGlobalVisibilityByName) {
final var globals = new ArrayList<IRGlobal>(); final var globals = new ArrayList<IRGlobal>();
var nextSlot = 0; var nextSlot = 0;
for (final var topDecl : ast.topDecls()) { for (final var topDecl : ast.topDecls()) {
@ -256,7 +263,7 @@ public final class PbsFrontendCompiler {
globalDecl.name(), globalDecl.name(),
PbsReservedMetadataExtractor.typeSurfaceKey(globalDecl.explicitType()), PbsReservedMetadataExtractor.typeSurfaceKey(globalDecl.explicitType()),
nextSlot++, nextSlot++,
IRGlobalVisibility.MODULE, declaredGlobalVisibilityByName.getOrDefault(globalDecl.name(), IRGlobalVisibility.MODULE),
false, false,
p.studio.compiler.models.IRHiddenGlobalKind.NONE, p.studio.compiler.models.IRHiddenGlobalKind.NONE,
new IRGlobalOrigin( new IRGlobalOrigin(

View File

@ -89,7 +89,8 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
importedSemanticContext.supplementalTopDecls(), importedSemanticContext.supplementalTopDecls(),
importedSemanticContext.importedCallables(), importedSemanticContext.importedCallables(),
importedSemanticContext.importedGlobals(), importedSemanticContext.importedGlobals(),
importedSemanticContext.importedReservedMetadata()); importedSemanticContext.importedReservedMetadata(),
assembly.globalVisibilityByModule().getOrDefault(parsedSource.moduleId(), Map.of()));
if (diagnostics.errorCount() > compileErrorBaseline) { if (diagnostics.errorCount() > compileErrorBaseline) {
failedModuleIds.add(parsedSource.moduleId()); failedModuleIds.add(parsedSource.moduleId());
} }

View File

@ -1,5 +1,6 @@
package p.studio.compiler.services; package p.studio.compiler.services;
import p.studio.compiler.models.IRGlobalVisibility;
import p.studio.compiler.source.identifiers.ModuleId; import p.studio.compiler.source.identifiers.ModuleId;
import p.studio.compiler.source.tables.ModuleReference; import p.studio.compiler.source.tables.ModuleReference;
import p.studio.compiler.source.tables.ModuleTable; import p.studio.compiler.source.tables.ModuleTable;
@ -15,7 +16,8 @@ record PbsModuleAssembly(
Map<ModuleId, Set<ModuleId>> moduleDependencyGraph, Map<ModuleId, Set<ModuleId>> moduleDependencyGraph,
ReadOnlyList<ModuleReference> canonicalModulePool, ReadOnlyList<ModuleReference> canonicalModulePool,
Set<ModuleId> failedModuleIds, Set<ModuleId> failedModuleIds,
ModuleTable moduleTable) { ModuleTable moduleTable,
Map<ModuleId, Map<String, IRGlobalVisibility>> globalVisibilityByModule) {
PbsModuleAssembly { PbsModuleAssembly {
parsedSourceFiles = parsedSourceFiles == null ? ReadOnlyList.empty() : parsedSourceFiles; parsedSourceFiles = parsedSourceFiles == null ? ReadOnlyList.empty() : parsedSourceFiles;
canonicalModulePool = canonicalModulePool == null ? ReadOnlyList.empty() : canonicalModulePool; canonicalModulePool = canonicalModulePool == null ? ReadOnlyList.empty() : canonicalModulePool;
@ -34,6 +36,15 @@ record PbsModuleAssembly(
if (moduleTable == null) { if (moduleTable == null) {
moduleTable = new ModuleTable(); moduleTable = new ModuleTable();
} }
if (globalVisibilityByModule == null || globalVisibilityByModule.isEmpty()) {
globalVisibilityByModule = Map.of();
} else {
final var copiedVisibility = new HashMap<ModuleId, Map<String, IRGlobalVisibility>>();
for (final var entry : globalVisibilityByModule.entrySet()) {
copiedVisibility.put(entry.getKey(), Map.copyOf(entry.getValue() == null ? Map.of() : entry.getValue()));
}
globalVisibilityByModule = Map.copyOf(copiedVisibility);
}
} }
Set<ModuleId> mutableFailedModuleIds() { Set<ModuleId> mutableFailedModuleIds() {

View File

@ -2,6 +2,7 @@ package p.studio.compiler.services;
import p.studio.compiler.messages.BuildingIssueSink; import p.studio.compiler.messages.BuildingIssueSink;
import p.studio.compiler.messages.FrontendPhaseContext; import p.studio.compiler.messages.FrontendPhaseContext;
import p.studio.compiler.models.IRGlobalVisibility;
import p.studio.compiler.models.ProjectDescriptor; import p.studio.compiler.models.ProjectDescriptor;
import p.studio.compiler.models.SourceHandle; import p.studio.compiler.models.SourceHandle;
import p.studio.compiler.models.SourceKind; import p.studio.compiler.models.SourceKind;
@ -116,7 +117,34 @@ final class PbsModuleAssemblyService {
buildModuleDependencyGraph(parsedSourceFiles, moduleTable), buildModuleDependencyGraph(parsedSourceFiles, moduleTable),
emitModulePool(moduleTable), emitModulePool(moduleTable),
failedModuleIds, failedModuleIds,
moduleTable); moduleTable,
collectGlobalVisibilityByModule(modulesByCoordinates, moduleTable));
}
private Map<ModuleId, Map<String, IRGlobalVisibility>> collectGlobalVisibilityByModule(
final Map<PbsModuleVisibilityValidator.ModuleCoordinates, MutableModuleUnit> modulesByCoordinates,
final ModuleTable moduleTable) {
final var visibilityByModule = new LinkedHashMap<ModuleId, Map<String, IRGlobalVisibility>>();
for (final var entry : modulesByCoordinates.entrySet()) {
final var moduleId = moduleId(moduleTable, entry.getKey());
final var visibilityByGlobal = new LinkedHashMap<String, IRGlobalVisibility>();
for (final var barrelFile : entry.getValue().barrels) {
for (final var item : barrelFile.ast().items()) {
if (!(item instanceof PbsAst.BarrelGlobalItem globalItem)) {
continue;
}
visibilityByGlobal.put(
globalItem.name(),
globalItem.visibility() == PbsAst.Visibility.PUB
? IRGlobalVisibility.PUBLIC
: IRGlobalVisibility.MODULE);
}
}
if (!visibilityByGlobal.isEmpty()) {
visibilityByModule.put(moduleId, Map.copyOf(visibilityByGlobal));
}
}
return Map.copyOf(visibilityByModule);
} }
private void consumeSourceFile( private void consumeSourceFile(

View File

@ -3,6 +3,7 @@ package p.studio.compiler.pbs;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import p.studio.compiler.messages.HostAdmissionContext; import p.studio.compiler.messages.HostAdmissionContext;
import p.studio.compiler.models.IRHiddenGlobalKind; import p.studio.compiler.models.IRHiddenGlobalKind;
import p.studio.compiler.models.IRGlobalVisibility;
import p.studio.compiler.models.IRSyntheticCallableKind; import p.studio.compiler.models.IRSyntheticCallableKind;
import p.studio.compiler.models.SourceKind; import p.studio.compiler.models.SourceKind;
import p.studio.compiler.pbs.lexer.LexErrors; import p.studio.compiler.pbs.lexer.LexErrors;
@ -63,6 +64,7 @@ class PbsFrontendCompilerTest {
assertEquals(1, fileBackend.globals().size()); assertEquals(1, fileBackend.globals().size());
assertEquals("SCORE", fileBackend.globals().getFirst().name()); assertEquals("SCORE", fileBackend.globals().getFirst().name());
assertEquals(0, fileBackend.globals().getFirst().slot()); assertEquals(0, fileBackend.globals().getFirst().slot());
assertEquals(IRGlobalVisibility.MODULE, fileBackend.globals().getFirst().visibility());
assertFalse(fileBackend.globals().getFirst().isHidden()); assertFalse(fileBackend.globals().getFirst().isHidden());
assertEquals(IRHiddenGlobalKind.NONE, fileBackend.globals().getFirst().hiddenKind()); assertEquals(IRHiddenGlobalKind.NONE, fileBackend.globals().getFirst().hiddenKind());
assertEquals("SCORE", fileBackend.globals().getFirst().origin().derivedFromUserSymbol()); assertEquals("SCORE", fileBackend.globals().getFirst().origin().derivedFromUserSymbol());

View File

@ -4,6 +4,7 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import p.studio.compiler.messages.BuildingIssueSink; import p.studio.compiler.messages.BuildingIssueSink;
import p.studio.compiler.messages.FrontendPhaseContext; import p.studio.compiler.messages.FrontendPhaseContext;
import p.studio.compiler.models.IRGlobalVisibility;
import p.studio.compiler.models.BuildStack; import p.studio.compiler.models.BuildStack;
import p.studio.compiler.models.IRHiddenGlobalKind; import p.studio.compiler.models.IRHiddenGlobalKind;
import p.studio.compiler.models.ProjectDescriptor; import p.studio.compiler.models.ProjectDescriptor;
@ -363,11 +364,17 @@ class PBSFrontendPhaseServiceTest {
assertTrue(diagnostics.isEmpty(), diagnostics.stream().map(d -> d.getCode() + ":" + d.getMessage()).toList().toString()); assertTrue(diagnostics.isEmpty(), diagnostics.stream().map(d -> d.getCode() + ":" + d.getMessage()).toList().toString());
assertTrue(irBackend.getEntryPointCallableName().startsWith("__pbs.frame_wrapper$m")); assertTrue(irBackend.getEntryPointCallableName().startsWith("__pbs.frame_wrapper$m"));
final var scoreGlobal = irBackend.getGlobals().stream()
.filter(global -> "SCORE".equals(global.name()))
.findFirst()
.orElseThrow();
assertEquals(IRGlobalVisibility.PUBLIC, scoreGlobal.visibility());
final var bootGuard = irBackend.getGlobals().stream() final var bootGuard = irBackend.getGlobals().stream()
.filter(global -> global.hiddenKind() == IRHiddenGlobalKind.BOOT_GUARD) .filter(global -> global.hiddenKind() == IRHiddenGlobalKind.BOOT_GUARD)
.findFirst() .findFirst()
.orElseThrow(); .orElseThrow();
assertTrue(bootGuard.isHidden()); assertTrue(bootGuard.isHidden());
assertEquals(IRGlobalVisibility.MODULE, bootGuard.visibility());
assertTrue(bootGuard.name().startsWith("__pbs.boot_guard$m")); assertTrue(bootGuard.name().startsWith("__pbs.boot_guard$m"));
assertEquals(1, bootGuard.slot()); assertEquals(1, bootGuard.slot());
final var wrapper = irBackend.getExecutableFunctions().stream() final var wrapper = irBackend.getExecutableFunctions().stream()
@ -449,7 +456,8 @@ class PBSFrontendPhaseServiceTest {
function.callableName().startsWith("__pbs.module_init$m"))); function.callableName().startsWith("__pbs.module_init$m")));
assertTrue(irBackend.getExecutableFunctions().stream().anyMatch(function -> assertTrue(irBackend.getExecutableFunctions().stream().anyMatch(function ->
function.callableName().startsWith("__pbs.project_init$m"))); function.callableName().startsWith("__pbs.project_init$m")));
assertTrue(irBackend.getGlobals().stream().anyMatch(global -> "SCORE".equals(global.name()))); assertTrue(irBackend.getGlobals().stream().anyMatch(global ->
"SCORE".equals(global.name()) && global.visibility() == IRGlobalVisibility.PUBLIC));
assertTrue(irBackend.getGlobals().stream().anyMatch(global -> global.hiddenKind() == IRHiddenGlobalKind.BOOT_GUARD)); assertTrue(irBackend.getGlobals().stream().anyMatch(global -> global.hiddenKind() == IRHiddenGlobalKind.BOOT_GUARD));
} }