Avoiding dependency on EnsoContext from Module and ModuleScope (#7277)

Less dependencies on `EnsoContext` - `Module` shall exist without it. `Module` is a result of a `Compiler` and shall be created before its execution - e.g. requiring `EnsoContext` (with all its runtime information) is a bit too _demanding_.

# Important Notes
The only reason why `Module` wanted `EnsoContext` was to create its (associated) `Type`. `Type`'s constructor needed a parent type and the code was asking for `Any` from the context. That's unnecessary at creation time - we can just use some constant (like `null`) and turning it into `Any` during execution. Benchmarks show that there is no slowdown doing so.
This commit is contained in:
Jaroslav Tulach 2023-07-15 10:11:28 +01:00 committed by GitHub
parent aaa235fbad
commit 3d2c0c0154
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 54 additions and 35 deletions

View File

@ -173,15 +173,11 @@ public final class Module implements TruffleObject {
* belong to a package.
*/
private Module(
QualifiedName name,
Package<TruffleFile> pkg,
boolean synthetic,
Rope literalSource,
EnsoContext context) {
QualifiedName name, Package<TruffleFile> pkg, boolean synthetic, Rope literalSource) {
this.sources =
literalSource == null ? ModuleSources.NONE : ModuleSources.NONE.newWith(literalSource);
this.name = name;
this.scope = new ModuleScope(this, context);
this.scope = new ModuleScope(this);
this.pkg = pkg;
this.compilationStage = synthetic ? CompilationStage.INITIAL : CompilationStage.AFTER_CODEGEN;
this.cache = new ModuleCache(this);
@ -198,8 +194,8 @@ public final class Module implements TruffleObject {
* belong to a package.
* @return the module with empty scope.
*/
public static Module empty(QualifiedName name, Package<TruffleFile> pkg, EnsoContext context) {
return new Module(name, pkg, false, null, context);
public static Module empty(QualifiedName name, Package<TruffleFile> pkg) {
return new Module(name, pkg, false, null);
}
/**
@ -211,9 +207,8 @@ public final class Module implements TruffleObject {
* @param source source of the module declaring exports of the desired modules
* @return the synthetic module
*/
public static Module synthetic(
QualifiedName name, Package<TruffleFile> pkg, Rope source, EnsoContext context) {
return new Module(name, pkg, true, source, context);
public static Module synthetic(QualifiedName name, Package<TruffleFile> pkg, Rope source) {
return new Module(name, pkg, true, source);
}
/** Clears any literal source set for this module. */
@ -333,7 +328,7 @@ public final class Module implements TruffleObject {
* @return the scope defined by this module
*/
public ModuleScope compileScope(EnsoContext context) {
ensureScopeExists(context);
ensureScopeExists();
if (!compilationStage.isAtLeast(CompilationStage.AFTER_CODEGEN)) {
try {
compile(context);
@ -344,9 +339,9 @@ public final class Module implements TruffleObject {
}
/** Create scope if it does not exist. */
public void ensureScopeExists(EnsoContext context) {
public void ensureScopeExists() {
if (scope == null) {
scope = new ModuleScope(this, context);
scope = new ModuleScope(this);
compilationStage = CompilationStage.INITIAL;
}
}
@ -404,7 +399,7 @@ public final class Module implements TruffleObject {
}
private void compile(EnsoContext context) throws IOException {
ensureScopeExists(context);
ensureScopeExists();
Source source = getSource();
if (source == null) return;
scope.reset();

View File

@ -124,7 +124,7 @@ public final class Builtins {
*/
public Builtins(EnsoContext context) {
EnsoLanguage language = context.getLanguage();
module = Module.empty(QualifiedName.fromString(MODULE_NAME), null, null);
module = Module.empty(QualifiedName.fromString(MODULE_NAME), null);
scope = module.compileScope(context);
builtins = initializeBuiltinTypes(loadedBuiltinConstructors, language, scope);

View File

@ -118,6 +118,13 @@ public final class Type implements TruffleObject {
}
public Type getSupertype() {
if (supertype == null) {
if (builtin) {
return null;
}
var ctx = EnsoContext.get(null);
return ctx.getBuiltins().any();
}
return supertype;
}
@ -204,13 +211,13 @@ public final class Type implements TruffleObject {
if (isNothing(lib) || !hasMetaParents()) {
throw UnsupportedMessageException.create();
}
assert supertype != null;
return new Array(supertype);
assert getSupertype() != null;
return new Array(getSupertype());
}
@ExportMessage
boolean hasMetaParents() {
return supertype != null && supertype != this;
return getSupertype() != null && getSupertype() != this;
}
@ExportMessage

View File

@ -10,7 +10,6 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.Module;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.data.Type;
@ -32,9 +31,8 @@ public final class ModuleScope implements TruffleObject {
* Creates a new object of this class.
*
* @param module the module related to the newly created scope.
* @param context the current langauge context
*/
public ModuleScope(Module module, EnsoContext context) {
public ModuleScope(Module module) {
this.polyglotSymbols = new HashMap<>();
this.types = new HashMap<>();
this.methods = new HashMap<>();
@ -42,12 +40,7 @@ public final class ModuleScope implements TruffleObject {
this.imports = new HashSet<>();
this.exports = new HashSet<>();
this.module = module;
this.associatedType =
Type.createSingleton(
module.getName().item(),
this,
context == null ? null : context.getBuiltins().any(),
false);
this.associatedType = Type.createSingleton(module.getName().item(), this, null, false);
}
public ModuleScope(

View File

@ -136,7 +136,7 @@ public final class TopLevelScope implements TruffleObject {
private static Module createModule(TopLevelScope scope, Object[] arguments, EnsoContext context)
throws ArityException, UnsupportedTypeException {
String moduleName = Types.extractArguments(arguments, String.class);
return Module.empty(QualifiedName.simpleName(moduleName), null, context);
return Module.empty(QualifiedName.simpleName(moduleName), null);
}
@CompilerDirectives.TruffleBoundary

View File

@ -552,7 +552,7 @@ class Compiler(
"Parsing module [{0}].",
module.getName
)
module.ensureScopeExists(context)
module.ensureScopeExists()
module.getScope.reset()
if (irCachingEnabled && !module.isInteractive) {
@ -585,7 +585,7 @@ class Compiler(
"Loading module [{0}] from source.",
module.getName
)
module.ensureScopeExists(context)
module.ensureScopeExists()
module.getScope.reset()
val moduleContext = ModuleContext(

View File

@ -348,8 +348,7 @@ object PackageRepository {
Module.synthetic(
qName,
pkg,
Rope(source),
context
Rope(source)
),
modulesWithSources.map(_._1)
)

View File

@ -19,6 +19,7 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.AfterClass;
import static org.junit.Assert.assertNotEquals;
import org.junit.BeforeClass;
import org.junit.Test;
@ -153,6 +154,30 @@ public class MetaObjectTest extends TestBase {
}
}
@Test
public void errorsAreWeird() {
var g = ValuesGenerator.create(ctx, ValuesGenerator.Language.ENSO);
for (var v : g.errors()) {
Value vMeta = v.getMetaObject();
var isError = vMeta.equals(g.typeError());
var isPanic = vMeta.equals(g.typePanic());
assertTrue("either error or panic: " + v, isError || isPanic);
assertNotEquals("never both: " + v, isError, isPanic);
if (isError) {
assertFalse("No meta parents for errors: " + vMeta, vMeta.hasMetaParents());
} else {
assertTrue("There are meta parents for panics: " + vMeta, vMeta.hasMetaParents());
var arr = vMeta.getMetaParents();
for (long i = 0; i < arr.getArraySize(); i++) {
var p = arr.getArrayElement(i);
assertEquals(g.typeAny(), p);
}
}
}
}
private void checkAllTypesSatisfy(Check check) throws Exception {
var g = generator();
var expecting = new LinkedHashSet<Value>();

View File

@ -202,7 +202,7 @@ trait CompilerRunner {
isGeneratingDocs: Boolean = false
): ModuleContext = {
ModuleContext(
module = Module.empty(moduleName, null, null),
module = Module.empty(moduleName, null),
freshNameSupply = freshNameSupply,
passConfiguration = passConfiguration,
compilerConfig = compilerConfig,
@ -226,7 +226,7 @@ trait CompilerRunner {
passConfiguration: Option[PassConfiguration] = None,
compilerConfig: CompilerConfig = defaultConfig
): InlineContext = {
val mod = Module.empty(QualifiedName.simpleName("Test_Module"), null, null)
val mod = Module.empty(QualifiedName.simpleName("Test_Module"), null)
mod.unsafeSetIr(
IR.Module(List(), List(), List(), None)
.updateMetadata(