diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Meta.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Meta.enso index ae77974db3e1..95ff3de02edc 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Meta.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Meta.enso @@ -209,7 +209,7 @@ type Unresolved_Symbol - new_name: The new name for the unresolved symbol. rename : Text -> Any rename self new_name = - create_unresolved_symbol new_name self.scope + create_unresolved_symbol new_name self.value ## ADVANCED GROUP Metadata @@ -219,14 +219,6 @@ type Unresolved_Symbol name : Text name self = get_unresolved_symbol_name self.value - ## ADVANCED - GROUP Metadata - ICON metadata - - Returns the definition scope of an unresolved symbol. - scope : Any - scope self = get_unresolved_symbol_scope self.value - ## ADVANCED GROUP Metadata ICON metadata @@ -348,9 +340,9 @@ get_polyglot_language value = @Builtin_Method "Meta.get_polyglot_language" Arguments: - name: The name of the unresolved symbol. - - scope: The scope in which the symbol name is unresolved. + - symbol: The unresolved symbol from which to get the scope. create_unresolved_symbol : Text -> Any -> Unresolved_Symbol -create_unresolved_symbol name scope = @Builtin_Method "Meta.create_unresolved_symbol" +create_unresolved_symbol name symbol = @Builtin_Method "Meta.create_unresolved_symbol" ## PRIVATE @@ -361,15 +353,6 @@ create_unresolved_symbol name scope = @Builtin_Method "Meta.create_unresolved_sy get_unresolved_symbol_name : Unresolved_Symbol -> Text get_unresolved_symbol_name symbol = @Builtin_Method "Meta.get_unresolved_symbol_name" -## PRIVATE - - Obtains the scope in which the provided unresolved symbol was created. - - Arguments: - - symbol: The unresolved symbol from which to get the scope. -get_unresolved_symbol_scope : Unresolved_Symbol -> Any -get_unresolved_symbol_scope symbol = @Builtin_Method "Meta.get_unresolved_symbol_scope" - ## PRIVATE Get the fields of an atom constructor. diff --git a/engine/polyglot-api/src/test/scala/org/enso/polyglot/ModuleManagementTest.scala b/engine/polyglot-api/src/test/scala/org/enso/polyglot/ModuleManagementTest.scala index 502cb310c60e..68ba211c13e7 100644 --- a/engine/polyglot-api/src/test/scala/org/enso/polyglot/ModuleManagementTest.scala +++ b/engine/polyglot-api/src/test/scala/org/enso/polyglot/ModuleManagementTest.scala @@ -69,7 +69,8 @@ class ModuleManagementTest |""".stripMargin) mainModule.reparse() - val mainFun2 = mainModule.getMethod(assocCons, "main").get + val assocCons2 = mainModule.getAssociatedType + val mainFun2 = mainModule.getMethod(assocCons2, "main").get mainFun2.execute().asLong() shouldEqual 4567L } @@ -88,13 +89,15 @@ class ModuleManagementTest mainModule.setSource(""" |main = 456 |""".stripMargin) - val mainFun2 = mainModule.getMethod(assocCons, "main").get + val assocCons2 = mainModule.getAssociatedType + val mainFun2 = mainModule.getMethod(assocCons2, "main").get mainFun2.execute().asLong() shouldEqual 456L mainModule.setSource(""" |main = 789 |""".stripMargin) - val mainFun3 = mainModule.getMethod(assocCons, "main").get + val assocCons3 = mainModule.getAssociatedType + val mainFun3 = mainModule.getMethod(assocCons3, "main").get mainFun3.execute().asLong() shouldEqual 789L ctx.writeMain(""" @@ -102,7 +105,8 @@ class ModuleManagementTest |""".stripMargin) mainModule.setSourceFile(ctx.pkg.mainFile.getAbsolutePath) - val mainFun4 = mainModule.getMethod(assocCons, "main").get + val assocCons4 = mainModule.getAssociatedType + val mainFun4 = mainModule.getMethod(assocCons4, "main").get mainFun4.execute().asLong() shouldEqual 987L } diff --git a/engine/runtime-benchmarks/src/main/java/org/enso/compiler/benchmarks/inline/InlineContextUtils.java b/engine/runtime-benchmarks/src/main/java/org/enso/compiler/benchmarks/inline/InlineContextUtils.java index db69b09543ad..2712735b561a 100644 --- a/engine/runtime-benchmarks/src/main/java/org/enso/compiler/benchmarks/inline/InlineContextUtils.java +++ b/engine/runtime-benchmarks/src/main/java/org/enso/compiler/benchmarks/inline/InlineContextUtils.java @@ -28,7 +28,7 @@ static Set localVarNames(int localVarsCnt) { * Creates a main method, generates some local variables, and fills their identifiers in the given * set. * - * @param localVarsCnt How many local variables should be initialized in the main method + * @param localVarNames local variables that should be initialized in the main method * @return Body of the main method */ static InlineSource createMainMethodWithLocalVars(Context ctx, Set localVarNames) diff --git a/engine/runtime-compiler/src/main/java/org/enso/compiler/context/CompilerContext.java b/engine/runtime-compiler/src/main/java/org/enso/compiler/context/CompilerContext.java index 0390ea8ef248..25e29cdf90af 100644 --- a/engine/runtime-compiler/src/main/java/org/enso/compiler/context/CompilerContext.java +++ b/engine/runtime-compiler/src/main/java/org/enso/compiler/context/CompilerContext.java @@ -70,11 +70,12 @@ RuntimeException formatDiagnostic( // Truffle related - void truffleRunCodegen(Module module, CompilerConfig config) throws IOException; + void truffleRunCodegen(Module module, ModuleScopeBuilder scopeBuilder, CompilerConfig config) + throws IOException; // module related - void runStubsGenerator(Module module); + void runStubsGenerator(Module module, ModuleScopeBuilder scopeBuilder); boolean typeContainsValues(String name); @@ -147,5 +148,11 @@ public abstract static class Module { public abstract org.enso.compiler.core.ir.Module getIr(); public abstract boolean isPrivate(); + + public abstract ModuleScopeBuilder getScopeBuilder(); + + public abstract ModuleScopeBuilder newScopeBuilder(); } + + public abstract static class ModuleScopeBuilder {} } diff --git a/engine/runtime-compiler/src/main/scala/org/enso/compiler/Compiler.scala b/engine/runtime-compiler/src/main/scala/org/enso/compiler/Compiler.scala index b8c04541283d..738186613d31 100644 --- a/engine/runtime-compiler/src/main/scala/org/enso/compiler/Compiler.scala +++ b/engine/runtime-compiler/src/main/scala/org/enso/compiler/Compiler.scala @@ -360,7 +360,7 @@ class Compiler( runErrorHandling(requiredModules) - requiredModules.foreach { module => + val requiredModulesWithScope = requiredModules.map { module => if ( !context .getCompilationStage(module) @@ -368,16 +368,21 @@ class Compiler( CompilationStage.AFTER_RUNTIME_STUBS ) ) { - context.runStubsGenerator(module) + val moduleScopeBuilder = module.getScopeBuilder() + context.runStubsGenerator(module, moduleScopeBuilder) context.updateModule( module, { u => u.compilationStage(CompilationStage.AFTER_RUNTIME_STUBS) } ) + (module, moduleScopeBuilder) + } else { + (module, module.getScopeBuilder) } } - requiredModules.foreach { module => + + requiredModulesWithScope.foreach { case (module, moduleScopeBuilder) => if ( !context .getCompilationStage(module) @@ -393,7 +398,7 @@ class Compiler( context.getModuleName(module) ) - context.truffleRunCodegen(module, config) + context.truffleRunCodegen(module, moduleScopeBuilder, config) } context.updateModule( module, diff --git a/engine/runtime-instrument-common/src/main/java/org/enso/interpreter/service/ExecutionService.java b/engine/runtime-instrument-common/src/main/java/org/enso/interpreter/service/ExecutionService.java index a9203f14b21d..b144d550759c 100644 --- a/engine/runtime-instrument-common/src/main/java/org/enso/interpreter/service/ExecutionService.java +++ b/engine/runtime-instrument-common/src/main/java/org/enso/interpreter/service/ExecutionService.java @@ -120,10 +120,10 @@ public FunctionCallInstrumentationNode.FunctionCall prepareFunctionCall( Module module, String typeName, String methodName) throws TypeNotFoundException, MethodNotFoundException { ModuleScope scope = module.compileScope(context); - Type type = - scope - .getType(typeName) - .orElseThrow(() -> new TypeNotFoundException(module.getName().toString(), typeName)); + Type type = scope.getType(typeName, false); + if (type == null) { + throw new TypeNotFoundException(module.getName().toString(), typeName); + } Function function = scope.lookupMethodDefinition(type, methodName); if (function == null) { throw new MethodNotFoundException(module.getName().toString(), type, methodName); diff --git a/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/job/UpsertVisualizationJob.scala b/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/job/UpsertVisualizationJob.scala index f1056bbdc587..92cf691501a2 100644 --- a/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/job/UpsertVisualizationJob.scala +++ b/engine/runtime-instrument-common/src/main/scala/org/enso/interpreter/instrument/job/UpsertVisualizationJob.scala @@ -63,70 +63,66 @@ class UpsertVisualizationJob( ctx.locking.withContextLock( config.executionContextId, this.getClass, - () => - ctx.locking.withWriteCompilationLock( - this.getClass, - () => { - val maybeCallable = - UpsertVisualizationJob.evaluateVisualizationExpression( - config.visualizationModule, - config.expression - ) - - maybeCallable match { - case Left(ModuleNotFound(moduleName)) => - ctx.endpoint.sendToClient( - Api.Response(Api.ModuleNotFound(moduleName)) - ) - None + () => { + val maybeCallable = + UpsertVisualizationJob.evaluateVisualizationExpression( + config.visualizationModule, + config.expression + ) - case Left(EvaluationFailed(message, result)) => - replyWithExpressionFailedError( + maybeCallable match { + case Left(ModuleNotFound(moduleName)) => + ctx.endpoint.sendToClient( + Api.Response(Api.ModuleNotFound(moduleName)) + ) + None + + case Left(EvaluationFailed(message, result)) => + replyWithExpressionFailedError( + config.executionContextId, + visualizationId, + expressionId, + message, + result + ) + None + + case Right(EvaluationResult(module, callable, arguments)) => + val visualization = + UpsertVisualizationJob.updateAttachedVisualization( + visualizationId, + expressionId, + module, + config, + callable, + arguments + ) + val stack = + ctx.contextManager.getStack(config.executionContextId) + val runtimeCache = stack.headOption + .flatMap(frame => Option(frame.cache)) + val cachedValue = runtimeCache + .flatMap(c => Option(c.get(expressionId))) + UpsertVisualizationJob.requireVisualizationSynchronization( + stack, + expressionId + ) + cachedValue match { + case Some(value) => + ProgramExecutionSupport.executeAndSendVisualizationUpdate( config.executionContextId, - visualizationId, + runtimeCache.getOrElse(new RuntimeCache), + stack.headOption.get.syncState, + visualization, expressionId, - message, - result + value ) None - - case Right(EvaluationResult(module, callable, arguments)) => - val visualization = - UpsertVisualizationJob.updateAttachedVisualization( - visualizationId, - expressionId, - module, - config, - callable, - arguments - ) - val stack = - ctx.contextManager.getStack(config.executionContextId) - val runtimeCache = stack.headOption - .flatMap(frame => Option(frame.cache)) - val cachedValue = runtimeCache - .flatMap(c => Option(c.get(expressionId))) - UpsertVisualizationJob.requireVisualizationSynchronization( - stack, - expressionId - ) - cachedValue match { - case Some(value) => - ProgramExecutionSupport.executeAndSendVisualizationUpdate( - config.executionContextId, - runtimeCache.getOrElse(new RuntimeCache), - stack.headOption.get.syncState, - visualization, - expressionId, - value - ) - None - case None => - Some(Executable(config.executionContextId, stack)) - } + case None => + Some(Executable(config.executionContextId, stack)) } - } - ) + } + } ) } @@ -284,7 +280,6 @@ object UpsertVisualizationJob { ): Either[EvaluationFailure, AnyRef] = { Either .catchNonFatal { - ctx.locking.assertWriteCompilationLock() ctx.executionService.evaluateExpression(module, argumentExpression) } .leftFlatMap { @@ -355,7 +350,6 @@ object UpsertVisualizationJob { .catchNonFatal { expression match { case Api.VisualizationExpression.Text(_, expression, _) => - ctx.locking.assertWriteCompilationLock() ctx.executionService.evaluateExpression( expressionModule, expression @@ -504,7 +498,10 @@ object UpsertVisualizationJob { callback, arguments ) - invalidateCaches(visualization) + ctx.locking.withWriteCompilationLock( + this.getClass, + () => invalidateCaches(visualization) + ) ctx.contextManager.upsertVisualization( visualizationConfig.executionContextId, visualization diff --git a/engine/runtime-parser/src/main/java/org/enso/compiler/core/IR.java b/engine/runtime-parser/src/main/java/org/enso/compiler/core/IR.java index 1f446a948fc2..0450237f651f 100644 --- a/engine/runtime-parser/src/main/java/org/enso/compiler/core/IR.java +++ b/engine/runtime-parser/src/main/java/org/enso/compiler/core/IR.java @@ -52,7 +52,7 @@ public interface IR { * @return the external identifier for this IR node */ default Option<@ExternalID UUID> getExternalId() { - return location().flatMap(l -> l.id().map(id -> id)); + return location().flatMap(l -> l.id()); } /** diff --git a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/CallArgument.scala b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/CallArgument.scala index c0d0dd04f73d..8972865c1e56 100644 --- a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/CallArgument.scala +++ b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/CallArgument.scala @@ -138,7 +138,8 @@ object CallArgument { |""".toSingleLine /** @inheritdoc */ - override def children: List[IR] = name.toList :+ value + override def children: List[IR] = + name.map(List(_, value)).getOrElse(List(value)) /** @inheritdoc */ override def showCode(indent: Int): String = { 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 3c3da9c90013..96c15fb84a0b 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java @@ -265,7 +265,10 @@ protected ExecutableNode parse(InlineParsingRequest request) throws InlineParsin var m = org.enso.interpreter.runtime.Module.fromCompilerModule(mod); var toTruffle = new IrToTruffle( - context, request.getSource(), m.getScope(), redirectConfigWithStrictErrors); + context, + request.getSource(), + m.getScopeBuilder(), + redirectConfigWithStrictErrors); exprNode = toTruffle.runInline(ir, sco, ""); } else { exprNode = null; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodImportResolver.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodImportResolver.java index 26b06edd928f..2dfcc96c1683 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodImportResolver.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodImportResolver.java @@ -4,7 +4,6 @@ import java.io.IOException; import java.util.Collections; import java.util.List; -import java.util.stream.Stream; import org.enso.compiler.phase.ImportResolverAlgorithm; import org.enso.editions.LibraryName; import org.enso.interpreter.runtime.EnsoContext; @@ -74,10 +73,8 @@ protected List hiddenNames(Object ex) { } @Override - protected List definedEntities(UnresolvedSymbol name) { - var associatedType = module.getScope().getType(name.getName()); - var allRelativeTypes = module.getScope().getTypes().values(); - return Stream.concat(associatedType.stream(), allRelativeTypes.stream()).toList(); + protected List definedEntities(UnresolvedSymbol symbol) { + return module.getScope().getAllTypes(symbol.getName()); } @Override diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/InvokeFunctionNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/InvokeFunctionNode.java index 1d15d15f9c75..983d3f5f4d04 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/InvokeFunctionNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/dispatch/InvokeFunctionNode.java @@ -29,7 +29,6 @@ import org.enso.interpreter.runtime.callable.function.FunctionSchema; import org.enso.interpreter.runtime.data.atom.AtomConstructor; import org.enso.interpreter.runtime.error.PanicException; -import org.enso.interpreter.runtime.scope.ModuleScope; import org.enso.interpreter.runtime.state.State; import org.enso.pkg.Package; @@ -276,33 +275,22 @@ private boolean isInSameProject(Function function) { private Package getThisProject() { if (getRootNode() instanceof EnsoRootNode thisRootNode) { - var modScope = thisRootNode.getModuleScope(); - if (modScope != null) { - return modScope.getModule().getPackage(); - } + return thisRootNode.getModuleScope().getModule().getPackage(); } return null; } private Package getFunctionProject(Function function) { - var modScope = getModuleScopeForFunction(function); - if (modScope != null) { - return modScope.getModule().getPackage(); - } - return null; - } - - private ModuleScope getModuleScopeForFunction(Function function) { var cons = AtomConstructor.accessorFor(function); if (cons != null) { - return cons.getDefinitionScope(); + return cons.getDefinitionScope().getModule().getPackage(); } cons = MethodRootNode.constructorFor(function); if (cons != null) { - return cons.getDefinitionScope(); + return cons.getDefinitionScope().getModule().getPackage(); } if (function.getCallTarget().getRootNode() instanceof EnsoRootNode ensoRootNode) { - return ensoRootNode.getModuleScope(); + return ensoRootNode.getModuleScope().getModule().getPackage(); } return 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 73c96595f3a9..a9014dae2880 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 @@ -18,10 +18,11 @@ public Cons(String name, String... params) { this(name, Arrays.asList(params)); } - private AtomConstructor build(EnsoLanguage language, ModuleScope scope, Type type) { - var res = new AtomConstructor(name, scope, type, true); + private AtomConstructor build(EnsoLanguage language, ModuleScope.Builder scope, Type type) { + var res = new AtomConstructor(name, scope.getModule(), type, true); res.initializeFields( language, + scope, IntStream.range(0, params.size()) .mapToObj( i -> @@ -50,7 +51,9 @@ protected List getDeclaredConstructors() { } public final void initialize( - EnsoLanguage language, ModuleScope scope, Map, Builtin> builtins) { + EnsoLanguage language, + ModuleScope.Builder scope, + Map, Builtin> builtins) { if (type == null) { Type supertype = null; if (getSuperType() != null) { diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/CreateUnresolvedSymbolNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/CreateUnresolvedSymbolNode.java index d3bfac638000..9506cc0c7888 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/CreateUnresolvedSymbolNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/CreateUnresolvedSymbolNode.java @@ -1,11 +1,16 @@ package org.enso.interpreter.node.expression.builtin.meta; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.Constants; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.text.util.ExpectStringNode; +import org.enso.interpreter.runtime.EnsoContext; +import org.enso.interpreter.runtime.builtin.Builtins; import org.enso.interpreter.runtime.callable.UnresolvedConversion; import org.enso.interpreter.runtime.callable.UnresolvedSymbol; +import org.enso.interpreter.runtime.error.PanicException; import org.enso.interpreter.runtime.scope.ModuleScope; @BuiltinMethod( @@ -13,10 +18,33 @@ name = "create_unresolved_symbol", description = "Creates a new unresolved symbol node", autoRegister = false) -public class CreateUnresolvedSymbolNode extends Node { +public abstract class CreateUnresolvedSymbolNode extends Node { private @Child ExpectStringNode expectStringNode = ExpectStringNode.build(); - Object execute(Object name, ModuleScope scope) { + static CreateUnresolvedSymbolNode build() { + return CreateUnresolvedSymbolNodeGen.create(); + } + + abstract Object execute(Object name, Object symbol); + + @Specialization + Object doSymbol(Object name, UnresolvedSymbol symbol) { + return executeWithScope(name, symbol.getScope()); + } + + @Specialization + Object doConversion(Object name, UnresolvedConversion symbol) { + return executeWithScope(name, symbol.getScope()); + } + + @Fallback + ModuleScope doFallback(Object name, Object symbol) { + Builtins builtins = EnsoContext.get(this).getBuiltins(); + throw new PanicException( + builtins.error().makeTypeError("Unresolved_Symbol", symbol, "symbol"), this); + } + + private Object executeWithScope(Object name, ModuleScope scope) { String result = expectStringNode.execute(name); if (result.equals(Constants.Names.FROM_MEMBER)) { return UnresolvedConversion.build(scope); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsNode.java index 4962edee6390..71d15c5e591d 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsNode.java @@ -127,7 +127,7 @@ static Type findTypeUncached(Object obj) { private static boolean isDefinedIn(ModuleScope scope, Function fn) { if (fn.getCallTarget().getRootNode() instanceof EnsoRootNode ensoRoot) { - return ensoRoot.getModuleScope() == scope; + return ensoRoot.getModuleScope().getModule() == scope.getModule(); } else { return false; } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/FindTypeByFqnNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/FindTypeByFqnNode.java index 2c8b62df273a..757e48abcf50 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/FindTypeByFqnNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/FindTypeByFqnNode.java @@ -21,9 +21,9 @@ Object execute(Text fqn) { var moduleName = fullName.getParent().get(); var maybeModule = ctx.getTopScope().getModule(moduleName.toString()); if (maybeModule.isPresent()) { - var foundType = maybeModule.get().getScope().getType(fullName.item()); - if (foundType.isPresent()) { - return foundType.get(); + var foundType = maybeModule.get().getScope().getType(fullName.item(), false); + if (foundType != null) { + return foundType; } } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetUnresolvedSymbolScopeNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetUnresolvedSymbolScopeNode.java deleted file mode 100644 index e3e821ae8321..000000000000 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetUnresolvedSymbolScopeNode.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.enso.interpreter.node.expression.builtin.meta; - -import com.oracle.truffle.api.dsl.Fallback; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; -import org.enso.interpreter.dsl.BuiltinMethod; -import org.enso.interpreter.runtime.EnsoContext; -import org.enso.interpreter.runtime.builtin.Builtins; -import org.enso.interpreter.runtime.callable.UnresolvedConversion; -import org.enso.interpreter.runtime.callable.UnresolvedSymbol; -import org.enso.interpreter.runtime.error.PanicException; -import org.enso.interpreter.runtime.scope.ModuleScope; - -@BuiltinMethod( - type = "Meta", - name = "get_unresolved_symbol_scope", - description = "Gets the scope of an unresolved symbol", - autoRegister = false) -public abstract class GetUnresolvedSymbolScopeNode extends Node { - static GetUnresolvedSymbolScopeNode build() { - return GetUnresolvedSymbolScopeNodeGen.create(); - } - - abstract ModuleScope execute(Object symbol); - - @Specialization - ModuleScope doSymbol(UnresolvedSymbol symbol) { - return symbol.getScope(); - } - - @Specialization - ModuleScope doConversion(UnresolvedConversion symbol) { - return symbol.getScope(); - } - - @Fallback - ModuleScope doFallback(Object symbol) { - Builtins builtins = EnsoContext.get(this).getBuiltins(); - throw new PanicException( - builtins.error().makeTypeError("Unresolved_Symbol", symbol, "symbol"), this); - } -} 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 c3442c940136..e0a2109fc38e 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,7 +86,7 @@ RootCallTarget parseExpression(LocalScope scope, ModuleScope moduleScope, String 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.getScope(), compiler.getConfig()); + var toTruffle = new IrToTruffle(context, src, m.getScopeBuilder(), compiler.getConfig()); var expr = toTruffle.runInline(ir, sco, ""); if (shouldCaptureResultScope) { 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 f7b95c3af6e9..f2072c2617b6 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 @@ -53,18 +53,18 @@ /** Represents a source module with a known location. */ @ExportLibrary(InteropLibrary.class) public final class Module implements EnsoObject { - private ModuleScope scope; private ModuleSources sources; + private QualifiedName name; + private ModuleScope.Builder scopeBuilder; + private final Package pkg; + private final Cache cache; + private boolean wasLoadedFromCache; + private final boolean synthetic; private PatchedModuleValues patchedValues; private final Map allSources = new WeakHashMap<>(); - private final Package pkg; private CompilationStage compilationStage = CompilationStage.INITIAL; private org.enso.compiler.core.ir.Module ir; private Map uuidsMap; - private QualifiedName name; - private final Cache cache; - private boolean wasLoadedFromCache; - private final boolean synthetic; /** * This list is filled in case there is a directory with the same name as this module. The @@ -86,8 +86,9 @@ public final class Module implements EnsoObject { */ public Module(QualifiedName name, Package pkg, TruffleFile sourceFile) { this.sources = ModuleSources.NONE.newWith(sourceFile); - this.pkg = pkg; this.name = name; + this.scopeBuilder = new ModuleScope.Builder(this); + this.pkg = pkg; this.cache = ModuleCache.create(this); this.wasLoadedFromCache = false; this.synthetic = false; @@ -103,8 +104,9 @@ public Module(QualifiedName name, Package pkg, TruffleFile sourceFi */ public Module(QualifiedName name, Package pkg, String literalSource) { this.sources = ModuleSources.NONE.newWith(Rope.apply(literalSource)); - this.pkg = pkg; this.name = name; + this.scopeBuilder = new ModuleScope.Builder(this); + this.pkg = pkg; this.cache = ModuleCache.create(this); this.wasLoadedFromCache = false; this.patchedValues = new PatchedModuleValues(this); @@ -121,8 +123,9 @@ public Module(QualifiedName name, Package pkg, String literalSource */ public Module(QualifiedName name, Package pkg, Rope literalSource) { this.sources = ModuleSources.NONE.newWith(literalSource); - this.pkg = pkg; this.name = name; + this.scopeBuilder = new ModuleScope.Builder(this); + this.pkg = pkg; this.cache = ModuleCache.create(this); this.wasLoadedFromCache = false; this.patchedValues = new PatchedModuleValues(this); @@ -141,12 +144,17 @@ private Module( this.sources = literalSource == null ? ModuleSources.NONE : ModuleSources.NONE.newWith(literalSource); this.name = name; - this.scope = new ModuleScope(this); + this.scopeBuilder = new ModuleScope.Builder(this); this.pkg = pkg; - this.compilationStage = synthetic ? CompilationStage.INITIAL : CompilationStage.AFTER_CODEGEN; 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; + } } /** @@ -254,7 +262,7 @@ public List getDirectModulesRefs() { * @see PatchedModuleValues */ public void setLiteralSource(Rope source, SimpleUpdate update) { - if (this.scope != null && update != null) { + if (update != null) { var change = update.ir(); if (this.patchedValues == null) { this.patchedValues = new PatchedModuleValues(this); @@ -314,22 +322,13 @@ public String getPath() { * @return the scope defined by this module */ public ModuleScope compileScope(EnsoContext context) { - ensureScopeExists(); if (!compilationStage.isAtLeast(CompilationStage.AFTER_CODEGEN)) { try { compile(context); } catch (IOException ignored) { } } - return scope; - } - - /** Create scope if it does not exist. */ - public void ensureScopeExists() { - if (scope == null) { - scope = new ModuleScope(this); - compilationStage = CompilationStage.INITIAL; - } + return scopeBuilder.build(); } /** @@ -385,10 +384,9 @@ public final boolean isModuleSource(Source s) { } private void compile(EnsoContext context) throws IOException { - ensureScopeExists(); Source source = getSource(); if (source == null) return; - scope.reset(); + scopeBuilder = newScopeBuilder(false); compilationStage = CompilationStage.INITIAL; context.getCompiler().run(asCompilerModule()); } @@ -458,21 +456,20 @@ void unsafeSetIr(org.enso.compiler.core.ir.Module ir) { * @return the runtime scope of this module. */ public ModuleScope getScope() { - return scope; + return scopeBuilder.asModuleScope(); } - /** - * Returns the runtime scope of this module that filters out only the requested types. If the list - * of requested types is empty, returns the unchanged runtime scope. - * - * @param types a list of types to include in the scope - */ - public ModuleScope getScope(List types) { - if (types.isEmpty()) { - return scope; + public ModuleScope.Builder getScopeBuilder() { + return scopeBuilder; + } + + public ModuleScope.Builder newScopeBuilder(boolean inheritTypes) { + if (inheritTypes) { + this.scopeBuilder = this.scopeBuilder.newBuilderInheritingTypes(); } else { - return scope.withTypes(types); + this.scopeBuilder = new ModuleScope.Builder(this); } + return this.scopeBuilder; } /** @@ -584,7 +581,7 @@ private static Type getType(ModuleScope scope, Object[] args) throw UnsupportedTypeException.create(args, "First argument must be a string"); } String name = iop.asString(args[0]); - return scope.getTypes().get(name); + return scope.getType(name, true); } private static Module reparse(Module module, Object[] args, EnsoContext context) @@ -601,7 +598,7 @@ private static Module reparse(Module module, Object[] args, EnsoContext context) } private static Module setSource(Module module, Object[] args, EnsoContext context) - throws ArityException, UnsupportedTypeException, UnsupportedMessageException { + throws UnsupportedTypeException, UnsupportedMessageException { var iop = InteropLibrary.getUncached(); if (!iop.isString(args[0])) { throw UnsupportedTypeException.create(args, "First argument must be a string"); 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 dde34c544f4d..e1c8c7f8ee0d 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 @@ -137,10 +137,16 @@ public Thread createSystemThread(Runnable r) { } @Override - public void truffleRunCodegen(CompilerContext.Module module, CompilerConfig config) + public void truffleRunCodegen( + CompilerContext.Module module, + CompilerContext.ModuleScopeBuilder scopeBuilder, + CompilerConfig config) throws IOException { var m = org.enso.interpreter.runtime.Module.fromCompilerModule(module); - new IrToTruffle(context, m.getSource(), m.getScope(), config).run(module.getIr()); + var s = + org.enso.interpreter.runtime.scope.ModuleScope.Builder.fromCompilerModuleScopeBuilder( + scopeBuilder); + new IrToTruffle(context, m.getSource(), s, config).run(module.getIr()); } // module related @@ -241,8 +247,13 @@ public void initializeBuiltinsIr( } @Override - public void runStubsGenerator(CompilerContext.Module module) { - stubsGenerator.run(((Module) module).unsafeModule()); + public void runStubsGenerator( + CompilerContext.Module module, CompilerContext.ModuleScopeBuilder scopeBuilder) { + var m = ((Module) module).unsafeModule(); + var s = + ((org.enso.interpreter.runtime.scope.TruffleCompilerModuleScopeBuilder) scopeBuilder) + .unsafeScopeBuilder(); + stubsGenerator.run(m.getIr(), s); } @Override @@ -723,8 +734,7 @@ public void close() { module.module.setLoadedFromCache(loadedFromCache); } if (resetScope) { - module.module.ensureScopeExists(); - module.module.getScope().reset(); + module.module.newScopeBuilder(true); } if (invalidateCache) { module.module.getCache().invalidate(context); @@ -817,6 +827,18 @@ public boolean isPrivate() { return module.isPrivate(); } + @Override + public CompilerContext.ModuleScopeBuilder getScopeBuilder() { + return new org.enso.interpreter.runtime.scope.TruffleCompilerModuleScopeBuilder( + module.getScopeBuilder()); + } + + @Override + public ModuleScopeBuilder newScopeBuilder() { + return new org.enso.interpreter.runtime.scope.TruffleCompilerModuleScopeBuilder( + module.newScopeBuilder(false)); + } + @Override public int hashCode() { int hash = 7; 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 38b944b0e9fb..4955e2457869 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 @@ -126,19 +126,20 @@ public static class Debug { public Builtins(EnsoContext context) { EnsoLanguage language = context.getLanguage(); module = Module.empty(QualifiedName.fromString(MODULE_NAME), null); - scope = module.compileScope(context); + module.compileScope(context); // Dummy compilation for an empty module + ModuleScope.Builder scopeBuilder = module.newScopeBuilder(false); - builtins = initializeBuiltinTypes(loadedBuiltinConstructors, language, scope); + builtins = initializeBuiltinTypes(loadedBuiltinConstructors, language, scopeBuilder); builtinsByName = builtins.values().stream() .collect( Collectors.toMap( v -> v.getType().getName(), java.util.function.Function.identity())); if (TruffleOptions.AOT) { - builtinMethodNodes = readBuiltinMethodsMetadata(loadedBuiltinMethods, scope); - registerBuiltinMethods(scope, language); + builtinMethodNodes = readBuiltinMethodsMetadata(loadedBuiltinMethods, scopeBuilder); + registerBuiltinMethods(scopeBuilder, language); } else { - builtinMethodNodes = registerBuiltinMethodsLazily(scope, language); + builtinMethodNodes = registerBuiltinMethodsLazily(scopeBuilder, language); } ordering = getBuiltinType(Ordering.class); @@ -172,6 +173,7 @@ public Builtins(EnsoContext context) { system = new System(this); number = new Number(this); special = new Special(language); + scope = scopeBuilder.build(); } private static Map loadBuiltinMethodClassesEarly( @@ -192,7 +194,7 @@ private static Map loadBuiltinMethodClassesEarly( * @param scope Builtins scope * @param language The language the resulting function nodes should be associated with */ - private void registerBuiltinMethods(ModuleScope scope, EnsoLanguage language) { + private void registerBuiltinMethods(ModuleScope.Builder scope, EnsoLanguage language) { for (Builtin builtin : builtins.values()) { var type = builtin.getType(); Map> methods = builtinMethodNodes.get(type.getName()); @@ -226,7 +228,7 @@ private void registerBuiltinMethods(ModuleScope scope, EnsoLanguage language) { * @return map from types to builtin methods */ private Map>> registerBuiltinMethodsLazily( - ModuleScope scope, EnsoLanguage language) { + ModuleScope.Builder scope, EnsoLanguage language) { Map>> builtinMethodNodes = new HashMap<>(); Map> builtinMetaMethods = new HashMap<>(); loadedBuiltinMethodsMeta.forEach( @@ -237,7 +239,7 @@ private Map>> registerBuiltinM } String builtinMethodOwner = builtinName[0]; String builtinMethodName = builtinName[1]; - Optional.ofNullable(scope.getTypes().get(builtinMethodOwner)) + Optional.ofNullable(scope.asModuleScope().getType(builtinMethodOwner, true)) .ifPresentOrElse( constr -> { Map> atomNodes = @@ -375,7 +377,9 @@ private static List> readBuiltinTypes() { /** Initialize builting types in the context of the given language and module scope */ private Map, Builtin> initializeBuiltinTypes( - List> constrs, EnsoLanguage language, ModuleScope scope) { + List> constrs, + EnsoLanguage language, + ModuleScope.Builder scope) { Map, Builtin> builtins = new HashMap<>(); for (var constr : constrs) { @@ -400,7 +404,7 @@ private Map, Builtin> initializeBuiltinTypes( * @return A map of builtin method nodes per builtin type name */ private Map>> readBuiltinMethodsMetadata( - Map classes, ModuleScope scope) { + Map classes, ModuleScope.Builder scope) { Map>> methodNodes = new HashMap<>(); classes.forEach( @@ -411,7 +415,7 @@ private Map>> readBuiltinMetho } String builtinMethodOwner = builtinName[0]; String builtinMethodName = builtinName[1]; - Optional.ofNullable(scope.getTypes().get(builtinMethodOwner)) + Optional.ofNullable(scope.asModuleScope().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 cf043cf25d4d..c233d23e3279 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 @@ -28,8 +28,9 @@ @ExportLibrary(TypesLibrary.class) @ExportLibrary(InteropLibrary.class) public final class Type implements EnsoObject { + private final String name; - private @CompilerDirectives.CompilationFinal ModuleScope definitionScope; + private @CompilerDirectives.CompilationFinal ModuleScope.Builder definitionScope; private final boolean builtin; private final Type supertype; private final Type eigentype; @@ -40,7 +41,7 @@ public final class Type implements EnsoObject { private Type( String name, - ModuleScope definitionScope, + ModuleScope.Builder definitionScope, Type supertype, Type eigentype, boolean builtin, @@ -56,18 +57,16 @@ private Type( public static Type createSingleton( String name, - ModuleScope definitionScope, + ModuleScope.Builder definitionScope, Type supertype, boolean builtin, boolean isProjectPrivate) { - var result = new Type(name, definitionScope, supertype, null, builtin, isProjectPrivate); - result.generateQualifiedAccessor(); - return result; + return new Type(name, definitionScope, supertype, null, builtin, isProjectPrivate); } public static Type create( String name, - ModuleScope definitionScope, + ModuleScope.Builder definitionScope, Type supertype, Type any, boolean builtin, @@ -93,7 +92,8 @@ private void generateQualifiedAccessor() { schemaBldr.projectPrivate(); } var function = new Function(node.getCallTarget(), null, schemaBldr.build()); - definitionScope.registerMethod(definitionScope.getAssociatedType(), this.name, function); + definitionScope.registerMethod( + definitionScope.asModuleScope().getAssociatedType(), this.name, function); } public QualifiedName getQualifiedName() { @@ -104,11 +104,9 @@ public QualifiedName getQualifiedName() { } } - public void setShadowDefinitions(ModuleScope scope, boolean generateAccessorsInTarget) { + public void setShadowDefinitions(ModuleScope.Builder scope, boolean generateAccessorsInTarget) { if (builtin) { - // Ensure that synthetic methods, such as getters for fields are in the scope - // Some scopes won't have any methods at this point, e.g., Nil or Nothing, hence the null - // check. + // Ensure that synthetic methods, such as getters for fields are in the scope. CompilerAsserts.neverPartOfCompilation(); this.definitionScope.registerAllMethodsOfTypeToScope(this, scope); this.definitionScope = scope; @@ -129,7 +127,7 @@ public String getName() { } public ModuleScope getDefinitionScope() { - return definitionScope; + return definitionScope.asModuleScope(); } public boolean isBuiltin() { 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 cf0bce8ef50a..f4609ee40c5d 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 @@ -24,6 +24,7 @@ import org.enso.interpreter.node.callable.argument.ReadArgumentNode; import org.enso.interpreter.node.callable.function.BlockNode; import org.enso.interpreter.runtime.EnsoContext; +import org.enso.interpreter.runtime.Module; import org.enso.interpreter.runtime.callable.Annotation; import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition; import org.enso.interpreter.runtime.callable.function.Function; @@ -43,7 +44,7 @@ public final class AtomConstructor implements EnsoObject { private final String name; - private final ModuleScope definitionScope; + private final Module definitionModule; private final boolean builtin; private @CompilerDirectives.CompilationFinal Atom cachedInstance; private @CompilerDirectives.CompilationFinal Function constructorFunction; @@ -60,11 +61,11 @@ public final class AtomConstructor implements EnsoObject { * AtomConstructor#initializeFields} is called. * * @param name the name of the Atom constructor - * @param definitionScope the scope in which this constructor was defined + * @param definitionModule the module in which this constructor was defined * @param type associated type */ - public AtomConstructor(String name, ModuleScope definitionScope, Type type) { - this(name, definitionScope, type, false); + public AtomConstructor(String name, Module definitionModule, Type type) { + this(name, definitionModule, type, false); } /** @@ -72,13 +73,13 @@ public AtomConstructor(String name, ModuleScope definitionScope, Type type) { * AtomConstructor#initializeFields} is called. * * @param name the name of the Atom constructor - * @param definitionScope the scope in which this constructor was defined + * @param definitionModule the module in which this constructor was defined * @param type associated type * @param builtin if true, the constructor refers to a builtin type (annotated with @BuiltinType */ - public AtomConstructor(String name, ModuleScope definitionScope, Type type, boolean builtin) { + public AtomConstructor(String name, Module definitionModule, Type type, boolean builtin) { this.name = name; - this.definitionScope = definitionScope; + this.definitionModule = definitionModule; this.type = type; this.builtin = builtin; } @@ -102,13 +103,21 @@ boolean isBuiltin() { * * @return {@code this}, for convenience */ - public AtomConstructor initializeFields(EnsoLanguage language, ArgumentDefinition... args) { + public AtomConstructor initializeFields( + EnsoLanguage language, ModuleScope.Builder scopeBuilder, ArgumentDefinition... args) { ExpressionNode[] reads = new ExpressionNode[args.length]; for (int i = 0; i < args.length; i++) { reads[i] = ReadArgumentNode.build(i, null, null); } return initializeFields( - language, null, LocalScope.root(), new ExpressionNode[0], reads, new Annotation[0], args); + language, + null, + LocalScope.root(), + scopeBuilder, + new ExpressionNode[0], + reads, + new Annotation[0], + args); } /** @@ -116,6 +125,7 @@ public AtomConstructor initializeFields(EnsoLanguage language, ArgumentDefinitio * * @param localScope a description of the local scope * @param assignments the expressions that evaluate and assign constructor arguments to local vars + * @param scopeBuilder the module scope's builder where the accessor should be registered at * @param varReads the expressions that read field values from local vars * @return {@code this}, for convenience */ @@ -123,6 +133,7 @@ public AtomConstructor initializeFields( EnsoLanguage language, SourceSection section, LocalScope localScope, + ModuleScope.Builder scopeBuilder, ExpressionNode[] assignments, ExpressionNode[] varReads, Annotation[] annotations, @@ -137,8 +148,8 @@ public AtomConstructor initializeFields( boxedLayout = Layout.createBoxed(args); this.constructorFunction = buildConstructorFunction( - language, section, localScope, assignments, varReads, annotations, args); - this.accessor = generateQualifiedAccessor(language); + language, section, localScope, scopeBuilder, assignments, varReads, annotations, args); + this.accessor = generateQualifiedAccessor(language, scopeBuilder); return this; } @@ -159,6 +170,7 @@ private Function buildConstructorFunction( EnsoLanguage language, SourceSection section, LocalScope localScope, + ModuleScope.Builder scopeBuilder, ExpressionNode[] assignments, ExpressionNode[] varReads, Annotation[] annotations, @@ -170,7 +182,7 @@ private Function buildConstructorFunction( BlockNode instantiateBlock = BlockNode.buildSilent(assignments, instantiateNode); RootNode rootNode = MethodRootNode.buildConstructor( - language, localScope, definitionScope, instantiateBlock, section, this); + language, localScope, scopeBuilder.asModuleScope(), instantiateBlock, section, this); RootCallTarget callTarget = rootNode.getCallTarget(); var schemaBldr = FunctionSchema.newBuilder().annotations(annotations).argumentDefinitions(args); if (type.isProjectPrivate()) { @@ -179,7 +191,7 @@ private Function buildConstructorFunction( return new Function(callTarget, null, schemaBldr.build()); } - private Function generateQualifiedAccessor(EnsoLanguage lang) { + private Function generateQualifiedAccessor(EnsoLanguage lang, ModuleScope.Builder scopeBuilder) { var node = new QualifiedAccessorNode(lang, this, getDefinitionScope()); var callTarget = node.getCallTarget(); var schemaBldr = @@ -191,7 +203,7 @@ private Function generateQualifiedAccessor(EnsoLanguage lang) { schemaBldr.projectPrivate(); } var function = new Function(callTarget, null, schemaBldr.build()); - definitionScope.registerMethod(type.getEigentype(), this.name, function); + scopeBuilder.registerMethod(type.getEigentype(), this.name, function); return function; } @@ -221,7 +233,7 @@ public String getDisplayName() { * @return the scope in which this constructor was defined */ public ModuleScope getDefinitionScope() { - return definitionScope; + return definitionModule.getScope(); } /** diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/ImportExportScope.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/ImportExportScope.java new file mode 100644 index 000000000000..1b8637fd7e96 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/ImportExportScope.java @@ -0,0 +1,70 @@ +package org.enso.interpreter.runtime.scope; + +import java.util.List; +import org.enso.compiler.context.CompilerContext; +import org.enso.interpreter.runtime.Module; +import org.enso.interpreter.runtime.callable.function.Function; +import org.enso.interpreter.runtime.data.EnsoObject; +import org.enso.interpreter.runtime.data.Type; + +/** + * A proxy scope delegating to the underlying module's scope. Additionally, `ImportExportScope` may + * limit the number of types that are imported/exported. + */ +public class ImportExportScope implements EnsoObject { + + private final Module module; + private final List typesOnlyNames; + + public ImportExportScope(CompilerContext.Module module, List typesOnlyNames) { + this.module = org.enso.interpreter.runtime.Module.fromCompilerModule(module); + this.typesOnlyNames = + typesOnlyNames != null && !typesOnlyNames.isEmpty() ? typesOnlyNames : null; + } + + public ImportExportScope(CompilerContext.Module module) { + this.module = org.enso.interpreter.runtime.Module.fromCompilerModule(module); + this.typesOnlyNames = null; + } + + private boolean isValidType(Type type) { + if (typesOnlyNames == null) return true; + return typesOnlyNames.contains(type.getName()) && module.getScope().hasType(type); + } + + public Function getExportedMethod(Type type, String name) { + if (isValidType(type)) { + return module.getScope().getExportedMethod(type, name); + } else { + return null; + } + } + + public Function getExportedConversion(Type type, Type target) { + if (isValidType(target)) { + return module.getScope().getExportedConversion(type, target); + } else { + return null; + } + } + + public Function getMethodForType(Type type, String methodName) { + if (isValidType(type)) { + return module.getScope().getMethodForType(type, methodName); + } else { + return null; + } + } + + public Function getConversionForType(Type target, Type type) { + if (isValidType(target)) { + var result = module.getScope().getConversionsFor(target); + if (result == null) { + return null; + } + return result.get(type); + } else { + return null; + } + } +} 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 2b433955dbd2..5572cd505e72 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 @@ -1,18 +1,12 @@ package org.enso.interpreter.runtime.scope; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.function.Supplier; import java.util.stream.Collectors; +import org.enso.compiler.context.CompilerContext; import org.enso.interpreter.runtime.Module; import org.enso.interpreter.runtime.callable.function.Function; import org.enso.interpreter.runtime.data.EnsoObject; @@ -27,12 +21,12 @@ public final class ModuleScope implements EnsoObject { private final Type associatedType; private final Module module; - private Map polyglotSymbols; - private Map types; - private Map>> methods; - private Map> conversions; - private Set imports; - private Set exports; + private final Map polyglotSymbols; + private final Map types; + private final Map>> methods; + private final Map> conversions; + private final Set imports; + private final Set exports; private static final Type noTypeKey; @@ -40,22 +34,6 @@ public final class ModuleScope implements EnsoObject { noTypeKey = Type.noType(); } - /** - * Creates a new object of this class. - * - * @param module the module related to the newly created scope. - */ - public ModuleScope(Module module) { - this.polyglotSymbols = new LinkedHashMap<>(); - this.types = new LinkedHashMap<>(); - this.methods = new LinkedHashMap<>(); - this.conversions = new LinkedHashMap<>(); - this.imports = new LinkedHashSet<>(); - this.exports = new LinkedHashSet<>(); - this.module = module; - this.associatedType = Type.createSingleton(module.getName().item(), this, null, false, false); - } - public ModuleScope( Module module, Type associatedType, @@ -63,8 +41,8 @@ public ModuleScope( Map types, Map>> methods, Map> conversions, - Set imports, - Set exports) { + Set imports, + Set exports) { this.module = module; this.associatedType = associatedType; this.polyglotSymbols = polyglotSymbols; @@ -75,11 +53,6 @@ public ModuleScope( this.exports = exports; } - public Type registerType(Type type) { - Type current = types.putIfAbsent(type.getName(), type); - return current == null ? type : current; - } - /** * @return the associated type of this module. */ @@ -94,115 +67,6 @@ public Module getModule() { return module; } - /** - * @return the set of modules imported by this module. - */ - public Set getImports() { - return imports; - } - - /** - * Returns a map of methods defined in this module for a given type. - * - * @param type the type for which method map is requested - * @return a map containing all the defined methods by name - */ - private Map> ensureMethodMapFor(Type type) { - Type tpeKey = type == null ? noTypeKey : type; - return methods.computeIfAbsent(tpeKey, k -> new LinkedHashMap<>()); - } - - private Map> getMethodMapFor(Type type) { - Type tpeKey = type == null ? noTypeKey : type; - Map> result = methods.get(tpeKey); - if (result == null) { - return new LinkedHashMap<>(); - } - return result; - } - - /** - * Registers a method defined for a given type. - * - * @param type the type the method was defined for - * @param method method name - * @param function the {@link Function} associated with this definition - */ - public void registerMethod(Type type, String method, Function function) { - Map> methodMap = ensureMethodMapFor(type); - - // Builtin types will have double definition because of - // BuiltinMethod and that's OK - if (methodMap.containsKey(method) && !type.isBuiltin()) { - throw new RedefinedMethodException(type.getName(), method); - } else { - methodMap.put(method, new CachingSupplier<>(function)); - } - } - - /** - * Registers a lazily constructed method defined for a given type. - * - * @param type the type the method was defined for - * @param method method name - * @param supply provider of the {@link Function} associated with this definition - */ - public void registerMethod(Type type, String method, Supplier supply) { - Map> methodMap = ensureMethodMapFor(type); - - // Builtin types will have double definition because of - // BuiltinMethod and that's OK - if (methodMap.containsKey(method) && !type.isBuiltin()) { - throw new RedefinedMethodException(type.getName(), method); - } else { - methodMap.put(method, new CachingSupplier<>(supply)); - } - } - - /** - * Returns a list of the conversion methods defined in this module for a given constructor. - * - * @param type the type for which method map is requested - * @return a list containing all the defined conversions in definition order - */ - private Map ensureConversionsFor(Type type) { - return conversions.computeIfAbsent(type, k -> new LinkedHashMap<>()); - } - - private Map getConversionsFor(Type type) { - var result = conversions.get(type); - if (result == null) { - return new LinkedHashMap<>(); - } - return result; - } - - /** - * Registers a conversion method for a given type - * - * @param toType type the conversion was defined to - * @param fromType type the conversion was defined from - * @param function the {@link Function} associated with this definition - */ - public void registerConversionMethod(Type toType, Type fromType, Function function) { - var sourceMap = ensureConversionsFor(toType); - if (sourceMap.containsKey(fromType)) { - throw new RedefinedConversionException(toType.getName(), fromType.getName()); - } else { - sourceMap.put(fromType, function); - } - } - - /** - * Registers a new symbol in the polyglot namespace. - * - * @param name the name of the symbol - * @param sym the value being exposed - */ - public void registerPolyglotSymbol(String name, Object sym) { - polyglotSymbols.put(name, sym); - } - /** * Looks up the definition for a given type and method name. * @@ -214,16 +78,16 @@ public void registerPolyglotSymbol(String name, Object sym) { * @param name the method name. * @return the matching method definition or null if not found. */ - @TruffleBoundary + @CompilerDirectives.TruffleBoundary public Function lookupMethodDefinition(Type type, String name) { - var definedWithAtom = type.getDefinitionScope().getMethodMapFor(type).get(name); + var definedWithAtom = type.getDefinitionScope().getMethodForType(type, name); if (definedWithAtom != null) { - return definedWithAtom.get(); + return definedWithAtom; } - var definedHere = getMethodMapFor(type).get(name); + var definedHere = getMethodForType(type, name); if (definedHere != null) { - return definedHere.get(); + return definedHere; } return imports.stream() @@ -233,7 +97,7 @@ public Function lookupMethodDefinition(Type type, String name) { .orElse(null); } - @TruffleBoundary + @CompilerDirectives.TruffleBoundary public Function lookupConversionDefinition(Type original, Type target) { Function definedWithOriginal = original.getDefinitionScope().getConversionsFor(target).get(original); @@ -256,59 +120,49 @@ public Function lookupConversionDefinition(Type original, Type target) { .orElse(null); } - private Function getExportedMethod(Type type, String name) { - var here = getMethodMapFor(type).get(name); + Function getExportedMethod(Type type, String name) { + var here = getMethodForType(type, name); if (here != null) { - return here.get(); + return here; } return exports.stream() - .map(scope -> scope.getMethodMapFor(type).get(name)) + .map(scope -> scope.getMethodForType(type, name)) .filter(Objects::nonNull) - .map(s -> s.get()) .findFirst() .orElse(null); } - private Function getExportedConversion(Type type, Type target) { + Function getExportedConversion(Type type, Type target) { Function here = getConversionsFor(target).get(type); if (here != null) { return here; } return exports.stream() - .map(scope -> scope.getConversionsFor(target).get(type)) + .map(scope -> scope.getConversionForType(target, type)) .filter(Objects::nonNull) .findFirst() .orElse(null); } - /** - * Adds a dependency for this module. - * - * @param scope the scope of the newly added dependency - */ - public void addImport(ModuleScope scope) { - imports.add(scope); - } - - /** - * Adds an information about the module exporting another module. - * - * @param scope the exported scope - */ - public void addExport(ModuleScope scope) { - exports.add(scope); + public List getAllTypes(String name) { + var tpes = new ArrayList(types.size() + 1); + var tpe0 = getType(name, false); + if (tpe0 != null) tpes.add(tpe0); + tpes.addAll(types.values()); + return tpes; } - public Map getTypes() { - return types; + @ExportMessage.Ignore + public Type getType(String name, boolean ignoreAssociatedType) { + if (!ignoreAssociatedType && associatedType.getName().equals(name)) { + return associatedType; + } + return types.get(name); } @ExportMessage.Ignore - public Optional getType(String name) { - if (associatedType.getName().equals(name)) { - return Optional.of(associatedType); - } - return Optional.ofNullable(types.get(name)); + public boolean hasType(Type type) { + return types.get(type.getName()) == type; } /** @@ -352,18 +206,12 @@ public Set getMethodsForType(Type tpe) { } } - /** - * 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 scope) { - Type tpeKey = tpe == null ? noTypeKey : tpe; - var allTypeMethods = methods.get(tpeKey); - if (allTypeMethods != null) { - allTypeMethods.forEach((name, fun) -> scope.registerMethod(tpeKey, name, fun)); + Map getConversionsFor(Type type) { + var result = conversions.get(type); + if (result == null) { + return new LinkedHashMap<>(); } + return result; } /** @@ -392,60 +240,6 @@ public Object getPolyglotSymbol(String symbolName) { return polyglotSymbols.get(symbolName); } - public void reset() { - imports = new LinkedHashSet<>(); - exports = new LinkedHashSet<>(); - methods = new LinkedHashMap<>(); - conversions = new LinkedHashMap<>(); - polyglotSymbols = new LinkedHashMap<>(); - } - - /** - * Create a copy of this `ModuleScope` while taking into account only the provided list of types. - * - * @param typeNames list of types to copy to the new scope - * @return a copy of this scope modulo the requested types - */ - public ModuleScope withTypes(List typeNames) { - Map polyglotSymbols = new LinkedHashMap<>(this.polyglotSymbols); - Map requestedTypes = new LinkedHashMap<>(this.types); - Map>> methods = new LinkedHashMap<>(); - Map> conversions = new LinkedHashMap<>(); - Set imports = new LinkedHashSet<>(this.imports); - Set exports = new LinkedHashSet<>(this.exports); - this.types - .entrySet() - .forEach( - entry -> { - if (typeNames.contains(entry.getKey())) { - requestedTypes.put(entry.getKey(), entry.getValue()); - } - }); - Collection validTypes = requestedTypes.values(); - this.methods.forEach( - (tpe, meths) -> { - if (validTypes.contains(tpe)) { - methods.put(tpe, meths); - } - }); - this.conversions.forEach( - (tpe, meths) -> { - if (validTypes.contains(tpe)) { - conversions.put(tpe, meths); - } - }); - - return new ModuleScope( - module, - associatedType, - polyglotSymbols, - requestedTypes, - methods, - conversions, - imports, - exports); - } - @ExportMessage boolean hasType() { return true; @@ -460,4 +254,258 @@ Type getType() { public String toString() { return "Scope" + module; } + + public static class Builder { + + @CompilerDirectives.CompilationFinal private ModuleScope moduleScope = null; + private final Module module; + private final Type associatedType; + private final Map polyglotSymbols; + private final Map types; + private final Map>> methods; + private final Map> conversions; + private final Set imports; + private final Set exports; + + public Builder(Module module) { + this.module = module; + this.polyglotSymbols = new LinkedHashMap<>(); + this.types = new LinkedHashMap<>(); + this.methods = new LinkedHashMap<>(); + this.conversions = new LinkedHashMap<>(); + this.imports = new LinkedHashSet<>(); + this.exports = new LinkedHashSet<>(); + this.associatedType = Type.createSingleton(module.getName().item(), this, null, false, false); + } + + public Builder(Module module, Map types) { + this.module = module; + this.polyglotSymbols = new LinkedHashMap<>(); + this.types = types; + this.methods = new LinkedHashMap<>(); + this.conversions = new LinkedHashMap<>(); + this.imports = new LinkedHashSet<>(); + this.exports = new LinkedHashSet<>(); + this.associatedType = Type.createSingleton(module.getName().item(), this, null, false, false); + } + + public Builder( + Module module, + Type associatedType, + Map polyglotSymbols, + Map types, + Map>> methods, + Map> conversions, + Set imports, + Set exports) { + this.module = module; + this.associatedType = associatedType; + this.polyglotSymbols = polyglotSymbols; + this.types = types; + this.methods = methods; + this.conversions = conversions; + this.imports = imports; + this.exports = exports; + } + + public Type registerType(Type type) { + assert moduleScope == null; + Type current = types.putIfAbsent(type.getName(), type); + return current == null ? type : current; + } + + /** + * Returns a map of methods defined in this module for a given type. + * + * @param type the type for which method map is requested + * @return a map containing all the defined methods by name + */ + private Map> ensureMethodMapFor(Type type) { + Type tpeKey = type == null ? noTypeKey : type; + return methods.computeIfAbsent(tpeKey, k -> new LinkedHashMap<>()); + } + + /** + * Registers a method defined for a given type. + * + * @param type the type the method was defined for + * @param method method name + * @param function the {@link Function} associated with this definition + */ + public void registerMethod(Type type, String method, Function function) { + assert moduleScope == null; + Map> methodMap = ensureMethodMapFor(type); + + // Builtin types will have double definition because of + // BuiltinMethod and that's OK + if (methodMap.containsKey(method) && !type.isBuiltin()) { + throw new RedefinedMethodException(type.getName(), method); + } else { + methodMap.put(method, new CachingSupplier<>(function)); + } + } + + /** + * Registers a lazily constructed method defined for a given type. + * + * @param type the type the method was defined for + * @param method method name + * @param supply provider of the {@link Function} associated with this definition + */ + public void registerMethod(Type type, String method, Supplier supply) { + assert moduleScope == null; + Map> methodMap = ensureMethodMapFor(type); + + // Builtin types will have double definition because of + // BuiltinMethod and that's OK + if (methodMap.containsKey(method) && !type.isBuiltin()) { + throw new RedefinedMethodException(type.getName(), method); + } else { + methodMap.put(method, new CachingSupplier<>(supply)); + } + } + + /** + * Registers a conversion method for a given type + * + * @param toType type the conversion was defined to + * @param fromType type the conversion was defined from + * @param function the {@link Function} associated with this definition + */ + public void registerConversionMethod(Type toType, Type fromType, Function function) { + assert moduleScope == null; + var sourceMap = conversions.computeIfAbsent(toType, k -> new LinkedHashMap<>()); + if (sourceMap.containsKey(fromType)) { + throw new RedefinedConversionException(toType.getName(), fromType.getName()); + } else { + sourceMap.put(fromType, function); + } + } + + /** + * Registers a new symbol in the polyglot namespace. + * + * @param name the name of the symbol + * @param sym the value being exposed + */ + public void registerPolyglotSymbol(String name, Object sym) { + assert moduleScope == null; + 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. + * + * @param scope the scope of the newly added dependency + */ + public void addImport(ImportExportScope scope) { + assert moduleScope == null; + imports.add(scope); + } + + /** + * Adds an information about the module exporting another module. + * + * @param scope the exported scope + */ + public void addExport(ImportExportScope scope) { + assert moduleScope == null; + exports.add(scope); + } + + public Module getModule() { + return module; + } + + /** + * Create a new ModuleScope.Builder which inherits from `this` `module` and `types` that need to + * survive the compilation. + * + * @return new ModuleScope.Builder + */ + public Builder newBuilderInheritingTypes() { + return new Builder(this.module, new LinkedHashMap<>(this.types)); + } + + /** + * Materializes the builder and ensures that no further modifications to ModuleScope are + * possible. Action is idempotent. + * + * @return an immutable ModuleScope + */ + public ModuleScope build() { + if (moduleScope == null) { + moduleScope = + new ModuleScope( + module, + associatedType, + Collections.unmodifiableMap(polyglotSymbols), + Collections.unmodifiableMap(types), + Collections.unmodifiableMap(methods), + Collections.unmodifiableMap(conversions), + Collections.unmodifiableSet(imports), + Collections.unmodifiableSet(exports)); + } + return moduleScope; + } + + public static ModuleScope.Builder fromCompilerModuleScopeBuilder( + CompilerContext.ModuleScopeBuilder scopeBuilder) { + 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(); + builder.append("ModuleScope builder for " + module.getName()); + builder.append(",\n"); + builder.append("Polyglot Symbols: " + polyglotSymbols); + builder.append(",\n"); + builder.append("Methods: " + methods); + builder.append(",\n"); + builder.append("Conversions: " + conversions); + builder.append(",\n"); + builder.append("Imports: " + imports); + builder.append(",\n"); + builder.append("Exports: " + exports); + builder.append(",\n"); + builder.append("Types: " + types); + return builder.toString(); + } + } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/TruffleCompilerModuleScopeBuilder.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/TruffleCompilerModuleScopeBuilder.java new file mode 100644 index 000000000000..e379549fb5de --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/TruffleCompilerModuleScopeBuilder.java @@ -0,0 +1,16 @@ +package org.enso.interpreter.runtime.scope; + +import org.enso.compiler.context.CompilerContext; + +public final class TruffleCompilerModuleScopeBuilder extends CompilerContext.ModuleScopeBuilder { + private final org.enso.interpreter.runtime.scope.ModuleScope.Builder scopeBuilder; + + public TruffleCompilerModuleScopeBuilder( + org.enso.interpreter.runtime.scope.ModuleScope.Builder scopeBuilder) { + this.scopeBuilder = scopeBuilder; + } + + public org.enso.interpreter.runtime.scope.ModuleScope.Builder unsafeScopeBuilder() { + return scopeBuilder; + } +} 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 6ed61bf703aa..4fe5b7d6eb03 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 @@ -106,7 +106,7 @@ import org.enso.interpreter.runtime.callable.{ } import org.enso.interpreter.runtime.data.Type import org.enso.interpreter.runtime.data.text.Text -import org.enso.interpreter.runtime.scope.ModuleScope +import org.enso.interpreter.runtime.scope.{ImportExportScope, ModuleScope} import org.enso.interpreter.{Constants, EnsoLanguage} import java.math.BigInteger @@ -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 moduleScope the scope of the module for which code is being generated + * @param scopeBuilder the scope's builder of the module for which code is being generated * @param compilerConfig the configuration for the compiler */ class IrToTruffle( val context: EnsoContext, val source: Source, - val moduleScope: ModuleScope, + val scopeBuilder: ModuleScope.Builder, val compilerConfig: CompilerConfig ) { @@ -171,7 +171,7 @@ class IrToTruffle( new ExpressionProcessor( localScope, scopeName, - moduleScope.getModule().getName().toString() + scopeBuilder.getModule().getName().toString() ).runInline(ir) } @@ -197,17 +197,10 @@ class IrToTruffle( ) bindingsMap.resolvedExports - .collect { case ExportedModule(ResolvedModule(module), _, _) => - module - } - .foreach { exp => - moduleScope.addExport( - asScope( - exp - .unsafeAsModule() - ) - ) - } + .collect { case ExportedModule(ResolvedModule(module), _, _) => module } + .foreach(exp => + scopeBuilder.addExport(new ImportExportScope(exp.unsafeAsModule())) + ) val importDefs = module.imports val methodDefs = module.bindings.collect { case method: definition.Method.Explicit => method @@ -219,17 +212,10 @@ class IrToTruffle( case ResolvedModule(module) => val mod = module .unsafeAsModule() - val scope: ModuleScope = imp.importDef.onlyNames - .map(only => { - val requestedTypes = only.map(_.name).asJava - if (requestedTypes.isEmpty()) { - asScope(mod) - } else { - asScope(mod).withTypes(requestedTypes) - } - }) - .getOrElse(asScope(mod)) - moduleScope.addImport(scope) + val scope: ImportExportScope = imp.importDef.onlyNames + .map(only => new ImportExportScope(mod, only.map(_.name).asJava)) + .getOrElse(new ImportExportScope(mod)) + scopeBuilder.addImport(scope) } } @@ -243,7 +229,7 @@ class IrToTruffle( ) hostSymbol = DataflowError.withoutTrace(err, null) } - this.moduleScope.registerPolyglotSymbol( + this.scopeBuilder.registerPolyglotSymbol( poly.getVisibleName, hostSymbol ) @@ -255,7 +241,7 @@ class IrToTruffle( typeDefs.foreach { tpDef => // Register the atoms and their constructors in scope val atomDefs = tpDef.members - val asType = moduleScope.getTypes.get(tpDef.name.name) + val asType = scopeBuilder.asModuleScope().getType(tpDef.name.name, true) val atomConstructors = atomDefs.map(cons => asType.getConstructors.get(cons.name.name)) atomConstructors @@ -336,9 +322,9 @@ class IrToTruffle( val closureRootNode = ClosureRootNode.build( language, expressionProcessor.scope, - moduleScope, + scopeBuilder.asModuleScope(), expressionNode, - makeSection(moduleScope, annotation.location), + makeSection(scopeBuilder.getModule, annotation.location), closureName, true, false @@ -348,8 +334,9 @@ class IrToTruffle( if (!atomCons.isInitialized) { atomCons.initializeFields( language, - makeSection(moduleScope, atomDefn.location), + makeSection(scopeBuilder.getModule, atomDefn.location), localScope, + scopeBuilder, assignments.toArray, reads.toArray, annotations.toArray, @@ -392,23 +379,16 @@ class IrToTruffle( val declaredConsOpt = methodDef.methodReference.typePointer match { case None => - Some(moduleScope.getAssociatedType) + Some(scopeAssociatedType) case Some(tpePointer) => tpePointer .getMetadata(MethodDefinitions) .map { res => res.target match { - case BindingsMap.ResolvedType(module, tp) => - asScope( - module - .unsafeAsModule() - ).getTypes - .get(tp.name) + case binding @ BindingsMap.ResolvedType(_, _) => + asType(binding) case BindingsMap.ResolvedModule(module) => - asScope( - module - .unsafeAsModule() - ).getAssociatedType + asAssociatedType(module.unsafeAsModule()) case BindingsMap.ResolvedConstructor(_, _) => throw new CompilerError( "Impossible, should be caught by MethodDefinitions pass" @@ -446,7 +426,7 @@ class IrToTruffle( fullMethodDefName ) - moduleScope.registerMethod( + scopeBuilder.registerMethod( cons, methodDef.methodName.name, () => { @@ -528,7 +508,7 @@ class IrToTruffle( m.getFunction.getCallTarget.getRootNode .asInstanceOf[BuiltinRootNode] builtinRootNode - .setModuleName(moduleScope.getModule.getName) + .setModuleName(scopeBuilder.getModule.getName) builtinRootNode.setTypeName(cons.getQualifiedName) val funcSchemaBldr = FunctionSchema .newBuilder() @@ -570,11 +550,11 @@ class IrToTruffle( MethodRootNode.buildOperator( language, expressionProcessor.scope, - moduleScope, + scopeBuilder.asModuleScope(), () => bodyBuilder.argsExpr._1(0), () => bodyBuilder.argsExpr._1(1), () => bodyBuilder.argsExpr._2, - makeSection(moduleScope, methodDef.location), + makeSection(scopeBuilder.getModule, methodDef.location), cons, methodDef.methodName.name ) @@ -582,9 +562,9 @@ class IrToTruffle( MethodRootNode.build( language, expressionProcessor.scope, - moduleScope, + scopeBuilder.asModuleScope(), () => bodyBuilder.bodyNode(), - makeSection(moduleScope, methodDef.location), + makeSection(scopeBuilder.getModule, methodDef.location), cons, methodDef.methodName.name ) @@ -633,9 +613,12 @@ class IrToTruffle( val closureRootNode = ClosureRootNode.build( language, expressionProcessor.scope, - moduleScope, + scopeBuilder.asModuleScope(), expressionNode, - makeSection(moduleScope, annotation.location), + makeSection( + scopeBuilder.getModule, + annotation.location + ), closureName, true, false @@ -707,7 +690,7 @@ class IrToTruffle( case Some(tpePointer) => getTypeResolution(tpePointer) case None => - Some(moduleScope.getAssociatedType) + Some(scopeAssociatedType) } val fromOpt = getTypeResolution(methodDef.sourceTypeName) toOpt.zip(fromOpt).foreach { case (toType, fromType) => @@ -732,9 +715,9 @@ class IrToTruffle( val rootNode = MethodRootNode.build( language, expressionProcessor.scope, - moduleScope, + scopeBuilder.asModuleScope(), () => bodyBuilder.bodyNode(), - makeSection(moduleScope, methodDef.location), + makeSection(scopeBuilder.getModule, methodDef.location), toType, methodDef.methodName.name ) @@ -754,9 +737,10 @@ class IrToTruffle( "Conversion bodies must be functions at the point of codegen." ) } - moduleScope.registerConversionMethod(toType, fromType, function) + scopeBuilder.registerConversionMethod(toType, fromType, function) } }) + scopeBuilder.build() } // ========================================================================== @@ -788,16 +772,11 @@ class IrToTruffle( t.getMetadata(TypeNames) match { case Some( BindingsMap - .Resolution(BindingsMap.ResolvedType(mod, tpe)) + .Resolution(binding @ BindingsMap.ResolvedType(_, _)) ) => ReadArgumentCheckNode.build( comment, - asScope( - mod - .unsafeAsModule() - .asInstanceOf[TruffleCompilerContext.Module] - ).getTypes - .get(tpe.name) + asType(binding) ) case Some( BindingsMap @@ -806,9 +785,7 @@ class IrToTruffle( ReadArgumentCheckNode.meta( comment, asScope( - mod - .unsafeAsModule() - .asInstanceOf[TruffleCompilerContext.Module] + mod.unsafeAsModule().asInstanceOf[TruffleCompilerContext.Module] ).getPolyglotSymbol(symbol.name) ) case _ => null @@ -843,14 +820,14 @@ class IrToTruffle( * @return the source section corresponding to `location` */ private def makeSection( - module: ModuleScope, + module: org.enso.interpreter.runtime.Module, location: Option[IdentifiedLocation] ): SourceSection = { location .map(loc => { - val m = module.getModule() + val m = module if (m.isModuleSource(source)) { - module.getModule().createSection(loc.start, loc.length) + module.createSection(loc.start, loc.length) } else { source.createSection(loc.start, loc.length) } @@ -861,17 +838,10 @@ class IrToTruffle( private def getTypeResolution(expr: IR): Option[Type] = expr.getMetadata(MethodDefinitions).map { res => res.target match { - case BindingsMap.ResolvedType(definitionModule, tp) => - asScope( - definitionModule - .unsafeAsModule() - ).getTypes - .get(tp.name) + case binding @ BindingsMap.ResolvedType(_, _) => + asType(binding) case BindingsMap.ResolvedModule(module) => - asScope( - module - .unsafeAsModule() - ).getAssociatedType + asAssociatedType(module.unsafeAsModule()) case BindingsMap.ResolvedConstructor(_, _) => throw new CompilerError( "Impossible here, should be caught by MethodDefinitions pass." @@ -960,55 +930,51 @@ class IrToTruffle( if ( resolution.isInstanceOf[ResolvedConstructor] || !resolution.module .unsafeAsModule() - .equals(moduleScope.getModule.asCompilerModule) + .equals(scopeBuilder.getModule.asCompilerModule) ) { resolution match { - case BindingsMap.ResolvedType(module, tp) => + case binding @ BindingsMap.ResolvedType(_, _) => val runtimeTp = - asScope( - module - .unsafeAsModule() - ).getTypes - .get(tp.name) + asType(binding) val fun = mkTypeGetter(runtimeTp) - moduleScope.registerMethod( - moduleScope.getAssociatedType, + scopeBuilder.registerMethod( + scopeAssociatedType, name, fun ) case BindingsMap.ResolvedConstructor(definitionType, cons) => - val runtimeCons = asType(definitionType).getConstructors - .get(cons.name) + val tpe = asType(definitionType) + val runtimeCons = + tpe.getConstructors + .get(cons.name) val fun = mkConsGetter(runtimeCons) - moduleScope.registerMethod( - moduleScope.getAssociatedType, + scopeBuilder.registerMethod( + scopeAssociatedType, name, fun ) case BindingsMap.ResolvedModule(module) => val runtimeCons = - asScope( - module - .unsafeAsModule() - ).getAssociatedType + asAssociatedType(module.unsafeAsModule()) val fun = mkTypeGetter(runtimeCons) - moduleScope.registerMethod( - moduleScope.getAssociatedType, + scopeBuilder.registerMethod( + scopeAssociatedType, name, fun ) case BindingsMap.ResolvedMethod(module, method) => val actualModule = module.unsafeAsModule() - val fun = asScope(actualModule).getMethodForType( - asScope(actualModule).getAssociatedType, - method.name - ) + val fun = asScope(actualModule) + .getMethodForType( + asAssociatedType(actualModule), + method.name + ) assert( fun != null, s"exported symbol `${method.name}` needs to be registered first in the module " ) - moduleScope.registerMethod( - moduleScope.getAssociatedType, + scopeBuilder.registerMethod( + scopeAssociatedType, name, fun ) @@ -1175,9 +1141,9 @@ class IrToTruffle( val defaultRootNode = ClosureRootNode.build( language, childScope, - moduleScope, + scopeBuilder.asModuleScope(), blockNode, - makeSection(moduleScope, block.location), + makeSection(scopeBuilder.getModule, block.location), currentVarName, false, false @@ -1328,10 +1294,7 @@ class IrToTruffle( Right( ObjectEqualityBranchNode.build( branchCodeNode.getCallTarget, - asScope( - mod - .unsafeAsModule() - ).getAssociatedType, + asAssociatedType(mod.unsafeAsModule()), branch.terminalBranch ) ) @@ -1363,14 +1326,12 @@ class IrToTruffle( } Right(r) case Some( - BindingsMap.Resolution(BindingsMap.ResolvedType(mod, tp)) + BindingsMap.Resolution( + binding @ BindingsMap.ResolvedType(_, _) + ) ) => val tpe = - asScope( - mod - .unsafeAsModule() - ).getTypes - .get(tp.name) + asType(binding) val polyglot = context.getBuiltins.polyglot val branchNode = if (tpe == polyglot) { PolyglotBranchNode.build( @@ -1391,10 +1352,8 @@ class IrToTruffle( BindingsMap.ResolvedPolyglotSymbol(mod, symbol) ) ) => - val polyglotSymbol = asScope( - mod - .unsafeAsModule() - ).getPolyglotSymbol(symbol.name) + val polyglotSymbol = + asScope(mod.unsafeAsModule()).getPolyglotSymbol(symbol.name) Either.cond( polyglotSymbol != null, ObjectEqualityBranchNode @@ -1411,10 +1370,8 @@ class IrToTruffle( ) ) => val mod = typ.module - val polyClass = asScope( - mod - .unsafeAsModule() - ).getPolyglotSymbol(typ.symbol.name) + val polyClass = asScope(mod.unsafeAsModule()) + .getPolyglotSymbol(typ.symbol.name) val polyValueOrError = if (polyClass == null) @@ -1515,15 +1472,13 @@ class IrToTruffle( case None => Left(BadPatternMatch.NonVisibleType(tpeName.name)) case Some( - BindingsMap.Resolution(BindingsMap.ResolvedType(mod, tpe)) + BindingsMap.Resolution( + binding @ BindingsMap.ResolvedType(_, _) + ) ) => // Using .getTypes because .getType may return an associated type Option( - asScope( - mod - .unsafeAsModule() - ).getTypes - .get(tpe.name) + asType(binding) ) match { case Some(tpe) => val argOfType = List( @@ -1558,10 +1513,7 @@ class IrToTruffle( ) ) => val polySymbol = - asScope( - mod - .unsafeAsModule() - ).getPolyglotSymbol(symbol.name) + asScope(mod.unsafeAsModule()).getPolyglotSymbol(symbol.name) if (polySymbol != null) { val argOfType = List( DefinitionArgument.Specified( @@ -1724,10 +1676,12 @@ class IrToTruffle( val resolution = global.get.target nodeForResolution(resolution) } else if (nameStr == ConstantsNames.FROM_MEMBER) { - ConstantObjectNode.build(UnresolvedConversion.build(moduleScope)) + ConstantObjectNode.build( + UnresolvedConversion.build(scopeBuilder.asModuleScope()) + ) } else { DynamicSymbolNode.build( - UnresolvedSymbol.build(nameStr, moduleScope) + UnresolvedSymbol.build(nameStr, scopeBuilder.asModuleScope()) ) } case Name.MethodReference( @@ -1789,13 +1743,7 @@ class IrToTruffle( ): RuntimeExpression = { resolution match { case tp: BindingsMap.ResolvedType => - ConstantObjectNode.build( - asScope( - tp.module - .unsafeAsModule() - ).getTypes - .get(tp.tp.name) - ) + ConstantObjectNode.build(asType(tp)) case BindingsMap.ResolvedConstructor(definitionType, cons) => val c = asType(definitionType).getConstructors .get(cons.name) @@ -1805,16 +1753,11 @@ class IrToTruffle( ConstructorNode.build(c) case BindingsMap.ResolvedModule(module) => ConstantObjectNode.build( - asScope( - module - .unsafeAsModule() - ).getAssociatedType + asAssociatedType(module.unsafeAsModule()) ) case BindingsMap.ResolvedPolyglotSymbol(module, symbol) => - val s = asScope( - module - .unsafeAsModule() - ).getPolyglotSymbol(symbol.name) + val s = + asScope(module.unsafeAsModule()).getPolyglotSymbol(symbol.name) if (s == null) { throw new CompilerError( s"No polyglot symbol for ${symbol.name}" @@ -1822,10 +1765,8 @@ class IrToTruffle( } ConstantObjectNode.build(s) case BindingsMap.ResolvedPolyglotField(symbol, name) => - val s = asScope( - symbol.module - .unsafeAsModule() - ).getPolyglotSymbol(name) + val s = + asScope(symbol.module.unsafeAsModule()).getPolyglotSymbol(name) if (s == null) { throw new CompilerError( s"No polyglot field for ${name}" @@ -2076,9 +2017,9 @@ class IrToTruffle( val fnRootNode = ClosureRootNode.build( language, scope, - moduleScope, + scopeBuilder.asModuleScope(), bodyBuilder.bodyNode(), - makeSection(moduleScope, location), + makeSection(scopeBuilder.getModule, location), scopeName, false, binding @@ -2272,7 +2213,7 @@ class IrToTruffle( val closureRootNode = ClosureRootNode.build( language, childScope, - moduleScope, + scopeBuilder.asModuleScope(), argumentExpression, section, displayName, @@ -2358,9 +2299,12 @@ class IrToTruffle( val defaultRootNode = ClosureRootNode.build( language, scope, - moduleScope, + scopeBuilder.asModuleScope(), defaultExpression, - makeSection(moduleScope, arg.defaultValue.get.location()), + makeSection( + scopeBuilder.getModule, + arg.defaultValue.get.location() + ), s"", false, false @@ -2394,7 +2338,21 @@ class IrToTruffle( m.getScope() } - private def asType(typ: BindingsMap.ResolvedType): Type = { - asScope(typ.module.unsafeAsModule()).getTypes().get(typ.tp.name) + private def asType( + typ: BindingsMap.ResolvedType + ): Type = { + val m = org.enso.interpreter.runtime.Module + .fromCompilerModule(typ.module.unsafeAsModule()) + m.getScope().getType(typ.tp.name, true) + } + + private def asAssociatedType( + module: CompilerContext.Module + ): Type = { + val m = org.enso.interpreter.runtime.Module.fromCompilerModule(module) + m.getScope().getAssociatedType() } + + private def scopeAssociatedType = + scopeBuilder.asModuleScope().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 3de8a1f462b1..292dc1cada6e 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 @@ -1,13 +1,13 @@ package org.enso.interpreter.runtime import org.enso.compiler.data.BindingsMap -import org.enso.compiler.core.CompilerError +import org.enso.compiler.core.{CompilerError, IR} import org.enso.compiler.core.Implicits.AsMetadata import org.enso.compiler.pass.analyse.BindingAnalysis -import org.enso.interpreter.runtime.Module import org.enso.interpreter.runtime.builtin.Builtins import org.enso.interpreter.runtime.data.atom.AtomConstructor import org.enso.interpreter.runtime.data.Type +import org.enso.interpreter.runtime.scope.ModuleScope /** Generates stubs of runtime representations of atom constructors, to allow * [[IrToTruffle the code generator]] to refer to constructors that are not @@ -19,9 +19,7 @@ class RuntimeStubsGenerator(builtins: Builtins) { * * @param module the module to generate stubs in. */ - def run(module: Module): Unit = { - val ir = module.getIr - val scope = module.getScope + def run(ir: IR, scope: ModuleScope.Builder): Unit = { val localBindings = ir.unsafeGetMetadata( BindingAnalysis, "Non-parsed module used in stubs generator" @@ -74,7 +72,7 @@ class RuntimeStubsGenerator(builtins: Builtins) { val constructor = new AtomConstructor( cons.name, - scope, + scope.getModule(), rtp, false )