Extract mutable builder from ModuleScope (#9914)

Refactored mutable parts of `ModuleScope` into builder to make it easier to reduce unnecessary locks.

# Important Notes
Elements of ModuleScope (types, imports etc) are used while _building_ of it may still be in progress. In order to make static typing happy, every `ModuleScope.Builder` can be exposed as (unmodifiable) `ModuleScope`.
This commit is contained in:
Hubert Plociniczak 2024-06-05 18:57:08 +02:00 committed by GitHub
parent 698f4b5640
commit 1bc14252df
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 767 additions and 670 deletions

View File

@ -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.

View File

@ -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
}

View File

@ -28,7 +28,7 @@ class InlineContextUtils {
* 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<String> localVarNames)

View File

@ -70,11 +70,12 @@ public interface CompilerContext extends CompilerStub {
// 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 interface CompilerContext extends CompilerStub {
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 {}
}

View File

@ -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,

View File

@ -120,10 +120,10 @@ public final class ExecutionService {
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);

View File

@ -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
() => {
val maybeCallable =
UpsertVisualizationJob.evaluateVisualizationExpression(
config.visualizationModule,
config.expression
)
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
)
maybeCallable match {
case Left(ModuleNotFound(moduleName)) =>
ctx.endpoint.sendToClient(
Api.Response(Api.ModuleNotFound(moduleName))
)
None
case Left(EvaluationFailed(message, result)) =>
replyWithExpressionFailedError(
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

View File

@ -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());
}
/**

View File

@ -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 = {

View File

@ -265,7 +265,10 @@ public final class EnsoLanguage extends TruffleLanguage<EnsoContext> {
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, "<inline_source>");
} else {
exprNode = null;

View File

@ -4,7 +4,6 @@ import com.oracle.truffle.api.CompilerDirectives;
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 @@ final class InvokeMethodImportResolver
}
@Override
protected List<Type> 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<Type> definedEntities(UnresolvedSymbol symbol) {
return module.getScope().getAllTypes(symbol.getName());
}
@Override

View File

@ -29,7 +29,6 @@ import org.enso.interpreter.runtime.callable.function.Function;
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 @@ public abstract class InvokeFunctionNode extends BaseNode {
private Package<TruffleFile> 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<TruffleFile> 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;
}

View File

@ -18,10 +18,11 @@ public abstract class Builtin {
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 @@ public abstract class Builtin {
}
public final void initialize(
EnsoLanguage language, ModuleScope scope, Map<Class<? extends Builtin>, Builtin> builtins) {
EnsoLanguage language,
ModuleScope.Builder scope,
Map<Class<? extends Builtin>, Builtin> builtins) {
if (type == null) {
Type supertype = null;
if (getSuperType() != null) {

View File

@ -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 @@ import org.enso.interpreter.runtime.scope.ModuleScope;
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);

View File

@ -127,7 +127,7 @@ public final class EqualsNode extends Node {
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;
}

View File

@ -21,9 +21,9 @@ public class FindTypeByFqnNode extends Node {
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;
}
}
}

View File

@ -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);
}
}

View File

@ -86,7 +86,7 @@ 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.getScope(), compiler.getConfig());
var toTruffle = new IrToTruffle(context, src, m.getScopeBuilder(), compiler.getConfig());
var expr = toTruffle.runInline(ir, sco, "<inline_source>");
if (shouldCaptureResultScope) {

View File

@ -53,18 +53,18 @@ import org.enso.text.buffer.Rope;
/** Represents a source module with a known location. */
@ExportLibrary(InteropLibrary.class)
public final class Module implements EnsoObject {
private ModuleScope scope;
private ModuleSources sources;
private PatchedModuleValues patchedValues;
private final Map<Source, Module> allSources = new WeakHashMap<>();
private final Package<TruffleFile> pkg;
private CompilationStage compilationStage = CompilationStage.INITIAL;
private org.enso.compiler.core.ir.Module ir;
private Map<UUID, IR> uuidsMap;
private QualifiedName name;
private ModuleScope.Builder scopeBuilder;
private final Package<TruffleFile> pkg;
private final Cache<ModuleCache.CachedModule, ModuleCache.Metadata> cache;
private boolean wasLoadedFromCache;
private final boolean synthetic;
private PatchedModuleValues patchedValues;
private final Map<Source, Module> allSources = new WeakHashMap<>();
private CompilationStage compilationStage = CompilationStage.INITIAL;
private org.enso.compiler.core.ir.Module ir;
private Map<UUID, IR> uuidsMap;
/**
* 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<TruffleFile> 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 final class Module implements EnsoObject {
*/
public Module(QualifiedName name, Package<TruffleFile> 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 final class Module implements EnsoObject {
*/
public Module(QualifiedName name, Package<TruffleFile> 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 @@ public final class Module implements EnsoObject {
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 final class Module implements EnsoObject {
* @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 final class Module implements EnsoObject {
* @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 class Module implements EnsoObject {
}
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 @@ public final class Module implements EnsoObject {
* @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<String> 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 @@ public final class Module implements EnsoObject {
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 @@ public final class Module implements EnsoObject {
}
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");

View File

@ -137,10 +137,16 @@ final class TruffleCompilerContext implements CompilerContext {
}
@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 @@ final class TruffleCompilerContext implements CompilerContext {
}
@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 @@ final class TruffleCompilerContext implements CompilerContext {
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 @@ final class TruffleCompilerContext implements CompilerContext {
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;

View File

@ -126,19 +126,20 @@ public final class Builtins {
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 final class Builtins {
system = new System(this);
number = new Number(this);
special = new Special(language);
scope = scopeBuilder.build();
}
private static Map<String, LoadedBuiltinMethod> loadBuiltinMethodClassesEarly(
@ -192,7 +194,7 @@ public final class Builtins {
* @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<String, Supplier<LoadedBuiltinMethod>> methods = builtinMethodNodes.get(type.getName());
@ -226,7 +228,7 @@ public final class Builtins {
* @return map from types to builtin methods
*/
private Map<String, Map<String, Supplier<LoadedBuiltinMethod>>> registerBuiltinMethodsLazily(
ModuleScope scope, EnsoLanguage language) {
ModuleScope.Builder scope, EnsoLanguage language) {
Map<String, Map<String, Supplier<LoadedBuiltinMethod>>> builtinMethodNodes = new HashMap<>();
Map<String, Map<String, LoadedBuiltinMetaMethod>> builtinMetaMethods = new HashMap<>();
loadedBuiltinMethodsMeta.forEach(
@ -237,7 +239,7 @@ public final class Builtins {
}
String builtinMethodOwner = builtinName[0];
String builtinMethodName = builtinName[1];
Optional.ofNullable(scope.getTypes().get(builtinMethodOwner))
Optional.ofNullable(scope.asModuleScope().getType(builtinMethodOwner, true))
.ifPresentOrElse(
constr -> {
Map<String, Supplier<LoadedBuiltinMethod>> atomNodes =
@ -375,7 +377,9 @@ public final class Builtins {
/** Initialize builting types in the context of the given language and module scope */
private Map<Class<? extends Builtin>, Builtin> initializeBuiltinTypes(
List<Constructor<? extends Builtin>> constrs, EnsoLanguage language, ModuleScope scope) {
List<Constructor<? extends Builtin>> constrs,
EnsoLanguage language,
ModuleScope.Builder scope) {
Map<Class<? extends Builtin>, Builtin> builtins = new HashMap<>();
for (var constr : constrs) {
@ -400,7 +404,7 @@ public final class Builtins {
* @return A map of builtin method nodes per builtin type name
*/
private Map<String, Map<String, Supplier<LoadedBuiltinMethod>>> readBuiltinMethodsMetadata(
Map<String, LoadedBuiltinMethod> classes, ModuleScope scope) {
Map<String, LoadedBuiltinMethod> classes, ModuleScope.Builder scope) {
Map<String, Map<String, Supplier<LoadedBuiltinMethod>>> methodNodes = new HashMap<>();
classes.forEach(
@ -411,7 +415,7 @@ public final class Builtins {
}
String builtinMethodOwner = builtinName[0];
String builtinMethodName = builtinName[1];
Optional.ofNullable(scope.getTypes().get(builtinMethodOwner))
Optional.ofNullable(scope.asModuleScope().getType(builtinMethodOwner, true))
.ifPresentOrElse(
constr -> {
Map<String, Supplier<LoadedBuiltinMethod>> atomNodes =

View File

@ -28,8 +28,9 @@ import org.enso.pkg.QualifiedName;
@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 @@ public final class Type implements EnsoObject {
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 @@ public final class Type implements EnsoObject {
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 final class Type implements EnsoObject {
}
}
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 final class Type implements EnsoObject {
}
public ModuleScope getDefinitionScope() {
return definitionScope;
return definitionScope.asModuleScope();
}
public boolean isBuiltin() {

View File

@ -24,6 +24,7 @@ import org.enso.interpreter.node.MethodRootNode;
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 @@ import org.enso.pkg.QualifiedName;
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 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
* @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 @@ public final class AtomConstructor implements EnsoObject {
*
* @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 final class AtomConstructor implements EnsoObject {
*
* @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 final class AtomConstructor implements EnsoObject {
EnsoLanguage language,
SourceSection section,
LocalScope localScope,
ModuleScope.Builder scopeBuilder,
ExpressionNode[] assignments,
ExpressionNode[] varReads,
Annotation[] annotations,
@ -137,8 +148,8 @@ public final class AtomConstructor implements EnsoObject {
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 @@ public final class AtomConstructor implements EnsoObject {
EnsoLanguage language,
SourceSection section,
LocalScope localScope,
ModuleScope.Builder scopeBuilder,
ExpressionNode[] assignments,
ExpressionNode[] varReads,
Annotation[] annotations,
@ -170,7 +182,7 @@ public final class AtomConstructor implements EnsoObject {
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 @@ public final class AtomConstructor implements EnsoObject {
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 @@ public final class AtomConstructor implements EnsoObject {
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 final class AtomConstructor implements EnsoObject {
* @return the scope in which this constructor was defined
*/
public ModuleScope getDefinitionScope() {
return definitionScope;
return definitionModule.getScope();
}
/**

View File

@ -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<String> typesOnlyNames;
public ImportExportScope(CompilerContext.Module module, List<String> 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;
}
}
}

View File

@ -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 @@ import org.enso.interpreter.runtime.util.CachingSupplier;
public final class ModuleScope implements EnsoObject {
private final Type associatedType;
private final Module module;
private Map<String, Object> polyglotSymbols;
private Map<String, Type> types;
private Map<Type, Map<String, Supplier<Function>>> methods;
private Map<Type, Map<Type, Function>> conversions;
private Set<ModuleScope> imports;
private Set<ModuleScope> exports;
private final Map<String, Object> polyglotSymbols;
private final Map<String, Type> types;
private final Map<Type, Map<String, Supplier<Function>>> methods;
private final Map<Type, Map<Type, Function>> conversions;
private final Set<ImportExportScope> imports;
private final Set<ImportExportScope> 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 final class ModuleScope implements EnsoObject {
Map<String, Type> types,
Map<Type, Map<String, Supplier<Function>>> methods,
Map<Type, Map<Type, Function>> conversions,
Set<ModuleScope> imports,
Set<ModuleScope> exports) {
Set<ImportExportScope> imports,
Set<ImportExportScope> exports) {
this.module = module;
this.associatedType = associatedType;
this.polyglotSymbols = polyglotSymbols;
@ -75,11 +53,6 @@ public final class ModuleScope implements EnsoObject {
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 final class ModuleScope implements EnsoObject {
return module;
}
/**
* @return the set of modules imported by this module.
*/
public Set<ModuleScope> 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<String, Supplier<Function>> ensureMethodMapFor(Type type) {
Type tpeKey = type == null ? noTypeKey : type;
return methods.computeIfAbsent(tpeKey, k -> new LinkedHashMap<>());
}
private Map<String, Supplier<Function>> getMethodMapFor(Type type) {
Type tpeKey = type == null ? noTypeKey : type;
Map<String, Supplier<Function>> 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<String, Supplier<Function>> 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<Function> supply) {
Map<String, Supplier<Function>> 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<Type, Function> ensureConversionsFor(Type type) {
return conversions.computeIfAbsent(type, k -> new LinkedHashMap<>());
}
private Map<Type, Function> 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 final class ModuleScope implements EnsoObject {
* @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 final class ModuleScope implements EnsoObject {
.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 final class ModuleScope implements EnsoObject {
.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 Map<String, Type> getTypes() {
return types;
public List<Type> getAllTypes(String name) {
var tpes = new ArrayList<Type>(types.size() + 1);
var tpe0 = getType(name, false);
if (tpe0 != null) tpes.add(tpe0);
tpes.addAll(types.values());
return tpes;
}
@ExportMessage.Ignore
public Optional<Type> getType(String name) {
if (associatedType.getName().equals(name)) {
return Optional.of(associatedType);
public Type getType(String name, boolean ignoreAssociatedType) {
if (!ignoreAssociatedType && associatedType.getName().equals(name)) {
return associatedType;
}
return Optional.ofNullable(types.get(name));
return types.get(name);
}
@ExportMessage.Ignore
public boolean hasType(Type type) {
return types.get(type.getName()) == type;
}
/**
@ -352,18 +206,12 @@ public final class ModuleScope implements EnsoObject {
}
}
/**
* 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<Type, Function> getConversionsFor(Type type) {
var result = conversions.get(type);
if (result == null) {
return new LinkedHashMap<>();
}
return result;
}
/**
@ -392,60 +240,6 @@ public final class ModuleScope implements EnsoObject {
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<String> typeNames) {
Map<String, Object> polyglotSymbols = new LinkedHashMap<>(this.polyglotSymbols);
Map<String, Type> requestedTypes = new LinkedHashMap<>(this.types);
Map<Type, Map<String, Supplier<Function>>> methods = new LinkedHashMap<>();
Map<Type, Map<Type, Function>> conversions = new LinkedHashMap<>();
Set<ModuleScope> imports = new LinkedHashSet<>(this.imports);
Set<ModuleScope> exports = new LinkedHashSet<>(this.exports);
this.types
.entrySet()
.forEach(
entry -> {
if (typeNames.contains(entry.getKey())) {
requestedTypes.put(entry.getKey(), entry.getValue());
}
});
Collection<Type> 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 @@ public final class ModuleScope implements EnsoObject {
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<String, Object> polyglotSymbols;
private final Map<String, Type> types;
private final Map<Type, Map<String, Supplier<Function>>> methods;
private final Map<Type, Map<Type, Function>> conversions;
private final Set<ImportExportScope> imports;
private final Set<ImportExportScope> 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<String, Type> 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<String, Object> polyglotSymbols,
Map<String, Type> types,
Map<Type, Map<String, Supplier<Function>>> methods,
Map<Type, Map<Type, Function>> conversions,
Set<ImportExportScope> imports,
Set<ImportExportScope> 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<String, Supplier<Function>> 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<String, Supplier<Function>> 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<Function> supply) {
assert moduleScope == null;
Map<String, Supplier<Function>> 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();
}
}
}

View File

@ -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;
}
}

View File

@ -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"<default::$scopeName::${arg.name.showCode()}>",
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
}

View File

@ -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
)