Avoid long existing ModuleScope.Builder

This commit is contained in:
Jaroslav Tulach 2024-06-10 22:04:56 +02:00
parent f12e985b3a
commit b4aaa51676
11 changed files with 274 additions and 180 deletions

View File

@ -264,12 +264,8 @@ public final class EnsoLanguage extends TruffleLanguage<EnsoContext> {
var mod = newInlineContext.getModule();
var m = org.enso.interpreter.runtime.Module.fromCompilerModule(mod);
var toTruffle =
new IrToTruffle(
context,
request.getSource(),
m.getScopeBuilder(),
redirectConfigWithStrictErrors);
exprNode = toTruffle.runInline(ir, sco, "<inline_source>");
new IrToTruffle(context, request.getSource(), m, redirectConfigWithStrictErrors);
exprNode = toTruffle.runInline(m.getScope(), ir, sco, "<inline_source>");
} else {
exprNode = null;
}

View File

@ -6,6 +6,7 @@ import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;
import org.enso.interpreter.EnsoLanguage;
import org.enso.interpreter.runtime.Module;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.data.Type;
import org.enso.interpreter.runtime.data.atom.AtomConstructor;
@ -18,8 +19,10 @@ public abstract class Builtin {
this(name, Arrays.asList(params));
}
private AtomConstructor build(EnsoLanguage language, ModuleScope.Builder scope, Type type) {
var res = new AtomConstructor(name, scope.getModule(), type, true);
private AtomConstructor build(
EnsoLanguage language, ModuleScope.Builder builder, ModuleScope scope, Type type) {
var res = new AtomConstructor(name, builder.getModule(), type, true);
res.initializeBuilder(language, builder);
res.initializeFields(
language,
scope,
@ -52,30 +55,33 @@ public abstract class Builtin {
public final void initialize(
EnsoLanguage language,
ModuleScope.Builder scope,
Module module,
ModuleScope.Builder builder,
ModuleScope scope,
Map<Class<? extends Builtin>, Builtin> builtins) {
if (type == null) {
Type supertype = null;
if (getSuperType() != null) {
var s = builtins.get(getSuperType());
s.initialize(language, scope, builtins);
s.initialize(language, module, builder, scope, builtins);
supertype = s.getType();
}
type =
containsValues()
? Type.create(name, scope, supertype, builtins.get(Any.class).getType(), true, false)
: Type.createSingleton(name, scope, supertype, true, false);
? Type.create(
name, module, builder, supertype, builtins.get(Any.class).getType(), true, false)
: Type.createSingleton(name, module, supertype, true, false);
}
if (constructors == null) {
var conses = getDeclaredConstructors();
constructors = new AtomConstructor[conses.size()];
for (int i = 0; i < constructors.length; i++) {
var cons = conses.get(i).build(language, scope, type);
var cons = conses.get(i).build(language, builder, scope, type);
constructors[i] = cons;
type.registerConstructor(cons);
}
}
type.generateGetters(language);
type.generateGetters(builder, language);
postInitialize();
}

View File

@ -86,8 +86,8 @@ public abstract class EvalNode extends BaseNode {
var sco = newInlineContext.localScope().getOrElse(LocalScope::root);
var mod = newInlineContext.getModule();
var m = org.enso.interpreter.runtime.Module.fromCompilerModule(mod);
var toTruffle = new IrToTruffle(context, src, m.getScopeBuilder(), compiler.getConfig());
var expr = toTruffle.runInline(ir, sco, "<inline_source>");
var toTruffle = new IrToTruffle(context, src, m, compiler.getConfig());
var expr = toTruffle.runInline(m.getScope(), ir, sco, "<inline_source>");
if (shouldCaptureResultScope) {
expr = CaptureResultScopeNode.build(expr);

View File

@ -55,7 +55,7 @@ import org.enso.text.buffer.Rope;
public final class Module implements EnsoObject {
private ModuleSources sources;
private QualifiedName name;
private ModuleScope.Builder scopeBuilder;
private ModuleScope moduleScope;
private final Package<TruffleFile> pkg;
private final Cache<ModuleCache.CachedModule, ModuleCache.Metadata> cache;
private boolean wasLoadedFromCache;
@ -87,7 +87,7 @@ public final class Module implements EnsoObject {
public Module(QualifiedName name, Package<TruffleFile> pkg, TruffleFile sourceFile) {
this.sources = ModuleSources.NONE.newWith(sourceFile);
this.name = name;
this.scopeBuilder = new ModuleScope.Builder(this);
this.moduleScope = new ModuleScope.Builder(this).build();
this.pkg = pkg;
this.cache = ModuleCache.create(this);
this.wasLoadedFromCache = false;
@ -105,7 +105,7 @@ public final class Module implements EnsoObject {
public Module(QualifiedName name, Package<TruffleFile> pkg, String literalSource) {
this.sources = ModuleSources.NONE.newWith(Rope.apply(literalSource));
this.name = name;
this.scopeBuilder = new ModuleScope.Builder(this);
this.moduleScope = new ModuleScope.Builder(this).build();
this.pkg = pkg;
this.cache = ModuleCache.create(this);
this.wasLoadedFromCache = false;
@ -124,7 +124,7 @@ public final class Module implements EnsoObject {
public Module(QualifiedName name, Package<TruffleFile> pkg, Rope literalSource) {
this.sources = ModuleSources.NONE.newWith(literalSource);
this.name = name;
this.scopeBuilder = new ModuleScope.Builder(this);
this.moduleScope = new ModuleScope.Builder(this).build();
this.pkg = pkg;
this.cache = ModuleCache.create(this);
this.wasLoadedFromCache = false;
@ -144,14 +144,13 @@ public final class Module implements EnsoObject {
this.sources =
literalSource == null ? ModuleSources.NONE : ModuleSources.NONE.newWith(literalSource);
this.name = name;
this.scopeBuilder = new ModuleScope.Builder(this);
this.moduleScope = new ModuleScope.Builder(this).build();
this.pkg = pkg;
this.cache = ModuleCache.create(this);
this.wasLoadedFromCache = false;
this.synthetic = synthetic;
if (synthetic) {
this.compilationStage = CompilationStage.INITIAL;
scopeBuilder.build();
} else {
this.compilationStage = CompilationStage.AFTER_CODEGEN;
}
@ -328,7 +327,7 @@ public final class Module implements EnsoObject {
} catch (IOException ignored) {
}
}
return scopeBuilder.build();
return moduleScope;
}
/**
@ -386,7 +385,7 @@ public final class Module implements EnsoObject {
private void compile(EnsoContext context) throws IOException {
Source source = getSource();
if (source == null) return;
scopeBuilder = newScopeBuilder(false);
moduleScope = newScopeBuilder(false).build();
compilationStage = CompilationStage.INITIAL;
context.getCompiler().run(asCompilerModule());
}
@ -456,20 +455,14 @@ public final class Module implements EnsoObject {
* @return the runtime scope of this module.
*/
public ModuleScope getScope() {
return scopeBuilder.asModuleScope();
}
public ModuleScope.Builder getScopeBuilder() {
return scopeBuilder;
return moduleScope;
}
public ModuleScope.Builder newScopeBuilder(boolean inheritTypes) {
if (inheritTypes) {
this.scopeBuilder = this.scopeBuilder.newBuilderInheritingTypes();
} else {
this.scopeBuilder = new ModuleScope.Builder(this);
}
return this.scopeBuilder;
var builder = // inheritTypes ?
// this.scopeBuilder.newBuilderInheritingTypes();
new ModuleScope.Builder(this);
return builder;
}
/**

View File

@ -146,7 +146,7 @@ final class TruffleCompilerContext implements CompilerContext {
var s =
org.enso.interpreter.runtime.scope.ModuleScope.Builder.fromCompilerModuleScopeBuilder(
scopeBuilder);
new IrToTruffle(context, m.getSource(), s, config).run(module.getIr());
new IrToTruffle(context, m.getSource(), m, config).run(module.getIr());
}
// module related
@ -823,7 +823,7 @@ final class TruffleCompilerContext implements CompilerContext {
@Override
public CompilerContext.ModuleScopeBuilder getScopeBuilder() {
return new org.enso.interpreter.runtime.scope.TruffleCompilerModuleScopeBuilder(
module.getScopeBuilder());
module.newScopeBuilder(true));
}
@Override

View File

@ -129,7 +129,9 @@ public final class Builtins {
module.compileScope(context); // Dummy compilation for an empty module
ModuleScope.Builder scopeBuilder = module.newScopeBuilder(false);
builtins = initializeBuiltinTypes(loadedBuiltinConstructors, language, scopeBuilder);
builtins =
initializeBuiltinTypes(
loadedBuiltinConstructors, language, scopeBuilder, null /* as no scope */);
builtinsByName =
builtins.values().stream()
.collect(
@ -239,7 +241,7 @@ public final class Builtins {
}
String builtinMethodOwner = builtinName[0];
String builtinMethodName = builtinName[1];
Optional.ofNullable(scope.asModuleScope().getType(builtinMethodOwner, true))
Optional.ofNullable(scope.getType(builtinMethodOwner, true))
.ifPresentOrElse(
constr -> {
Map<String, Supplier<LoadedBuiltinMethod>> atomNodes =
@ -375,11 +377,12 @@ public final class Builtins {
.collect(Collectors.toList());
}
/** Initialize builting types in the context of the given language and module scope */
/** Initialize builting types in the context of the given language and module builder */
private Map<Class<? extends Builtin>, Builtin> initializeBuiltinTypes(
List<Constructor<? extends Builtin>> constrs,
EnsoLanguage language,
ModuleScope.Builder scope) {
ModuleScope.Builder builder,
ModuleScope scope) {
Map<Class<? extends Builtin>, Builtin> builtins = new HashMap<>();
for (var constr : constrs) {
@ -391,7 +394,7 @@ public final class Builtins {
}
}
for (var b : builtins.values()) {
b.initialize(language, scope, builtins);
b.initialize(language, getModule(), builder, scope, builtins);
}
return builtins;
}
@ -400,11 +403,11 @@ public final class Builtins {
* Returns a map of Builtin methods associated with their owner.
*
* @param classes a map of (already loaded) builtin methods
* @param scope Builtins scope
* @param builder Builtins builder
* @return A map of builtin method nodes per builtin type name
*/
private Map<String, Map<String, Supplier<LoadedBuiltinMethod>>> readBuiltinMethodsMetadata(
Map<String, LoadedBuiltinMethod> classes, ModuleScope.Builder scope) {
Map<String, LoadedBuiltinMethod> classes, ModuleScope.Builder builder) {
Map<String, Map<String, Supplier<LoadedBuiltinMethod>>> methodNodes = new HashMap<>();
classes.forEach(
@ -415,7 +418,7 @@ public final class Builtins {
}
String builtinMethodOwner = builtinName[0];
String builtinMethodName = builtinName[1];
Optional.ofNullable(scope.asModuleScope().getType(builtinMethodOwner, true))
Optional.ofNullable(builder.getType(builtinMethodOwner, true))
.ifPresentOrElse(
constr -> {
Map<String, Supplier<LoadedBuiltinMethod>> atomNodes =

View File

@ -16,6 +16,7 @@ import org.enso.interpreter.Constants;
import org.enso.interpreter.EnsoLanguage;
import org.enso.interpreter.node.ConstantNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.Module;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
@ -30,7 +31,7 @@ import org.enso.pkg.QualifiedName;
public final class Type implements EnsoObject {
private final String name;
private @CompilerDirectives.CompilationFinal ModuleScope.Builder definitionScope;
private final Module definingModule;
private final boolean builtin;
private final Type supertype;
private final Type eigentype;
@ -41,13 +42,13 @@ public final class Type implements EnsoObject {
private Type(
String name,
ModuleScope.Builder definitionScope,
Module definingModule,
Type supertype,
Type eigentype,
boolean builtin,
boolean isProjectPrivate) {
this.name = name;
this.definitionScope = definitionScope;
this.definingModule = definingModule;
this.supertype = supertype;
this.builtin = builtin;
this.isProjectPrivate = isProjectPrivate;
@ -57,23 +58,24 @@ public final class Type implements EnsoObject {
public static Type createSingleton(
String name,
ModuleScope.Builder definitionScope,
Module definingModule,
Type supertype,
boolean builtin,
boolean isProjectPrivate) {
return new Type(name, definitionScope, supertype, null, builtin, isProjectPrivate);
return new Type(name, definingModule, supertype, null, builtin, isProjectPrivate);
}
public static Type create(
String name,
ModuleScope.Builder definitionScope,
Module definingModule,
ModuleScope.Builder builder,
Type supertype,
Type any,
boolean builtin,
boolean isProjectPrivate) {
var eigentype = new Type(name + ".type", definitionScope, any, null, builtin, isProjectPrivate);
var result = new Type(name, definitionScope, supertype, eigentype, builtin, isProjectPrivate);
result.generateQualifiedAccessor();
var eigentype = new Type(name + ".type", definingModule, any, null, builtin, isProjectPrivate);
var result = new Type(name, definingModule, supertype, eigentype, builtin, isProjectPrivate);
result.generateQualifiedAccessor(builder);
return result;
}
@ -81,7 +83,7 @@ public final class Type implements EnsoObject {
return new Type("null", null, null, null, false, false);
}
private void generateQualifiedAccessor() {
private void generateQualifiedAccessor(ModuleScope.Builder builder) {
var node = new ConstantNode(null, this);
var schemaBldr =
FunctionSchema.newBuilder()
@ -92,29 +94,27 @@ public final class Type implements EnsoObject {
schemaBldr.projectPrivate();
}
var function = new Function(node.getCallTarget(), null, schemaBldr.build());
definitionScope.registerMethod(
definitionScope.asModuleScope().getAssociatedType(), this.name, function);
builder.registerMethod(null /* as builder.getAssociatedType() */, this.name, function);
}
public QualifiedName getQualifiedName() {
if (this == this.getDefinitionScope().getAssociatedType()) {
return definitionScope.getModule().getName();
return definingModule.getName();
} else {
return definitionScope.getModule().getName().createChild(getName());
return definingModule.getName().createChild(getName());
}
}
public void setShadowDefinitions(ModuleScope.Builder scope, boolean generateAccessorsInTarget) {
public void setShadowDefinitions(ModuleScope.Builder builder, boolean generateAccessorsInTarget) {
if (builtin) {
// Ensure that synthetic methods, such as getters for fields are in the scope.
// Ensure that synthetic methods, such as getters for fields are in the builder.
CompilerAsserts.neverPartOfCompilation();
this.definitionScope.registerAllMethodsOfTypeToScope(this, scope);
this.definitionScope = scope;
this.definingModule.getScope().registerAllMethodsOfTypeToScope(this, builder);
if (generateAccessorsInTarget) {
generateQualifiedAccessor();
generateQualifiedAccessor(builder);
}
if (getEigentype() != this) {
getEigentype().setShadowDefinitions(scope, false);
getEigentype().setShadowDefinitions(builder, false);
}
} else {
throw new RuntimeException(
@ -127,7 +127,7 @@ public final class Type implements EnsoObject {
}
public ModuleScope getDefinitionScope() {
return definitionScope.asModuleScope();
return definingModule.getScope();
}
public boolean isBuiltin() {
@ -174,7 +174,7 @@ public final class Type implements EnsoObject {
return allTypes;
}
public void generateGetters(EnsoLanguage language) {
public void generateGetters(ModuleScope.Builder builder, EnsoLanguage language) {
if (gettersGenerated) return;
gettersGenerated = true;
var roots = AtomConstructor.collectFieldAccessors(language, this);
@ -194,7 +194,7 @@ public final class Type implements EnsoObject {
}
var funcSchema = schemaBldr.build();
var f = new Function(node.getCallTarget(), null, funcSchema);
definitionScope.registerMethod(this, name, f);
builder.registerMethod(this, name, f);
});
}

View File

@ -104,7 +104,7 @@ public final class AtomConstructor implements EnsoObject {
* @return {@code this}, for convenience
*/
public AtomConstructor initializeFields(
EnsoLanguage language, ModuleScope.Builder scopeBuilder, ArgumentDefinition... args) {
EnsoLanguage language, ModuleScope scope, ArgumentDefinition... args) {
ExpressionNode[] reads = new ExpressionNode[args.length];
for (int i = 0; i < args.length; i++) {
reads[i] = ReadArgumentNode.build(i, null, null);
@ -113,13 +113,25 @@ public final class AtomConstructor implements EnsoObject {
language,
null,
LocalScope.root(),
scopeBuilder,
scope,
new ExpressionNode[0],
reads,
new Annotation[0],
args);
}
/**
* Sets the fields of this {@link AtomConstructor} and generates a constructor function.
*
* @param scopeBuilder the module scope's builder where the accessor should be registered at
* @return {@code this}, for convenience
*/
public AtomConstructor initializeBuilder(
EnsoLanguage language, ModuleScope.Builder scopeBuilder) {
this.accessor = generateQualifiedAccessor(language, scopeBuilder);
return this;
}
/**
* Sets the fields of this {@link AtomConstructor} and generates a constructor function.
*
@ -133,7 +145,7 @@ public final class AtomConstructor implements EnsoObject {
EnsoLanguage language,
SourceSection section,
LocalScope localScope,
ModuleScope.Builder scopeBuilder,
ModuleScope scope,
ExpressionNode[] assignments,
ExpressionNode[] varReads,
Annotation[] annotations,
@ -148,8 +160,7 @@ public final class AtomConstructor implements EnsoObject {
boxedLayout = Layout.createBoxed(args);
this.constructorFunction =
buildConstructorFunction(
language, section, localScope, scopeBuilder, assignments, varReads, annotations, args);
this.accessor = generateQualifiedAccessor(language, scopeBuilder);
language, section, localScope, scope, assignments, varReads, annotations, args);
return this;
}
@ -170,7 +181,7 @@ public final class AtomConstructor implements EnsoObject {
EnsoLanguage language,
SourceSection section,
LocalScope localScope,
ModuleScope.Builder scopeBuilder,
ModuleScope scope,
ExpressionNode[] assignments,
ExpressionNode[] varReads,
Annotation[] annotations,
@ -182,7 +193,7 @@ public final class AtomConstructor implements EnsoObject {
BlockNode instantiateBlock = BlockNode.buildSilent(assignments, instantiateNode);
RootNode rootNode =
MethodRootNode.buildConstructor(
language, localScope, scopeBuilder.asModuleScope(), instantiateBlock, section, this);
language, localScope, scope, instantiateBlock, section, this);
RootCallTarget callTarget = rootNode.getCallTarget();
var schemaBldr = FunctionSchema.newBuilder().annotations(annotations).argumentDefinitions(args);
if (type.isProjectPrivate()) {

View File

@ -255,6 +255,21 @@ public final class ModuleScope implements EnsoObject {
return "Scope" + module;
}
/**
* Registers all methods of a type in the provided scope.
*
* @param tpe the methods of which type should be registered
* @param scope target scope where methods should be registered to
*/
public void registerAllMethodsOfTypeToScope(Type tpe, ModuleScope.Builder scope) {
// FIXME: because of Builtins can't enable 'assert moduleScope == null;'
Type tpeKey = tpe == null ? noTypeKey : tpe;
var allTypeMethods = methods.get(tpeKey);
if (allTypeMethods != null) {
allTypeMethods.forEach((name, fun) -> scope.registerMethod(tpeKey, name, fun));
}
}
public static class Builder {
@CompilerDirectives.CompilationFinal private ModuleScope moduleScope = null;
@ -275,7 +290,8 @@ public final class ModuleScope implements EnsoObject {
this.conversions = new LinkedHashMap<>();
this.imports = new LinkedHashSet<>();
this.exports = new LinkedHashSet<>();
this.associatedType = Type.createSingleton(module.getName().item(), this, null, false, false);
this.associatedType =
Type.createSingleton(module.getName().item(), module, null, false, false);
}
public Builder(Module module, Map<String, Type> types) {
@ -286,7 +302,8 @@ public final class ModuleScope implements EnsoObject {
this.conversions = new LinkedHashMap<>();
this.imports = new LinkedHashSet<>();
this.exports = new LinkedHashSet<>();
this.associatedType = Type.createSingleton(module.getName().item(), this, null, false, false);
this.associatedType =
Type.createSingleton(module.getName().item(), module, null, false, false);
}
public Builder(
@ -314,6 +331,20 @@ public final class ModuleScope implements EnsoObject {
return current == null ? type : current;
}
/**
* Get a type registered in this builder.
*
* @param name name of the type
* @param ignoreAssociatedType ignore associated type or not?
* @return type or {@code null}
*/
public Type getType(String name, boolean ignoreAssociatedType) {
if (!ignoreAssociatedType && associatedType.getName().equals(name)) {
return associatedType;
}
return types.get(name);
}
/**
* Returns a map of methods defined in this module for a given type.
*
@ -354,6 +385,9 @@ public final class ModuleScope implements EnsoObject {
*/
public void registerMethod(Type type, String method, Supplier<Function> supply) {
assert moduleScope == null;
if (type == null) {
type = this.associatedType;
}
Map<String, Supplier<Function>> methodMap = ensureMethodMapFor(type);
// Builtin types will have double definition because of
@ -393,21 +427,6 @@ public final class ModuleScope implements EnsoObject {
polyglotSymbols.put(name, sym);
}
/**
* Registers all methods of a type in the provided scope.
*
* @param tpe the methods of which type should be registered
* @param scope target scope where methods should be registered to
*/
public void registerAllMethodsOfTypeToScope(Type tpe, ModuleScope.Builder scope) {
// FIXME: because of Builtins can't enable 'assert moduleScope == null;'
Type tpeKey = tpe == null ? noTypeKey : tpe;
var allTypeMethods = methods.get(tpeKey);
if (allTypeMethods != null) {
allTypeMethods.forEach((name, fun) -> scope.registerMethod(tpeKey, name, fun));
}
}
/**
* Adds a dependency for this module.
*
@ -450,7 +469,7 @@ public final class ModuleScope implements EnsoObject {
*/
public ModuleScope build() {
if (moduleScope == null) {
moduleScope =
return moduleScope =
new ModuleScope(
module,
associatedType,
@ -460,8 +479,9 @@ public final class ModuleScope implements EnsoObject {
Collections.unmodifiableMap(conversions),
Collections.unmodifiableSet(imports),
Collections.unmodifiableSet(exports));
} else {
throw new AssertionError("Already built");
}
return moduleScope;
}
public static ModuleScope.Builder fromCompilerModuleScopeBuilder(
@ -469,26 +489,6 @@ public final class ModuleScope implements EnsoObject {
return ((TruffleCompilerModuleScopeBuilder) scopeBuilder).unsafeScopeBuilder();
}
/**
* Return a view on `this` as a ModuleScope, rather than its builder.
*
* @return ModuleScope, if the builder has already been `built`, a proxy instance with the
* currently registered entities
*/
public ModuleScope asModuleScope() {
if (moduleScope != null) return moduleScope;
else
return new ModuleScope(
module,
associatedType,
Collections.unmodifiableMap(polyglotSymbols),
Collections.unmodifiableMap(types),
Collections.unmodifiableMap(methods),
Collections.unmodifiableMap(conversions),
Collections.unmodifiableSet(imports),
Collections.unmodifiableSet(exports));
}
@Override
public java.lang.String toString() {
StringBuilder builder = new StringBuilder();

View File

@ -126,13 +126,13 @@ import org.enso.interpreter.runtime.error.DataflowError
* @param context the language context instance for which this is executing
* @param source the source code that corresponds to the text for which code
* is being generated
* @param scopeBuilder the scope's builder of the module for which code is being generated
* @param module the module for which we are building the Truffle representation
* @param compilerConfig the configuration for the compiler
*/
class IrToTruffle(
val context: EnsoContext,
val source: Source,
val scopeBuilder: ModuleScope.Builder,
val module: org.enso.interpreter.runtime.Module,
val compilerConfig: CompilerConfig
) {
@ -164,6 +164,7 @@ class IrToTruffle(
* @return an truffle expression representing `ir`
*/
def runInline(
moduleScope: ModuleScope,
ir: Expression,
localScope: LocalScope,
scopeName: String
@ -171,8 +172,8 @@ class IrToTruffle(
new ExpressionProcessor(
localScope,
scopeName,
scopeBuilder.getModule().getName().toString()
).runInline(ir)
module.getName().toString()
).runInline(moduleScope, ir)
}
// ==========================================================================
@ -188,7 +189,8 @@ class IrToTruffle(
* @param module the module for which code should be generated
*/
private def processModule(module: Module): Unit = {
generateReExportBindings(module)
val scopeBuilder = this.module.newScopeBuilder(true)
generateReExportBindings(scopeBuilder, module)
val bindingsMap =
module
.unsafeGetMetadata(
@ -229,7 +231,7 @@ class IrToTruffle(
)
hostSymbol = DataflowError.withoutTrace(err, null)
}
this.scopeBuilder.registerPolyglotSymbol(
scopeBuilder.registerPolyglotSymbol(
poly.getVisibleName,
hostSymbol
)
@ -238,10 +240,30 @@ class IrToTruffle(
}
val typeDefs = module.bindings.collect { case tp: Definition.Type => tp }
typeDefs.foreach { tpDef =>
// Register the atoms and their constructors in scope
val atomDefs = tpDef.members
val asType = scopeBuilder.asModuleScope().getType(tpDef.name.name, true)
val asType = scopeBuilder.getType(tpDef.name.name, true)
val atomConstructors =
atomDefs.map(cons => asType.getConstructors.get(cons.name.name))
atomConstructors
.zip(atomDefs)
.foreach { case (atomCons, _) =>
atomCons.initializeBuilder(
language,
scopeBuilder
)
}
asType.generateGetters(scopeBuilder, language)
}
val moduleScope = scopeBuilder.build()
typeDefs.foreach { tpDef =>
// Register the atoms and their constructors in scope
val atomDefs = tpDef.members
val asType = moduleScope.getType(tpDef.name.name, true)
val atomConstructors =
atomDefs.map(cons => asType.getConstructors.get(cons.name.name))
atomConstructors
@ -267,6 +289,7 @@ class IrToTruffle(
val argFactory =
new DefinitionArgumentProcessor(
moduleScope = moduleScope,
scope = localScope,
initialName = "Type " + tpDef.name
)
@ -278,7 +301,8 @@ class IrToTruffle(
for (idx <- atomDefn.arguments.indices) {
val unprocessedArg = atomDefn.arguments(idx)
val checkNode = checkAsTypes(unprocessedArg)
val arg = argFactory.run(unprocessedArg, idx, checkNode)
val arg =
argFactory.run(moduleScope, unprocessedArg, idx, checkNode)
val occInfo = unprocessedArg
.unsafeGetMetadata(
AliasAnalysis,
@ -317,14 +341,14 @@ class IrToTruffle(
atomDefn.name.name
)
val expressionNode =
expressionProcessor.run(annotation.expression, true)
expressionProcessor.run(moduleScope, annotation.expression, true)
val closureName = s"<default::$scopeName>"
val closureRootNode = ClosureRootNode.build(
language,
expressionProcessor.scope,
scopeBuilder.asModuleScope(),
moduleScope,
expressionNode,
makeSection(scopeBuilder.getModule, annotation.location),
makeSection(this.module, annotation.location),
closureName,
true,
false
@ -334,9 +358,9 @@ class IrToTruffle(
if (!atomCons.isInitialized) {
atomCons.initializeFields(
language,
makeSection(scopeBuilder.getModule, atomDefn.location),
makeSection(this.module, atomDefn.location),
localScope,
scopeBuilder,
moduleScope,
assignments.toArray,
reads.toArray,
annotations.toArray,
@ -344,7 +368,6 @@ class IrToTruffle(
)
}
}
asType.generateGetters(language)
}
// Register the method definitions in scope
@ -498,6 +521,7 @@ class IrToTruffle(
}
val bodyBuilder =
new expressionProcessor.BuildFunctionBody(
moduleScope,
m.getFunction.getName,
fn.arguments,
fn.body,
@ -508,7 +532,7 @@ class IrToTruffle(
m.getFunction.getCallTarget.getRootNode
.asInstanceOf[BuiltinRootNode]
builtinRootNode
.setModuleName(scopeBuilder.getModule.getName)
.setModuleName(this.module.getName)
builtinRootNode.setTypeName(cons.getQualifiedName)
val funcSchemaBldr = FunctionSchema
.newBuilder()
@ -530,6 +554,7 @@ class IrToTruffle(
case fn: Function =>
val bodyBuilder =
new expressionProcessor.BuildFunctionBody(
moduleScope,
fullMethodDefName,
fn.arguments,
fn.body,
@ -550,11 +575,11 @@ class IrToTruffle(
MethodRootNode.buildOperator(
language,
expressionProcessor.scope,
scopeBuilder.asModuleScope(),
moduleScope,
() => bodyBuilder.argsExpr._1(0),
() => bodyBuilder.argsExpr._1(1),
() => bodyBuilder.argsExpr._2,
makeSection(scopeBuilder.getModule, methodDef.location),
makeSection(this.module, methodDef.location),
cons,
methodDef.methodName.name
)
@ -562,9 +587,9 @@ class IrToTruffle(
MethodRootNode.build(
language,
expressionProcessor.scope,
scopeBuilder.asModuleScope(),
moduleScope,
() => bodyBuilder.bodyNode(),
makeSection(scopeBuilder.getModule, methodDef.location),
makeSection(this.module, methodDef.location),
cons,
methodDef.methodName.name
)
@ -607,16 +632,17 @@ class IrToTruffle(
methodDef.methodName.name
)
val expressionNode =
expressionProcessor.run(annotation.expression, true)
expressionProcessor
.run(moduleScope, annotation.expression, true)
val closureName =
s"<default::${expressionProcessor.scopeName}>"
val closureRootNode = ClosureRootNode.build(
language,
expressionProcessor.scope,
scopeBuilder.asModuleScope(),
moduleScope,
expressionNode,
makeSection(
scopeBuilder.getModule,
this.module,
annotation.location
),
closureName,
@ -706,6 +732,7 @@ class IrToTruffle(
case fn: Function =>
val bodyBuilder =
new expressionProcessor.BuildFunctionBody(
moduleScope,
methodDef.methodName.name,
fn.arguments,
fn.body,
@ -715,9 +742,9 @@ class IrToTruffle(
val rootNode = MethodRootNode.build(
language,
expressionProcessor.scope,
scopeBuilder.asModuleScope(),
moduleScope,
() => bodyBuilder.bodyNode(),
makeSection(scopeBuilder.getModule, methodDef.location),
makeSection(this.module, methodDef.location),
toType,
methodDef.methodName.name
)
@ -897,7 +924,10 @@ class IrToTruffle(
expr
}
private def generateReExportBindings(module: Module): Unit = {
private def generateReExportBindings(
scopeBuilder: ModuleScope.Builder,
module: Module
): Unit = {
def mkConsGetter(constructor: AtomConstructor): RuntimeFunction =
constructor.getAccessorFunction()
@ -930,7 +960,7 @@ class IrToTruffle(
if (
resolution.isInstanceOf[ResolvedConstructor] || !resolution.module
.unsafeAsModule()
.equals(scopeBuilder.getModule.asCompilerModule)
.equals(module)
) {
resolution match {
case binding @ BindingsMap.ResolvedType(_, _) =>
@ -1051,25 +1081,28 @@ class IrToTruffle(
* @return a truffle expression that represents the same program as `ir`
*/
def run(
moduleScope: ModuleScope,
ir: Expression,
subjectToInstrumentation: Boolean
): RuntimeExpression = run(ir, false, subjectToInstrumentation)
): RuntimeExpression = run(moduleScope, ir, false, subjectToInstrumentation)
private def run(
moduleScope: ModuleScope,
ir: Expression,
binding: Boolean,
subjectToInstrumentation: Boolean
): RuntimeExpression = {
var runtimeExpression = ir match {
case block: Expression.Block => processBlock(block)
case block: Expression.Block => processBlock(moduleScope, block)
case literal: Literal => processLiteral(literal)
case app: Application =>
processApplication(app, subjectToInstrumentation)
case name: Name => processName(name)
case function: Function => processFunction(function, binding)
case binding: Expression.Binding => processBinding(binding)
processApplication(moduleScope, app, subjectToInstrumentation)
case name: Name => processName(moduleScope, name)
case function: Function =>
processFunction(moduleScope, function, binding)
case binding: Expression.Binding => processBinding(moduleScope, binding)
case caseExpr: Case =>
processCase(caseExpr, subjectToInstrumentation)
processCase(moduleScope, caseExpr, subjectToInstrumentation)
case typ: Tpe => processType(typ)
case _: Empty =>
processEmpty()
@ -1108,8 +1141,11 @@ class IrToTruffle(
* @param ir the IR to generate code for
* @return a truffle expression that represents the same program as `ir`
*/
def runInline(ir: Expression): RuntimeExpression = {
val expression = run(ir, false)
def runInline(
moduleScope: ModuleScope,
ir: Expression
): RuntimeExpression = {
val expression = run(moduleScope, ir, false)
expression
}
@ -1120,7 +1156,10 @@ class IrToTruffle(
* @param block the block to generate code for
* @return the truffle nodes corresponding to `block`
*/
private def processBlock(block: Expression.Block): RuntimeExpression = {
private def processBlock(
moduleScope: ModuleScope,
block: Expression.Block
): RuntimeExpression = {
if (block.suspended) {
val scopeInfo = block
.unsafeGetMetadata(
@ -1136,14 +1175,15 @@ class IrToTruffle(
)
val childScope = childFactory.scope
val blockNode = childFactory.processBlock(block.copy(suspended = false))
val blockNode =
childFactory.processBlock(moduleScope, block.copy(suspended = false))
val defaultRootNode = ClosureRootNode.build(
language,
childScope,
scopeBuilder.asModuleScope(),
moduleScope,
blockNode,
makeSection(scopeBuilder.getModule, block.location),
makeSection(module, block.location),
currentVarName,
false,
false
@ -1152,8 +1192,9 @@ class IrToTruffle(
val callTarget = defaultRootNode.getCallTarget
setLocation(CreateThunkNode.build(callTarget), block.location)
} else {
val statementExprs = block.expressions.map(this.run(_, true)).toArray
val retExpr = this.run(block.returnValue, true)
val statementExprs =
block.expressions.map(this.run(moduleScope, _, true)).toArray
val retExpr = this.run(moduleScope, block.returnValue, true)
val blockNode = BlockNode.build(statementExprs, retExpr)
setLocation(blockNode, block.location)
@ -1186,14 +1227,16 @@ class IrToTruffle(
* @return the truffle nodes corresponding to `caseExpr`
*/
def processCase(
moduleScope: ModuleScope,
caseExpr: Case,
subjectToInstrumentation: Boolean
): RuntimeExpression =
caseExpr match {
case Case.Expr(scrutinee, branches, isNested, location, _, _) =>
val scrutineeNode = this.run(scrutinee, subjectToInstrumentation)
val scrutineeNode =
this.run(moduleScope, scrutinee, subjectToInstrumentation)
val maybeCases = branches.map(processCaseBranch)
val maybeCases = branches.map(processCaseBranch(moduleScope, _))
val allCasesValid = maybeCases.forall(_.isRight)
if (allCasesValid) {
@ -1234,6 +1277,7 @@ class IrToTruffle(
* the match is invalid
*/
def processCaseBranch(
moduleScope: ModuleScope,
branch: Case.Branch
): Either[BadPatternMatch, BranchNode] = {
val scopeInfo = branch
@ -1255,6 +1299,7 @@ class IrToTruffle(
val arg = List(genArgFromMatchField(named))
val branchCodeNode = childProcessor.processFunctionBody(
moduleScope,
arg,
branch.expression,
branch.location
@ -1276,6 +1321,7 @@ class IrToTruffle(
val fieldsAsArgs = fieldNames.map(genArgFromMatchField)
val branchCodeNode = childProcessor.processFunctionBody(
moduleScope,
fieldsAsArgs,
branch.expression,
branch.location
@ -1421,6 +1467,7 @@ class IrToTruffle(
}
case literalPattern: Pattern.Literal =>
val branchCodeNode = childProcessor.processFunctionBody(
moduleScope,
Nil,
branch.expression,
branch.location
@ -1494,6 +1541,7 @@ class IrToTruffle(
)
val branchCodeNode = childProcessor.processFunctionBody(
moduleScope,
argOfType,
branch.expression,
branch.location
@ -1528,6 +1576,7 @@ class IrToTruffle(
)
val branchCodeNode = childProcessor.processFunctionBody(
moduleScope,
argOfType,
branch.expression,
branch.location
@ -1594,6 +1643,7 @@ class IrToTruffle(
* @return the truffle nodes corresponding to `binding`
*/
private def processBinding(
moduleScope: ModuleScope,
binding: Expression.Binding
): RuntimeExpression = {
val occInfo = binding
@ -1608,7 +1658,10 @@ class IrToTruffle(
val slotIdx = scope.getVarSlotIdx(occInfo.id)
setLocation(
AssignmentNode.build(this.run(binding.expression, true, true), slotIdx),
AssignmentNode.build(
this.run(moduleScope, binding.expression, true, true),
slotIdx
),
binding.location
)
}
@ -1620,6 +1673,7 @@ class IrToTruffle(
* @return the truffle nodes corresponding to `function`
*/
private def processFunction(
moduleScope: ModuleScope,
function: Function,
binding: Boolean
): RuntimeExpression = {
@ -1644,6 +1698,7 @@ class IrToTruffle(
this.createChild(scopeName, scopeInfo.scope, "case " + currentVarName)
val fn = child.processFunctionBody(
moduleScope,
function.arguments,
function.body,
function.location,
@ -1658,7 +1713,7 @@ class IrToTruffle(
* @param name the name to generate code for
* @return the truffle nodes corresponding to `name`
*/
def processName(name: Name): RuntimeExpression = {
def processName(moduleScope: ModuleScope, name: Name): RuntimeExpression = {
val nameExpr = name match {
case Name.Literal(nameStr, _, _, _, _, _) =>
val useInfo = name
@ -1677,11 +1732,11 @@ class IrToTruffle(
nodeForResolution(resolution)
} else if (nameStr == ConstantsNames.FROM_MEMBER) {
ConstantObjectNode.build(
UnresolvedConversion.build(scopeBuilder.asModuleScope())
UnresolvedConversion.build(moduleScope)
)
} else {
DynamicSymbolNode.build(
UnresolvedSymbol.build(nameStr, scopeBuilder.asModuleScope())
UnresolvedSymbol.build(nameStr, moduleScope)
)
}
case Name.MethodReference(
@ -1694,6 +1749,7 @@ class IrToTruffle(
DynamicSymbolNode.buildUnresolvedConstructor(nameStr)
case Name.Self(location, _, passData, _) =>
processName(
moduleScope,
Name.Literal(
ConstantsNames.SELF_ARGUMENT,
isMethod = false,
@ -1892,6 +1948,7 @@ class IrToTruffle(
* argument definitions.
*/
class BuildFunctionBody(
val moduleScope: ModuleScope,
val initialName: String,
val arguments: List[DefinitionArgument],
val body: Expression,
@ -1899,7 +1956,12 @@ class IrToTruffle(
val subjectToInstrumentation: Boolean
) {
private val argFactory =
new DefinitionArgumentProcessor(scopeName, scope, initialName)
new DefinitionArgumentProcessor(
moduleScope,
scopeName,
scope,
initialName
)
private lazy val slots = computeSlots()
lazy val argsExpr = computeArgsAndExpression()
@ -1921,7 +1983,12 @@ class IrToTruffle(
argSlotIdxs
)
case _ =>
ExpressionProcessor.this.run(body, false, subjectToInstrumentation)
ExpressionProcessor.this.run(
moduleScope,
body,
false,
subjectToInstrumentation
)
}
(argExpressions.toArray, bodyExpr)
}
@ -1938,7 +2005,8 @@ class IrToTruffle(
val argSlots = arguments.zipWithIndex.map {
case (unprocessedArg, idx) =>
val checkNode = checkAsTypes(unprocessedArg)
val arg = argFactory.run(unprocessedArg, idx, checkNode)
val arg =
argFactory.run(moduleScope, unprocessedArg, idx, checkNode)
argDefinitions(idx) = arg
val occInfo = unprocessedArg
.unsafeGetMetadata(
@ -2007,19 +2075,27 @@ class IrToTruffle(
* @return a truffle node representing the described function
*/
private def processFunctionBody(
moduleScope: ModuleScope,
arguments: List[DefinitionArgument],
body: Expression,
location: Option[IdentifiedLocation],
binding: Boolean = false
): CreateFunctionNode = {
val bodyBuilder =
new BuildFunctionBody(scopeName, arguments, body, None, false)
new BuildFunctionBody(
moduleScope,
scopeName,
arguments,
body,
None,
false
)
val fnRootNode = ClosureRootNode.build(
language,
scope,
scopeBuilder.asModuleScope(),
moduleScope,
bodyBuilder.bodyNode(),
makeSection(scopeBuilder.getModule, location),
makeSection(module, location),
scopeName,
false,
binding
@ -2061,21 +2137,25 @@ class IrToTruffle(
* @return the truffle nodes corresponding to `application`
*/
private def processApplication(
moduleScope: ModuleScope,
application: Application,
subjectToInstrumentation: Boolean
): RuntimeExpression =
application match {
case Application.Prefix(fn, Nil, true, _, _, _) =>
run(fn, subjectToInstrumentation)
run(moduleScope, fn, subjectToInstrumentation)
case app: Application.Prefix =>
processApplicationWithArgs(app, subjectToInstrumentation)
processApplicationWithArgs(moduleScope, app, subjectToInstrumentation)
case Application.Force(expr, location, _, _) =>
setLocation(
ForceNode.build(this.run(expr, subjectToInstrumentation)),
ForceNode.build(
this.run(moduleScope, expr, subjectToInstrumentation)
),
location
)
case Application.Sequence(items, location, _, _) =>
val itemNodes = items.map(run(_, subjectToInstrumentation)).toArray
val itemNodes =
items.map(run(moduleScope, _, subjectToInstrumentation)).toArray
setLocation(SequenceLiteralNode.build(itemNodes), location)
case _: Application.Typeset =>
setLocation(
@ -2102,13 +2182,14 @@ class IrToTruffle(
}
private def processApplicationWithArgs(
moduleScope: ModuleScope,
application: Application.Prefix,
subjectToInstrumentation: Boolean
): RuntimeExpression = {
val Application.Prefix(fn, args, hasDefaultsSuspended, loc, _, _) =
application
val callArgFactory =
new CallArgumentProcessor(scope, scopeName, currentVarName)
new CallArgumentProcessor(moduleScope, scope, scopeName, currentVarName)
val arguments = args
val callArgs = new ArrayBuffer[callable.argument.CallArgument]()
@ -2126,7 +2207,7 @@ class IrToTruffle(
}
val appNode = ApplicationNode.build(
this.run(fn, subjectToInstrumentation),
this.run(moduleScope, fn, subjectToInstrumentation),
callArgs.toArray,
defaultsExecutionMode
)
@ -2147,6 +2228,7 @@ class IrToTruffle(
* @param initialName suggested name for a first closure
*/
sealed private class CallArgumentProcessor(
val moduleScope: ModuleScope,
val scope: LocalScope,
val scopeName: String,
private val initialName: String
@ -2196,7 +2278,7 @@ class IrToTruffle(
}
val argumentExpression =
new ExpressionProcessor(childScope, scopeName, initialName)
.run(value, subjectToInstrumentation)
.run(moduleScope, value, subjectToInstrumentation)
val result = if (!shouldCreateClosureRootNode) {
argumentExpression
@ -2213,7 +2295,7 @@ class IrToTruffle(
val closureRootNode = ClosureRootNode.build(
language,
childScope,
scopeBuilder.asModuleScope(),
moduleScope,
argumentExpression,
section,
displayName,
@ -2254,6 +2336,7 @@ class IrToTruffle(
* @param initialName suggested name for a first closure
*/
sealed private class DefinitionArgumentProcessor(
private val moduleScope: ModuleScope,
val scopeName: String = "<root>",
val scope: LocalScope,
private val initialName: String
@ -2280,6 +2363,7 @@ class IrToTruffle(
* given function
*/
def run(
moduleScope: ModuleScope,
inputArg: DefinitionArgument,
position: Int,
types: ReadArgumentCheckNode
@ -2289,7 +2373,7 @@ class IrToTruffle(
val defaultExpression = arg.defaultValue
.map(
new ExpressionProcessor(scope, scopeName, initialName)
.run(_, false)
.run(moduleScope, _, false)
)
.orNull
@ -2299,10 +2383,10 @@ class IrToTruffle(
val defaultRootNode = ClosureRootNode.build(
language,
scope,
scopeBuilder.asModuleScope(),
moduleScope,
defaultExpression,
makeSection(
scopeBuilder.getModule,
module,
arg.defaultValue.get.location()
),
s"<default::$scopeName::${arg.name.showCode()}>",
@ -2354,5 +2438,5 @@ class IrToTruffle(
}
private def scopeAssociatedType =
scopeBuilder.asModuleScope().getAssociatedType
module.getScope.getAssociatedType
}

View File

@ -52,6 +52,7 @@ class RuntimeStubsGenerator(builtins: Builtins) {
if (tp.members.nonEmpty || tp.builtinType) {
Type.create(
tp.name,
builtins.getModule(),
scope,
builtins.any(),
builtins.any(),
@ -61,7 +62,7 @@ class RuntimeStubsGenerator(builtins: Builtins) {
} else {
Type.createSingleton(
tp.name,
scope,
builtins.getModule(),
builtins.any(),
false,
isTypeProjectPrivate