diff --git a/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java b/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java index 96c15fb84a..dd76e3027f 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java @@ -264,12 +264,8 @@ public final class EnsoLanguage extends TruffleLanguage { var mod = newInlineContext.getModule(); var m = org.enso.interpreter.runtime.Module.fromCompilerModule(mod); var toTruffle = - new IrToTruffle( - context, - request.getSource(), - m.getScopeBuilder(), - redirectConfigWithStrictErrors); - exprNode = toTruffle.runInline(ir, sco, ""); + new IrToTruffle(context, request.getSource(), m, redirectConfigWithStrictErrors); + exprNode = toTruffle.runInline(m.getScope(), ir, sco, ""); } else { exprNode = null; } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/Builtin.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/Builtin.java index a9014dae28..7c6773697b 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/Builtin.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/Builtin.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Map; import java.util.stream.IntStream; import org.enso.interpreter.EnsoLanguage; +import org.enso.interpreter.runtime.Module; import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition; import org.enso.interpreter.runtime.data.Type; import org.enso.interpreter.runtime.data.atom.AtomConstructor; @@ -18,8 +19,10 @@ public abstract class Builtin { this(name, Arrays.asList(params)); } - private AtomConstructor build(EnsoLanguage language, ModuleScope.Builder scope, Type type) { - var res = new AtomConstructor(name, scope.getModule(), type, true); + private AtomConstructor build( + EnsoLanguage language, ModuleScope.Builder builder, ModuleScope scope, Type type) { + var res = new AtomConstructor(name, builder.getModule(), type, true); + res.initializeBuilder(language, builder); res.initializeFields( language, scope, @@ -52,30 +55,33 @@ public abstract class Builtin { public final void initialize( EnsoLanguage language, - ModuleScope.Builder scope, + Module module, + ModuleScope.Builder builder, + ModuleScope scope, Map, Builtin> builtins) { if (type == null) { Type supertype = null; if (getSuperType() != null) { var s = builtins.get(getSuperType()); - s.initialize(language, scope, builtins); + s.initialize(language, module, builder, scope, builtins); supertype = s.getType(); } type = containsValues() - ? Type.create(name, scope, supertype, builtins.get(Any.class).getType(), true, false) - : Type.createSingleton(name, scope, supertype, true, false); + ? Type.create( + name, module, builder, supertype, builtins.get(Any.class).getType(), true, false) + : Type.createSingleton(name, module, supertype, true, false); } if (constructors == null) { var conses = getDeclaredConstructors(); constructors = new AtomConstructor[conses.size()]; for (int i = 0; i < constructors.length; i++) { - var cons = conses.get(i).build(language, scope, type); + var cons = conses.get(i).build(language, builder, scope, type); constructors[i] = cons; type.registerConstructor(cons); } } - type.generateGetters(language); + type.generateGetters(builder, language); postInitialize(); } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/debug/EvalNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/debug/EvalNode.java index e0a2109fc3..a724020e2b 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/debug/EvalNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/debug/EvalNode.java @@ -86,8 +86,8 @@ public abstract class EvalNode extends BaseNode { var sco = newInlineContext.localScope().getOrElse(LocalScope::root); var mod = newInlineContext.getModule(); var m = org.enso.interpreter.runtime.Module.fromCompilerModule(mod); - var toTruffle = new IrToTruffle(context, src, m.getScopeBuilder(), compiler.getConfig()); - var expr = toTruffle.runInline(ir, sco, ""); + var toTruffle = new IrToTruffle(context, src, m, compiler.getConfig()); + var expr = toTruffle.runInline(m.getScope(), ir, sco, ""); if (shouldCaptureResultScope) { expr = CaptureResultScopeNode.build(expr); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/Module.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/Module.java index f2072c2617..b047500188 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/Module.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/Module.java @@ -55,7 +55,7 @@ import org.enso.text.buffer.Rope; public final class Module implements EnsoObject { private ModuleSources sources; private QualifiedName name; - private ModuleScope.Builder scopeBuilder; + private ModuleScope moduleScope; private final Package pkg; private final Cache cache; private boolean wasLoadedFromCache; @@ -87,7 +87,7 @@ public final class Module implements EnsoObject { public Module(QualifiedName name, Package pkg, TruffleFile sourceFile) { this.sources = ModuleSources.NONE.newWith(sourceFile); this.name = name; - this.scopeBuilder = new ModuleScope.Builder(this); + this.moduleScope = new ModuleScope.Builder(this).build(); this.pkg = pkg; this.cache = ModuleCache.create(this); this.wasLoadedFromCache = false; @@ -105,7 +105,7 @@ public final class Module implements EnsoObject { public Module(QualifiedName name, Package pkg, String literalSource) { this.sources = ModuleSources.NONE.newWith(Rope.apply(literalSource)); this.name = name; - this.scopeBuilder = new ModuleScope.Builder(this); + this.moduleScope = new ModuleScope.Builder(this).build(); this.pkg = pkg; this.cache = ModuleCache.create(this); this.wasLoadedFromCache = false; @@ -124,7 +124,7 @@ public final class Module implements EnsoObject { public Module(QualifiedName name, Package pkg, Rope literalSource) { this.sources = ModuleSources.NONE.newWith(literalSource); this.name = name; - this.scopeBuilder = new ModuleScope.Builder(this); + this.moduleScope = new ModuleScope.Builder(this).build(); this.pkg = pkg; this.cache = ModuleCache.create(this); this.wasLoadedFromCache = false; @@ -144,14 +144,13 @@ public final class Module implements EnsoObject { this.sources = literalSource == null ? ModuleSources.NONE : ModuleSources.NONE.newWith(literalSource); this.name = name; - this.scopeBuilder = new ModuleScope.Builder(this); + this.moduleScope = new ModuleScope.Builder(this).build(); this.pkg = pkg; this.cache = ModuleCache.create(this); this.wasLoadedFromCache = false; this.synthetic = synthetic; if (synthetic) { this.compilationStage = CompilationStage.INITIAL; - scopeBuilder.build(); } else { this.compilationStage = CompilationStage.AFTER_CODEGEN; } @@ -328,7 +327,7 @@ public final class Module implements EnsoObject { } catch (IOException ignored) { } } - return scopeBuilder.build(); + return moduleScope; } /** @@ -386,7 +385,7 @@ public final class Module implements EnsoObject { private void compile(EnsoContext context) throws IOException { Source source = getSource(); if (source == null) return; - scopeBuilder = newScopeBuilder(false); + moduleScope = newScopeBuilder(false).build(); compilationStage = CompilationStage.INITIAL; context.getCompiler().run(asCompilerModule()); } @@ -456,20 +455,14 @@ public final class Module implements EnsoObject { * @return the runtime scope of this module. */ public ModuleScope getScope() { - return scopeBuilder.asModuleScope(); - } - - public ModuleScope.Builder getScopeBuilder() { - return scopeBuilder; + return moduleScope; } public ModuleScope.Builder newScopeBuilder(boolean inheritTypes) { - if (inheritTypes) { - this.scopeBuilder = this.scopeBuilder.newBuilderInheritingTypes(); - } else { - this.scopeBuilder = new ModuleScope.Builder(this); - } - return this.scopeBuilder; + var builder = // inheritTypes ? + // this.scopeBuilder.newBuilderInheritingTypes(); + new ModuleScope.Builder(this); + return builder; } /** diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/TruffleCompilerContext.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/TruffleCompilerContext.java index a4e07b1d64..cb78712f25 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/TruffleCompilerContext.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/TruffleCompilerContext.java @@ -146,7 +146,7 @@ final class TruffleCompilerContext implements CompilerContext { var s = org.enso.interpreter.runtime.scope.ModuleScope.Builder.fromCompilerModuleScopeBuilder( scopeBuilder); - new IrToTruffle(context, m.getSource(), s, config).run(module.getIr()); + new IrToTruffle(context, m.getSource(), m, config).run(module.getIr()); } // module related @@ -823,7 +823,7 @@ final class TruffleCompilerContext implements CompilerContext { @Override public CompilerContext.ModuleScopeBuilder getScopeBuilder() { return new org.enso.interpreter.runtime.scope.TruffleCompilerModuleScopeBuilder( - module.getScopeBuilder()); + module.newScopeBuilder(true)); } @Override diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Builtins.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Builtins.java index 4955e24578..26e2f3b2af 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Builtins.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Builtins.java @@ -129,7 +129,9 @@ public final class Builtins { module.compileScope(context); // Dummy compilation for an empty module ModuleScope.Builder scopeBuilder = module.newScopeBuilder(false); - builtins = initializeBuiltinTypes(loadedBuiltinConstructors, language, scopeBuilder); + builtins = + initializeBuiltinTypes( + loadedBuiltinConstructors, language, scopeBuilder, null /* as no scope */); builtinsByName = builtins.values().stream() .collect( @@ -239,7 +241,7 @@ public final class Builtins { } String builtinMethodOwner = builtinName[0]; String builtinMethodName = builtinName[1]; - Optional.ofNullable(scope.asModuleScope().getType(builtinMethodOwner, true)) + Optional.ofNullable(scope.getType(builtinMethodOwner, true)) .ifPresentOrElse( constr -> { Map> atomNodes = @@ -375,11 +377,12 @@ public final class Builtins { .collect(Collectors.toList()); } - /** Initialize builting types in the context of the given language and module scope */ + /** Initialize builting types in the context of the given language and module builder */ private Map, Builtin> initializeBuiltinTypes( List> constrs, EnsoLanguage language, - ModuleScope.Builder scope) { + ModuleScope.Builder builder, + ModuleScope scope) { Map, Builtin> builtins = new HashMap<>(); for (var constr : constrs) { @@ -391,7 +394,7 @@ public final class Builtins { } } for (var b : builtins.values()) { - b.initialize(language, scope, builtins); + b.initialize(language, getModule(), builder, scope, builtins); } return builtins; } @@ -400,11 +403,11 @@ public final class Builtins { * Returns a map of Builtin methods associated with their owner. * * @param classes a map of (already loaded) builtin methods - * @param scope Builtins scope + * @param builder Builtins builder * @return A map of builtin method nodes per builtin type name */ private Map>> readBuiltinMethodsMetadata( - Map classes, ModuleScope.Builder scope) { + Map classes, ModuleScope.Builder builder) { Map>> methodNodes = new HashMap<>(); classes.forEach( @@ -415,7 +418,7 @@ public final class Builtins { } String builtinMethodOwner = builtinName[0]; String builtinMethodName = builtinName[1]; - Optional.ofNullable(scope.asModuleScope().getType(builtinMethodOwner, true)) + Optional.ofNullable(builder.getType(builtinMethodOwner, true)) .ifPresentOrElse( constr -> { Map> atomNodes = diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/Type.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/Type.java index c233d23e32..7791bffbb1 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/Type.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/Type.java @@ -16,6 +16,7 @@ import org.enso.interpreter.Constants; import org.enso.interpreter.EnsoLanguage; import org.enso.interpreter.node.ConstantNode; import org.enso.interpreter.runtime.EnsoContext; +import org.enso.interpreter.runtime.Module; import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition; import org.enso.interpreter.runtime.callable.function.Function; import org.enso.interpreter.runtime.callable.function.FunctionSchema; @@ -30,7 +31,7 @@ import org.enso.pkg.QualifiedName; public final class Type implements EnsoObject { private final String name; - private @CompilerDirectives.CompilationFinal ModuleScope.Builder definitionScope; + private final Module definingModule; private final boolean builtin; private final Type supertype; private final Type eigentype; @@ -41,13 +42,13 @@ public final class Type implements EnsoObject { private Type( String name, - ModuleScope.Builder definitionScope, + Module definingModule, Type supertype, Type eigentype, boolean builtin, boolean isProjectPrivate) { this.name = name; - this.definitionScope = definitionScope; + this.definingModule = definingModule; this.supertype = supertype; this.builtin = builtin; this.isProjectPrivate = isProjectPrivate; @@ -57,23 +58,24 @@ public final class Type implements EnsoObject { public static Type createSingleton( String name, - ModuleScope.Builder definitionScope, + Module definingModule, Type supertype, boolean builtin, boolean isProjectPrivate) { - return new Type(name, definitionScope, supertype, null, builtin, isProjectPrivate); + return new Type(name, definingModule, supertype, null, builtin, isProjectPrivate); } public static Type create( String name, - ModuleScope.Builder definitionScope, + Module definingModule, + ModuleScope.Builder builder, Type supertype, Type any, boolean builtin, boolean isProjectPrivate) { - var eigentype = new Type(name + ".type", definitionScope, any, null, builtin, isProjectPrivate); - var result = new Type(name, definitionScope, supertype, eigentype, builtin, isProjectPrivate); - result.generateQualifiedAccessor(); + var eigentype = new Type(name + ".type", definingModule, any, null, builtin, isProjectPrivate); + var result = new Type(name, definingModule, supertype, eigentype, builtin, isProjectPrivate); + result.generateQualifiedAccessor(builder); return result; } @@ -81,7 +83,7 @@ public final class Type implements EnsoObject { return new Type("null", null, null, null, false, false); } - private void generateQualifiedAccessor() { + private void generateQualifiedAccessor(ModuleScope.Builder builder) { var node = new ConstantNode(null, this); var schemaBldr = FunctionSchema.newBuilder() @@ -92,29 +94,27 @@ public final class Type implements EnsoObject { schemaBldr.projectPrivate(); } var function = new Function(node.getCallTarget(), null, schemaBldr.build()); - definitionScope.registerMethod( - definitionScope.asModuleScope().getAssociatedType(), this.name, function); + builder.registerMethod(null /* as builder.getAssociatedType() */, this.name, function); } public QualifiedName getQualifiedName() { if (this == this.getDefinitionScope().getAssociatedType()) { - return definitionScope.getModule().getName(); + return definingModule.getName(); } else { - return definitionScope.getModule().getName().createChild(getName()); + return definingModule.getName().createChild(getName()); } } - public void setShadowDefinitions(ModuleScope.Builder scope, boolean generateAccessorsInTarget) { + public void setShadowDefinitions(ModuleScope.Builder builder, boolean generateAccessorsInTarget) { if (builtin) { - // Ensure that synthetic methods, such as getters for fields are in the scope. + // Ensure that synthetic methods, such as getters for fields are in the builder. CompilerAsserts.neverPartOfCompilation(); - this.definitionScope.registerAllMethodsOfTypeToScope(this, scope); - this.definitionScope = scope; + this.definingModule.getScope().registerAllMethodsOfTypeToScope(this, builder); if (generateAccessorsInTarget) { - generateQualifiedAccessor(); + generateQualifiedAccessor(builder); } if (getEigentype() != this) { - getEigentype().setShadowDefinitions(scope, false); + getEigentype().setShadowDefinitions(builder, false); } } else { throw new RuntimeException( @@ -127,7 +127,7 @@ public final class Type implements EnsoObject { } public ModuleScope getDefinitionScope() { - return definitionScope.asModuleScope(); + return definingModule.getScope(); } public boolean isBuiltin() { @@ -174,7 +174,7 @@ public final class Type implements EnsoObject { return allTypes; } - public void generateGetters(EnsoLanguage language) { + public void generateGetters(ModuleScope.Builder builder, EnsoLanguage language) { if (gettersGenerated) return; gettersGenerated = true; var roots = AtomConstructor.collectFieldAccessors(language, this); @@ -194,7 +194,7 @@ public final class Type implements EnsoObject { } var funcSchema = schemaBldr.build(); var f = new Function(node.getCallTarget(), null, funcSchema); - definitionScope.registerMethod(this, name, f); + builder.registerMethod(this, name, f); }); } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/atom/AtomConstructor.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/atom/AtomConstructor.java index f4609ee40c..7b0cb9ec94 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/atom/AtomConstructor.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/atom/AtomConstructor.java @@ -104,7 +104,7 @@ public final class AtomConstructor implements EnsoObject { * @return {@code this}, for convenience */ public AtomConstructor initializeFields( - EnsoLanguage language, ModuleScope.Builder scopeBuilder, ArgumentDefinition... args) { + EnsoLanguage language, ModuleScope scope, ArgumentDefinition... args) { ExpressionNode[] reads = new ExpressionNode[args.length]; for (int i = 0; i < args.length; i++) { reads[i] = ReadArgumentNode.build(i, null, null); @@ -113,13 +113,25 @@ public final class AtomConstructor implements EnsoObject { language, null, LocalScope.root(), - scopeBuilder, + scope, new ExpressionNode[0], reads, new Annotation[0], args); } + /** + * Sets the fields of this {@link AtomConstructor} and generates a constructor function. + * + * @param scopeBuilder the module scope's builder where the accessor should be registered at + * @return {@code this}, for convenience + */ + public AtomConstructor initializeBuilder( + EnsoLanguage language, ModuleScope.Builder scopeBuilder) { + this.accessor = generateQualifiedAccessor(language, scopeBuilder); + return this; + } + /** * Sets the fields of this {@link AtomConstructor} and generates a constructor function. * @@ -133,7 +145,7 @@ public final class AtomConstructor implements EnsoObject { EnsoLanguage language, SourceSection section, LocalScope localScope, - ModuleScope.Builder scopeBuilder, + ModuleScope scope, ExpressionNode[] assignments, ExpressionNode[] varReads, Annotation[] annotations, @@ -148,8 +160,7 @@ public final class AtomConstructor implements EnsoObject { boxedLayout = Layout.createBoxed(args); this.constructorFunction = buildConstructorFunction( - language, section, localScope, scopeBuilder, assignments, varReads, annotations, args); - this.accessor = generateQualifiedAccessor(language, scopeBuilder); + language, section, localScope, scope, assignments, varReads, annotations, args); return this; } @@ -170,7 +181,7 @@ public final class AtomConstructor implements EnsoObject { EnsoLanguage language, SourceSection section, LocalScope localScope, - ModuleScope.Builder scopeBuilder, + ModuleScope scope, ExpressionNode[] assignments, ExpressionNode[] varReads, Annotation[] annotations, @@ -182,7 +193,7 @@ public final class AtomConstructor implements EnsoObject { BlockNode instantiateBlock = BlockNode.buildSilent(assignments, instantiateNode); RootNode rootNode = MethodRootNode.buildConstructor( - language, localScope, scopeBuilder.asModuleScope(), instantiateBlock, section, this); + language, localScope, scope, instantiateBlock, section, this); RootCallTarget callTarget = rootNode.getCallTarget(); var schemaBldr = FunctionSchema.newBuilder().annotations(annotations).argumentDefinitions(args); if (type.isProjectPrivate()) { diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/ModuleScope.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/ModuleScope.java index 5572cd505e..a3cbee72e2 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/ModuleScope.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/ModuleScope.java @@ -255,6 +255,21 @@ public final class ModuleScope implements EnsoObject { return "Scope" + module; } + /** + * Registers all methods of a type in the provided scope. + * + * @param tpe the methods of which type should be registered + * @param scope target scope where methods should be registered to + */ + public void registerAllMethodsOfTypeToScope(Type tpe, ModuleScope.Builder scope) { + // FIXME: because of Builtins can't enable 'assert moduleScope == null;' + Type tpeKey = tpe == null ? noTypeKey : tpe; + var allTypeMethods = methods.get(tpeKey); + if (allTypeMethods != null) { + allTypeMethods.forEach((name, fun) -> scope.registerMethod(tpeKey, name, fun)); + } + } + public static class Builder { @CompilerDirectives.CompilationFinal private ModuleScope moduleScope = null; @@ -275,7 +290,8 @@ public final class ModuleScope implements EnsoObject { this.conversions = new LinkedHashMap<>(); this.imports = new LinkedHashSet<>(); this.exports = new LinkedHashSet<>(); - this.associatedType = Type.createSingleton(module.getName().item(), this, null, false, false); + this.associatedType = + Type.createSingleton(module.getName().item(), module, null, false, false); } public Builder(Module module, Map types) { @@ -286,7 +302,8 @@ public final class ModuleScope implements EnsoObject { this.conversions = new LinkedHashMap<>(); this.imports = new LinkedHashSet<>(); this.exports = new LinkedHashSet<>(); - this.associatedType = Type.createSingleton(module.getName().item(), this, null, false, false); + this.associatedType = + Type.createSingleton(module.getName().item(), module, null, false, false); } public Builder( @@ -314,6 +331,20 @@ public final class ModuleScope implements EnsoObject { return current == null ? type : current; } + /** + * Get a type registered in this builder. + * + * @param name name of the type + * @param ignoreAssociatedType ignore associated type or not? + * @return type or {@code null} + */ + public Type getType(String name, boolean ignoreAssociatedType) { + if (!ignoreAssociatedType && associatedType.getName().equals(name)) { + return associatedType; + } + return types.get(name); + } + /** * Returns a map of methods defined in this module for a given type. * @@ -354,6 +385,9 @@ public final class ModuleScope implements EnsoObject { */ public void registerMethod(Type type, String method, Supplier supply) { assert moduleScope == null; + if (type == null) { + type = this.associatedType; + } Map> methodMap = ensureMethodMapFor(type); // Builtin types will have double definition because of @@ -393,21 +427,6 @@ public final class ModuleScope implements EnsoObject { polyglotSymbols.put(name, sym); } - /** - * Registers all methods of a type in the provided scope. - * - * @param tpe the methods of which type should be registered - * @param scope target scope where methods should be registered to - */ - public void registerAllMethodsOfTypeToScope(Type tpe, ModuleScope.Builder scope) { - // FIXME: because of Builtins can't enable 'assert moduleScope == null;' - Type tpeKey = tpe == null ? noTypeKey : tpe; - var allTypeMethods = methods.get(tpeKey); - if (allTypeMethods != null) { - allTypeMethods.forEach((name, fun) -> scope.registerMethod(tpeKey, name, fun)); - } - } - /** * Adds a dependency for this module. * @@ -450,7 +469,7 @@ public final class ModuleScope implements EnsoObject { */ public ModuleScope build() { if (moduleScope == null) { - moduleScope = + return moduleScope = new ModuleScope( module, associatedType, @@ -460,8 +479,9 @@ public final class ModuleScope implements EnsoObject { Collections.unmodifiableMap(conversions), Collections.unmodifiableSet(imports), Collections.unmodifiableSet(exports)); + } else { + throw new AssertionError("Already built"); } - return moduleScope; } public static ModuleScope.Builder fromCompilerModuleScopeBuilder( @@ -469,26 +489,6 @@ public final class ModuleScope implements EnsoObject { return ((TruffleCompilerModuleScopeBuilder) scopeBuilder).unsafeScopeBuilder(); } - /** - * Return a view on `this` as a ModuleScope, rather than its builder. - * - * @return ModuleScope, if the builder has already been `built`, a proxy instance with the - * currently registered entities - */ - public ModuleScope asModuleScope() { - if (moduleScope != null) return moduleScope; - else - return new ModuleScope( - module, - associatedType, - Collections.unmodifiableMap(polyglotSymbols), - Collections.unmodifiableMap(types), - Collections.unmodifiableMap(methods), - Collections.unmodifiableMap(conversions), - Collections.unmodifiableSet(imports), - Collections.unmodifiableSet(exports)); - } - @Override public java.lang.String toString() { StringBuilder builder = new StringBuilder(); diff --git a/engine/runtime/src/main/scala/org/enso/interpreter/runtime/IrToTruffle.scala b/engine/runtime/src/main/scala/org/enso/interpreter/runtime/IrToTruffle.scala index 4fe5b7d6eb..6de0cb0b18 100644 --- a/engine/runtime/src/main/scala/org/enso/interpreter/runtime/IrToTruffle.scala +++ b/engine/runtime/src/main/scala/org/enso/interpreter/runtime/IrToTruffle.scala @@ -126,13 +126,13 @@ import org.enso.interpreter.runtime.error.DataflowError * @param context the language context instance for which this is executing * @param source the source code that corresponds to the text for which code * is being generated - * @param scopeBuilder the scope's builder of the module for which code is being generated + * @param module the module for which we are building the Truffle representation * @param compilerConfig the configuration for the compiler */ class IrToTruffle( val context: EnsoContext, val source: Source, - val scopeBuilder: ModuleScope.Builder, + val module: org.enso.interpreter.runtime.Module, val compilerConfig: CompilerConfig ) { @@ -164,6 +164,7 @@ class IrToTruffle( * @return an truffle expression representing `ir` */ def runInline( + moduleScope: ModuleScope, ir: Expression, localScope: LocalScope, scopeName: String @@ -171,8 +172,8 @@ class IrToTruffle( new ExpressionProcessor( localScope, scopeName, - scopeBuilder.getModule().getName().toString() - ).runInline(ir) + module.getName().toString() + ).runInline(moduleScope, ir) } // ========================================================================== @@ -188,7 +189,8 @@ class IrToTruffle( * @param module the module for which code should be generated */ private def processModule(module: Module): Unit = { - generateReExportBindings(module) + val scopeBuilder = this.module.newScopeBuilder(true) + generateReExportBindings(scopeBuilder, module) val bindingsMap = module .unsafeGetMetadata( @@ -229,7 +231,7 @@ class IrToTruffle( ) hostSymbol = DataflowError.withoutTrace(err, null) } - this.scopeBuilder.registerPolyglotSymbol( + scopeBuilder.registerPolyglotSymbol( poly.getVisibleName, hostSymbol ) @@ -238,10 +240,30 @@ class IrToTruffle( } val typeDefs = module.bindings.collect { case tp: Definition.Type => tp } + typeDefs.foreach { tpDef => // Register the atoms and their constructors in scope val atomDefs = tpDef.members - val asType = scopeBuilder.asModuleScope().getType(tpDef.name.name, true) + val asType = scopeBuilder.getType(tpDef.name.name, true) + val atomConstructors = + atomDefs.map(cons => asType.getConstructors.get(cons.name.name)) + atomConstructors + .zip(atomDefs) + .foreach { case (atomCons, _) => + atomCons.initializeBuilder( + language, + scopeBuilder + ) + } + asType.generateGetters(scopeBuilder, language) + } + + val moduleScope = scopeBuilder.build() + + typeDefs.foreach { tpDef => + // Register the atoms and their constructors in scope + val atomDefs = tpDef.members + val asType = moduleScope.getType(tpDef.name.name, true) val atomConstructors = atomDefs.map(cons => asType.getConstructors.get(cons.name.name)) atomConstructors @@ -267,6 +289,7 @@ class IrToTruffle( val argFactory = new DefinitionArgumentProcessor( + moduleScope = moduleScope, scope = localScope, initialName = "Type " + tpDef.name ) @@ -278,7 +301,8 @@ class IrToTruffle( for (idx <- atomDefn.arguments.indices) { val unprocessedArg = atomDefn.arguments(idx) val checkNode = checkAsTypes(unprocessedArg) - val arg = argFactory.run(unprocessedArg, idx, checkNode) + val arg = + argFactory.run(moduleScope, unprocessedArg, idx, checkNode) val occInfo = unprocessedArg .unsafeGetMetadata( AliasAnalysis, @@ -317,14 +341,14 @@ class IrToTruffle( atomDefn.name.name ) val expressionNode = - expressionProcessor.run(annotation.expression, true) + expressionProcessor.run(moduleScope, annotation.expression, true) val closureName = s"" val closureRootNode = ClosureRootNode.build( language, expressionProcessor.scope, - scopeBuilder.asModuleScope(), + moduleScope, expressionNode, - makeSection(scopeBuilder.getModule, annotation.location), + makeSection(this.module, annotation.location), closureName, true, false @@ -334,9 +358,9 @@ class IrToTruffle( if (!atomCons.isInitialized) { atomCons.initializeFields( language, - makeSection(scopeBuilder.getModule, atomDefn.location), + makeSection(this.module, atomDefn.location), localScope, - scopeBuilder, + moduleScope, assignments.toArray, reads.toArray, annotations.toArray, @@ -344,7 +368,6 @@ class IrToTruffle( ) } } - asType.generateGetters(language) } // Register the method definitions in scope @@ -498,6 +521,7 @@ class IrToTruffle( } val bodyBuilder = new expressionProcessor.BuildFunctionBody( + moduleScope, m.getFunction.getName, fn.arguments, fn.body, @@ -508,7 +532,7 @@ class IrToTruffle( m.getFunction.getCallTarget.getRootNode .asInstanceOf[BuiltinRootNode] builtinRootNode - .setModuleName(scopeBuilder.getModule.getName) + .setModuleName(this.module.getName) builtinRootNode.setTypeName(cons.getQualifiedName) val funcSchemaBldr = FunctionSchema .newBuilder() @@ -530,6 +554,7 @@ class IrToTruffle( case fn: Function => val bodyBuilder = new expressionProcessor.BuildFunctionBody( + moduleScope, fullMethodDefName, fn.arguments, fn.body, @@ -550,11 +575,11 @@ class IrToTruffle( MethodRootNode.buildOperator( language, expressionProcessor.scope, - scopeBuilder.asModuleScope(), + moduleScope, () => bodyBuilder.argsExpr._1(0), () => bodyBuilder.argsExpr._1(1), () => bodyBuilder.argsExpr._2, - makeSection(scopeBuilder.getModule, methodDef.location), + makeSection(this.module, methodDef.location), cons, methodDef.methodName.name ) @@ -562,9 +587,9 @@ class IrToTruffle( MethodRootNode.build( language, expressionProcessor.scope, - scopeBuilder.asModuleScope(), + moduleScope, () => bodyBuilder.bodyNode(), - makeSection(scopeBuilder.getModule, methodDef.location), + makeSection(this.module, methodDef.location), cons, methodDef.methodName.name ) @@ -607,16 +632,17 @@ class IrToTruffle( methodDef.methodName.name ) val expressionNode = - expressionProcessor.run(annotation.expression, true) + expressionProcessor + .run(moduleScope, annotation.expression, true) val closureName = s"" val closureRootNode = ClosureRootNode.build( language, expressionProcessor.scope, - scopeBuilder.asModuleScope(), + moduleScope, expressionNode, makeSection( - scopeBuilder.getModule, + this.module, annotation.location ), closureName, @@ -706,6 +732,7 @@ class IrToTruffle( case fn: Function => val bodyBuilder = new expressionProcessor.BuildFunctionBody( + moduleScope, methodDef.methodName.name, fn.arguments, fn.body, @@ -715,9 +742,9 @@ class IrToTruffle( val rootNode = MethodRootNode.build( language, expressionProcessor.scope, - scopeBuilder.asModuleScope(), + moduleScope, () => bodyBuilder.bodyNode(), - makeSection(scopeBuilder.getModule, methodDef.location), + makeSection(this.module, methodDef.location), toType, methodDef.methodName.name ) @@ -897,7 +924,10 @@ class IrToTruffle( expr } - private def generateReExportBindings(module: Module): Unit = { + private def generateReExportBindings( + scopeBuilder: ModuleScope.Builder, + module: Module + ): Unit = { def mkConsGetter(constructor: AtomConstructor): RuntimeFunction = constructor.getAccessorFunction() @@ -930,7 +960,7 @@ class IrToTruffle( if ( resolution.isInstanceOf[ResolvedConstructor] || !resolution.module .unsafeAsModule() - .equals(scopeBuilder.getModule.asCompilerModule) + .equals(module) ) { resolution match { case binding @ BindingsMap.ResolvedType(_, _) => @@ -1051,25 +1081,28 @@ class IrToTruffle( * @return a truffle expression that represents the same program as `ir` */ def run( + moduleScope: ModuleScope, ir: Expression, subjectToInstrumentation: Boolean - ): RuntimeExpression = run(ir, false, subjectToInstrumentation) + ): RuntimeExpression = run(moduleScope, ir, false, subjectToInstrumentation) private def run( + moduleScope: ModuleScope, ir: Expression, binding: Boolean, subjectToInstrumentation: Boolean ): RuntimeExpression = { var runtimeExpression = ir match { - case block: Expression.Block => processBlock(block) + case block: Expression.Block => processBlock(moduleScope, block) case literal: Literal => processLiteral(literal) case app: Application => - processApplication(app, subjectToInstrumentation) - case name: Name => processName(name) - case function: Function => processFunction(function, binding) - case binding: Expression.Binding => processBinding(binding) + processApplication(moduleScope, app, subjectToInstrumentation) + case name: Name => processName(moduleScope, name) + case function: Function => + processFunction(moduleScope, function, binding) + case binding: Expression.Binding => processBinding(moduleScope, binding) case caseExpr: Case => - processCase(caseExpr, subjectToInstrumentation) + processCase(moduleScope, caseExpr, subjectToInstrumentation) case typ: Tpe => processType(typ) case _: Empty => processEmpty() @@ -1108,8 +1141,11 @@ class IrToTruffle( * @param ir the IR to generate code for * @return a truffle expression that represents the same program as `ir` */ - def runInline(ir: Expression): RuntimeExpression = { - val expression = run(ir, false) + def runInline( + moduleScope: ModuleScope, + ir: Expression + ): RuntimeExpression = { + val expression = run(moduleScope, ir, false) expression } @@ -1120,7 +1156,10 @@ class IrToTruffle( * @param block the block to generate code for * @return the truffle nodes corresponding to `block` */ - private def processBlock(block: Expression.Block): RuntimeExpression = { + private def processBlock( + moduleScope: ModuleScope, + block: Expression.Block + ): RuntimeExpression = { if (block.suspended) { val scopeInfo = block .unsafeGetMetadata( @@ -1136,14 +1175,15 @@ class IrToTruffle( ) val childScope = childFactory.scope - val blockNode = childFactory.processBlock(block.copy(suspended = false)) + val blockNode = + childFactory.processBlock(moduleScope, block.copy(suspended = false)) val defaultRootNode = ClosureRootNode.build( language, childScope, - scopeBuilder.asModuleScope(), + moduleScope, blockNode, - makeSection(scopeBuilder.getModule, block.location), + makeSection(module, block.location), currentVarName, false, false @@ -1152,8 +1192,9 @@ class IrToTruffle( val callTarget = defaultRootNode.getCallTarget setLocation(CreateThunkNode.build(callTarget), block.location) } else { - val statementExprs = block.expressions.map(this.run(_, true)).toArray - val retExpr = this.run(block.returnValue, true) + val statementExprs = + block.expressions.map(this.run(moduleScope, _, true)).toArray + val retExpr = this.run(moduleScope, block.returnValue, true) val blockNode = BlockNode.build(statementExprs, retExpr) setLocation(blockNode, block.location) @@ -1186,14 +1227,16 @@ class IrToTruffle( * @return the truffle nodes corresponding to `caseExpr` */ def processCase( + moduleScope: ModuleScope, caseExpr: Case, subjectToInstrumentation: Boolean ): RuntimeExpression = caseExpr match { case Case.Expr(scrutinee, branches, isNested, location, _, _) => - val scrutineeNode = this.run(scrutinee, subjectToInstrumentation) + val scrutineeNode = + this.run(moduleScope, scrutinee, subjectToInstrumentation) - val maybeCases = branches.map(processCaseBranch) + val maybeCases = branches.map(processCaseBranch(moduleScope, _)) val allCasesValid = maybeCases.forall(_.isRight) if (allCasesValid) { @@ -1234,6 +1277,7 @@ class IrToTruffle( * the match is invalid */ def processCaseBranch( + moduleScope: ModuleScope, branch: Case.Branch ): Either[BadPatternMatch, BranchNode] = { val scopeInfo = branch @@ -1255,6 +1299,7 @@ class IrToTruffle( val arg = List(genArgFromMatchField(named)) val branchCodeNode = childProcessor.processFunctionBody( + moduleScope, arg, branch.expression, branch.location @@ -1276,6 +1321,7 @@ class IrToTruffle( val fieldsAsArgs = fieldNames.map(genArgFromMatchField) val branchCodeNode = childProcessor.processFunctionBody( + moduleScope, fieldsAsArgs, branch.expression, branch.location @@ -1421,6 +1467,7 @@ class IrToTruffle( } case literalPattern: Pattern.Literal => val branchCodeNode = childProcessor.processFunctionBody( + moduleScope, Nil, branch.expression, branch.location @@ -1494,6 +1541,7 @@ class IrToTruffle( ) val branchCodeNode = childProcessor.processFunctionBody( + moduleScope, argOfType, branch.expression, branch.location @@ -1528,6 +1576,7 @@ class IrToTruffle( ) val branchCodeNode = childProcessor.processFunctionBody( + moduleScope, argOfType, branch.expression, branch.location @@ -1594,6 +1643,7 @@ class IrToTruffle( * @return the truffle nodes corresponding to `binding` */ private def processBinding( + moduleScope: ModuleScope, binding: Expression.Binding ): RuntimeExpression = { val occInfo = binding @@ -1608,7 +1658,10 @@ class IrToTruffle( val slotIdx = scope.getVarSlotIdx(occInfo.id) setLocation( - AssignmentNode.build(this.run(binding.expression, true, true), slotIdx), + AssignmentNode.build( + this.run(moduleScope, binding.expression, true, true), + slotIdx + ), binding.location ) } @@ -1620,6 +1673,7 @@ class IrToTruffle( * @return the truffle nodes corresponding to `function` */ private def processFunction( + moduleScope: ModuleScope, function: Function, binding: Boolean ): RuntimeExpression = { @@ -1644,6 +1698,7 @@ class IrToTruffle( this.createChild(scopeName, scopeInfo.scope, "case " + currentVarName) val fn = child.processFunctionBody( + moduleScope, function.arguments, function.body, function.location, @@ -1658,7 +1713,7 @@ class IrToTruffle( * @param name the name to generate code for * @return the truffle nodes corresponding to `name` */ - def processName(name: Name): RuntimeExpression = { + def processName(moduleScope: ModuleScope, name: Name): RuntimeExpression = { val nameExpr = name match { case Name.Literal(nameStr, _, _, _, _, _) => val useInfo = name @@ -1677,11 +1732,11 @@ class IrToTruffle( nodeForResolution(resolution) } else if (nameStr == ConstantsNames.FROM_MEMBER) { ConstantObjectNode.build( - UnresolvedConversion.build(scopeBuilder.asModuleScope()) + UnresolvedConversion.build(moduleScope) ) } else { DynamicSymbolNode.build( - UnresolvedSymbol.build(nameStr, scopeBuilder.asModuleScope()) + UnresolvedSymbol.build(nameStr, moduleScope) ) } case Name.MethodReference( @@ -1694,6 +1749,7 @@ class IrToTruffle( DynamicSymbolNode.buildUnresolvedConstructor(nameStr) case Name.Self(location, _, passData, _) => processName( + moduleScope, Name.Literal( ConstantsNames.SELF_ARGUMENT, isMethod = false, @@ -1892,6 +1948,7 @@ class IrToTruffle( * argument definitions. */ class BuildFunctionBody( + val moduleScope: ModuleScope, val initialName: String, val arguments: List[DefinitionArgument], val body: Expression, @@ -1899,7 +1956,12 @@ class IrToTruffle( val subjectToInstrumentation: Boolean ) { private val argFactory = - new DefinitionArgumentProcessor(scopeName, scope, initialName) + new DefinitionArgumentProcessor( + moduleScope, + scopeName, + scope, + initialName + ) private lazy val slots = computeSlots() lazy val argsExpr = computeArgsAndExpression() @@ -1921,7 +1983,12 @@ class IrToTruffle( argSlotIdxs ) case _ => - ExpressionProcessor.this.run(body, false, subjectToInstrumentation) + ExpressionProcessor.this.run( + moduleScope, + body, + false, + subjectToInstrumentation + ) } (argExpressions.toArray, bodyExpr) } @@ -1938,7 +2005,8 @@ class IrToTruffle( val argSlots = arguments.zipWithIndex.map { case (unprocessedArg, idx) => val checkNode = checkAsTypes(unprocessedArg) - val arg = argFactory.run(unprocessedArg, idx, checkNode) + val arg = + argFactory.run(moduleScope, unprocessedArg, idx, checkNode) argDefinitions(idx) = arg val occInfo = unprocessedArg .unsafeGetMetadata( @@ -2007,19 +2075,27 @@ class IrToTruffle( * @return a truffle node representing the described function */ private def processFunctionBody( + moduleScope: ModuleScope, arguments: List[DefinitionArgument], body: Expression, location: Option[IdentifiedLocation], binding: Boolean = false ): CreateFunctionNode = { val bodyBuilder = - new BuildFunctionBody(scopeName, arguments, body, None, false) + new BuildFunctionBody( + moduleScope, + scopeName, + arguments, + body, + None, + false + ) val fnRootNode = ClosureRootNode.build( language, scope, - scopeBuilder.asModuleScope(), + moduleScope, bodyBuilder.bodyNode(), - makeSection(scopeBuilder.getModule, location), + makeSection(module, location), scopeName, false, binding @@ -2061,21 +2137,25 @@ class IrToTruffle( * @return the truffle nodes corresponding to `application` */ private def processApplication( + moduleScope: ModuleScope, application: Application, subjectToInstrumentation: Boolean ): RuntimeExpression = application match { case Application.Prefix(fn, Nil, true, _, _, _) => - run(fn, subjectToInstrumentation) + run(moduleScope, fn, subjectToInstrumentation) case app: Application.Prefix => - processApplicationWithArgs(app, subjectToInstrumentation) + processApplicationWithArgs(moduleScope, app, subjectToInstrumentation) case Application.Force(expr, location, _, _) => setLocation( - ForceNode.build(this.run(expr, subjectToInstrumentation)), + ForceNode.build( + this.run(moduleScope, expr, subjectToInstrumentation) + ), location ) case Application.Sequence(items, location, _, _) => - val itemNodes = items.map(run(_, subjectToInstrumentation)).toArray + val itemNodes = + items.map(run(moduleScope, _, subjectToInstrumentation)).toArray setLocation(SequenceLiteralNode.build(itemNodes), location) case _: Application.Typeset => setLocation( @@ -2102,13 +2182,14 @@ class IrToTruffle( } private def processApplicationWithArgs( + moduleScope: ModuleScope, application: Application.Prefix, subjectToInstrumentation: Boolean ): RuntimeExpression = { val Application.Prefix(fn, args, hasDefaultsSuspended, loc, _, _) = application val callArgFactory = - new CallArgumentProcessor(scope, scopeName, currentVarName) + new CallArgumentProcessor(moduleScope, scope, scopeName, currentVarName) val arguments = args val callArgs = new ArrayBuffer[callable.argument.CallArgument]() @@ -2126,7 +2207,7 @@ class IrToTruffle( } val appNode = ApplicationNode.build( - this.run(fn, subjectToInstrumentation), + this.run(moduleScope, fn, subjectToInstrumentation), callArgs.toArray, defaultsExecutionMode ) @@ -2147,6 +2228,7 @@ class IrToTruffle( * @param initialName suggested name for a first closure */ sealed private class CallArgumentProcessor( + val moduleScope: ModuleScope, val scope: LocalScope, val scopeName: String, private val initialName: String @@ -2196,7 +2278,7 @@ class IrToTruffle( } val argumentExpression = new ExpressionProcessor(childScope, scopeName, initialName) - .run(value, subjectToInstrumentation) + .run(moduleScope, value, subjectToInstrumentation) val result = if (!shouldCreateClosureRootNode) { argumentExpression @@ -2213,7 +2295,7 @@ class IrToTruffle( val closureRootNode = ClosureRootNode.build( language, childScope, - scopeBuilder.asModuleScope(), + moduleScope, argumentExpression, section, displayName, @@ -2254,6 +2336,7 @@ class IrToTruffle( * @param initialName suggested name for a first closure */ sealed private class DefinitionArgumentProcessor( + private val moduleScope: ModuleScope, val scopeName: String = "", val scope: LocalScope, private val initialName: String @@ -2280,6 +2363,7 @@ class IrToTruffle( * given function */ def run( + moduleScope: ModuleScope, inputArg: DefinitionArgument, position: Int, types: ReadArgumentCheckNode @@ -2289,7 +2373,7 @@ class IrToTruffle( val defaultExpression = arg.defaultValue .map( new ExpressionProcessor(scope, scopeName, initialName) - .run(_, false) + .run(moduleScope, _, false) ) .orNull @@ -2299,10 +2383,10 @@ class IrToTruffle( val defaultRootNode = ClosureRootNode.build( language, scope, - scopeBuilder.asModuleScope(), + moduleScope, defaultExpression, makeSection( - scopeBuilder.getModule, + module, arg.defaultValue.get.location() ), s"", @@ -2354,5 +2438,5 @@ class IrToTruffle( } private def scopeAssociatedType = - scopeBuilder.asModuleScope().getAssociatedType + module.getScope.getAssociatedType } diff --git a/engine/runtime/src/main/scala/org/enso/interpreter/runtime/RuntimeStubsGenerator.scala b/engine/runtime/src/main/scala/org/enso/interpreter/runtime/RuntimeStubsGenerator.scala index 292dc1cada..a3af18594c 100644 --- a/engine/runtime/src/main/scala/org/enso/interpreter/runtime/RuntimeStubsGenerator.scala +++ b/engine/runtime/src/main/scala/org/enso/interpreter/runtime/RuntimeStubsGenerator.scala @@ -52,6 +52,7 @@ class RuntimeStubsGenerator(builtins: Builtins) { if (tp.members.nonEmpty || tp.builtinType) { Type.create( tp.name, + builtins.getModule(), scope, builtins.any(), builtins.any(), @@ -61,7 +62,7 @@ class RuntimeStubsGenerator(builtins: Builtins) { } else { Type.createSingleton( tp.name, - scope, + builtins.getModule(), builtins.any(), false, isTypeProjectPrivate