From 5853a1e6192d915b38ecf96e3e68066a763c8997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Mon, 28 Oct 2024 19:07:20 +0100 Subject: [PATCH] WIP replacing BindingsMap access and AtomTypeInterface with StaticModuleScope --- .../pass/analyse/types/BuiltinTypes.java | 2 +- .../analyse/types/MethodTypeResolver.java | 1 + .../pass/analyse/types/TypePropagation.java | 41 +++++++++++++++---- .../analyse/types/TypeRepresentation.java | 8 ++-- .../pass/analyse/types/TypeResolver.java | 2 +- .../pass/analyse/types/scope/AtomType.java | 8 +++- .../types/scope/StaticModuleScope.java | 4 ++ .../scope/StaticModuleScopeAnalysis.java | 27 ++++++++++-- .../org/enso/compiler/data/BindingsMap.scala | 18 +------- 9 files changed, 76 insertions(+), 35 deletions(-) diff --git a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/BuiltinTypes.java b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/BuiltinTypes.java index 5c9c00cc3b361..9890db723a3a0 100644 --- a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/BuiltinTypes.java +++ b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/BuiltinTypes.java @@ -20,7 +20,7 @@ private BuiltinTypes() {} private static TypeRepresentation fromQualifiedName(String qualifiedName) { var fqn = QualifiedName$.MODULE$.fromString(qualifiedName); - return new TypeRepresentation.AtomType(fqn, null); + return new TypeRepresentation.AtomType(fqn); } public static boolean isAny(QualifiedName qualifiedName) { diff --git a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/MethodTypeResolver.java b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/MethodTypeResolver.java index cc08cc227d4f1..9f7a28404b4f8 100644 --- a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/MethodTypeResolver.java +++ b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/MethodTypeResolver.java @@ -1,5 +1,6 @@ package org.enso.compiler.pass.analyse.types; +import org.enso.compiler.pass.analyse.types.scope.AtomType; import org.enso.compiler.pass.analyse.types.scope.BuiltinsFallbackScope; import org.enso.compiler.pass.analyse.types.scope.ModuleResolver; import org.enso.compiler.pass.analyse.types.scope.StaticMethodResolution; diff --git a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/TypePropagation.java b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/TypePropagation.java index 85318d2ec74fc..d431ab9caea72 100644 --- a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/TypePropagation.java +++ b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/TypePropagation.java @@ -21,9 +21,11 @@ import org.enso.compiler.pass.analyse.alias.AliasMetadata; import org.enso.compiler.pass.analyse.alias.graph.Graph; import org.enso.compiler.pass.analyse.alias.graph.GraphOccurrence; +import org.enso.compiler.pass.analyse.types.scope.AtomType; import org.enso.compiler.pass.analyse.types.scope.ModuleResolver; import org.enso.compiler.pass.analyse.types.scope.StaticModuleScope; import org.enso.compiler.pass.analyse.types.scope.TypeScopeReference; +import org.enso.pkg.QualifiedName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import scala.Option; @@ -41,6 +43,7 @@ abstract class TypePropagation { private static final Logger logger = LoggerFactory.getLogger(TypePropagation.class); private final TypeResolver typeResolver; private final TypeCompatibility compatibilityChecker; + private final ModuleResolver moduleResolver; private final MethodTypeResolver methodTypeResolver; TypePropagation( @@ -50,6 +53,7 @@ abstract class TypePropagation { ModuleResolver moduleResolver) { this.typeResolver = typeResolver; this.compatibilityChecker = compatibilityChecker; + this.moduleResolver = moduleResolver; var currentModuleScope = StaticModuleScope.forIR(currentModule); this.methodTypeResolver = new MethodTypeResolver(moduleResolver, currentModuleScope); @@ -81,6 +85,11 @@ protected abstract void encounteredInvocationOfNonFunctionType( protected abstract void encounteredNoSuchMethod( IR relatedIr, TypeRepresentation type, String methodName, MethodCallKind kind); + /** + * The callback that is called when a constructor is being invoked on a type that does not have such a constructor. + */ + protected abstract void encounteredNoSuchConstructor(IR relatedIr, TypeRepresentation type, String constructorName); + enum MethodCallKind { MEMBER, STATIC, @@ -323,6 +332,12 @@ private TypeRepresentation processSingleApplication( return null; } + private AtomType findTypeDefinition(QualifiedName name) { + var module = moduleResolver.findContainingModule(TypeScopeReference.atomType(name)); + var moduleScope = StaticModuleScope.forIR(module); + return moduleScope.getType(name.item()); + } + private TypeRepresentation processUnresolvedSymbolApplication( TypeRepresentation.UnresolvedSymbol function, Expression argument, @@ -336,14 +351,26 @@ private TypeRepresentation processUnresolvedSymbolApplication( switch (argumentType) { case TypeRepresentation.TypeObject typeObject -> { if (isConstructorOrType(function.name())) { - var ctorCandidate = - typeObject.typeInterface().constructors().stream() - .filter(ctor -> ctor.name().equals(function.name())) - .findFirst(); - if (ctorCandidate.isPresent()) { - return typeResolver.buildAtomConstructorType(typeObject, ctorCandidate.get()); + var typeDefinition = findTypeDefinition(typeObject.name()); + if (typeDefinition == null) { + logger.warn( + "processUnresolvedSymbolApplication: {} - no type definition found for {}", + relatedWholeApplicationIR.showCode(), + typeObject.name()); + return null; + } + + var constructor = typeDefinition.getConstructor(function.name()); + if (constructor != null) { + if (constructor.type() == null) { + // type is unknown due to default arguments + // TODO later on this should be assert != null because all constructors should have a type (once we can deal with default arguments) + return null; + } + + return constructor.type(); } else { - // TODO we could report that no valid constructor was found + encounteredNoSuchConstructor(relatedWholeApplicationIR, argumentType, function.name()); return null; } } else { diff --git a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/TypeRepresentation.java b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/TypeRepresentation.java index 26380dc3a9050..e4fe79ff62ce3 100644 --- a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/TypeRepresentation.java +++ b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/TypeRepresentation.java @@ -51,7 +51,7 @@ public QualifiedName getAssociatedType() { *

Instances that are assigned this type are built with one of the available constructors, but * statically we do not necessarily know which one. */ - record AtomType(QualifiedName fqn, AtomTypeInterface typeInterface) + record AtomType(QualifiedName fqn) implements TypeRepresentation { @Override public String toString() { @@ -157,10 +157,8 @@ public String toString() { * using its constructors, which will be assigned the corresponding AtomType. * * @param name the qualified name of the type - * @param typeInterface the declared interface of the type */ - record TypeObject(QualifiedName name, AtomTypeInterface typeInterface) - implements TypeRepresentation { + record TypeObject(QualifiedName name) implements TypeRepresentation { @Override public String toString() { return "(type " + name.item() + ")"; @@ -179,7 +177,7 @@ public TypeRepresentation instanceType() { return new ArrowType(TypeRepresentation.ANY, TypeRepresentation.ANY); } - return new AtomType(name, typeInterface); + return new AtomType(name); } @Override diff --git a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/TypeResolver.java b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/TypeResolver.java index d4dc858f9984e..bab17e22b4e45 100644 --- a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/TypeResolver.java +++ b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/TypeResolver.java @@ -129,7 +129,7 @@ TypeRepresentation resolvedTypeAsAtomType(BindingsMap.ResolvedType resolvedType) return resolvedTypeAsTypeObject(resolvedType).instanceType(); } - TypeRepresentation buildAtomConstructorType( + public TypeRepresentation buildAtomConstructorType( TypeRepresentation.TypeObject parentType, AtomTypeInterface.Constructor constructor) { boolean hasAnyDefaults = constructor.arguments().stream().anyMatch(AtomTypeInterface.Argument::hasDefaultValue); diff --git a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/scope/AtomType.java b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/scope/AtomType.java index 4437e3cb8ecd6..8e5b8c8df737a 100644 --- a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/scope/AtomType.java +++ b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/scope/AtomType.java @@ -6,17 +6,20 @@ public final class AtomType { private final String name; + private final List constructors; public AtomType(String name, List constructors) { this.name = name; + this.constructors = constructors; } public String getName() { return name; } - // TODO mark type in constructor only if no default arguments, treat same as function? - // TODO this should replace AtomTypeInterface + public Constructor getConstructor(String name) { + return constructors.stream().filter(c -> c.name().equals(name)).findFirst().orElse(null); + } /** * Represents a constructor of the atom type. @@ -24,6 +27,7 @@ public String getName() { * @param name the name of the constructor * @param isProjectPrivate whether the constructor is project private * @param type the type ascribed to the constructor, it may be null if it is unknown + * TODO the type will soon be always non-null - once we can handle default arguments */ public record Constructor(String name, boolean isProjectPrivate, TypeRepresentation type) {} } diff --git a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/scope/StaticModuleScope.java b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/scope/StaticModuleScope.java index 4d536f2d2e32a..c77e5aa3ce316 100644 --- a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/scope/StaticModuleScope.java +++ b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/scope/StaticModuleScope.java @@ -167,4 +167,8 @@ public TypeRepresentation getConversionFor(TypeScopeReference target, TypeScopeR // TODO conversions in static analysis return null; } + + public AtomType getType(String name) { + return typesDefinedHere.get(name); + } } diff --git a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/scope/StaticModuleScopeAnalysis.java b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/scope/StaticModuleScopeAnalysis.java index aa26cc8ba4a7f..0bf7e27855c55 100644 --- a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/scope/StaticModuleScopeAnalysis.java +++ b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/scope/StaticModuleScopeAnalysis.java @@ -139,9 +139,11 @@ protected void processTypeDefinition(Definition.Type typ) { List constructors = CollectionConverters$.MODULE$.asJava(typ.members()).stream() .map( - constructorDef -> - new AtomType.Constructor( - constructorDef.name().name(), constructorDef.isPrivate())) + constructorDef -> { + TypeRepresentation type = buildAtomConstructorType(constructorDef); + return new AtomType.Constructor( + constructorDef.name().name(), constructorDef.isPrivate(), type); + }) .toList(); AtomType atomType = new AtomType(typ.name().name(), constructors); @@ -151,6 +153,25 @@ protected void processTypeDefinition(Definition.Type typ) { registerFieldGetters(scopeBuilder, atomTypeScope, typ); } + private TypeRepresentation buildAtomConstructorType(Definition.Data constructorDef) { + boolean hasDefaults = constructorDef.arguments().exists(a -> a.defaultValue().isDefined()); + if (hasDefaults) { + // TODO implement handling of default arguments - not only ctors will need this! + return null; + } + + var arguments = + constructorDef.arguments().map( + (arg) -> { + var typ = arg.ascribedType(); + // TODO + return typ != null ? typ : TypeRepresentation.UNKNOWN; + }) + .toList(); + var resultType = parentType.instanceType(); + return TypeRepresentation.buildFunction(arguments, resultType); + } + @Override protected TypeScopeReference associatedTypeFromResolvedModule( BindingsMap.ResolvedModule module) { diff --git a/engine/runtime-compiler/src/main/scala/org/enso/compiler/data/BindingsMap.scala b/engine/runtime-compiler/src/main/scala/org/enso/compiler/data/BindingsMap.scala index 9c8753aad043e..078efbdae9685 100644 --- a/engine/runtime-compiler/src/main/scala/org/enso/compiler/data/BindingsMap.scala +++ b/engine/runtime-compiler/src/main/scala/org/enso/compiler/data/BindingsMap.scala @@ -595,15 +595,7 @@ object BindingsMap { def allFieldsDefaulted: Boolean = arguments.forall(_.hasDefaultValue) } - case class Argument( - name: String, - hasDefaultValue: Boolean, - typReference: Reference[Expression] - ) { - def typ(): Option[Expression] = Option( - typReference.get(classOf[Expression]) - ) - } + case class Argument(name: String, hasDefaultValue: Boolean) /** A representation of a sum type * @@ -629,15 +621,9 @@ object BindingsMap { Cons( m.name.name, m.arguments.map { arg => - val ascribedType: Reference[Expression] = - arg.ascribedType match { - case Some(value) => Reference.of(value, true) - case None => Reference.none() - } BindingsMap.Argument( arg.name.name, - arg.defaultValue.isDefined, - ascribedType + arg.defaultValue.isDefined ) }, m.isPrivate