mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 03:51:43 +03:00
Add Meta.get_annotation (#4049)
- add: `GeneralAnnotation` IR node for `@name expression` annotations - update: compilation pipeline to process the annotation expressions - update: rewrite `OverloadsResolution` compiler pass so that it keeps the order of module definitions - add: `Meta.get_annotation` builtin function that returns the result of annotation expression - misc: improvements (private methods, lazy arguments, build.sbt cleanup)
This commit is contained in:
parent
5b5a2be829
commit
bf9508603f
@ -525,6 +525,7 @@
|
||||
- [Introducing Meta.atom_with_hole][4023]
|
||||
- [Report failures in name resolution in type signatures][4030]
|
||||
- [Attach visualizations to sub-expressions][4048]
|
||||
- [Add Meta.get_annotation method][4049]
|
||||
- [Resolve Fully Qualified Names][4056]
|
||||
- [Optimize Atom storage layouts][3862]
|
||||
|
||||
@ -613,6 +614,7 @@
|
||||
[4023]: https://github.com/enso-org/enso/pull/4023
|
||||
[4030]: https://github.com/enso-org/enso/pull/4030
|
||||
[4048]: https://github.com/enso-org/enso/pull/4048
|
||||
[4056]: https://github.com/enso-org/enso/pull/4049
|
||||
[4056]: https://github.com/enso-org/enso/pull/4056
|
||||
|
||||
# Enso 2.0.0-alpha.18 (2021-10-12)
|
||||
|
@ -1146,9 +1146,6 @@ lazy val `polyglot-api` = project
|
||||
"org.scalacheck" %% "scalacheck" % scalacheckVersion % Test
|
||||
),
|
||||
libraryDependencies ++= jackson,
|
||||
addCompilerPlugin(
|
||||
"org.typelevel" %% "kind-projector" % kindProjectorVersion cross CrossVersion.full
|
||||
),
|
||||
GenerateFlatbuffers.flatcVersion := flatbuffersVersion,
|
||||
Compile / sourceGenerators += GenerateFlatbuffers.task
|
||||
)
|
||||
@ -1443,9 +1440,6 @@ lazy val runtime = (project in file("engine/runtime"))
|
||||
"-s",
|
||||
(Compile / sourceManaged).value.getAbsolutePath,
|
||||
"-Xlint:unchecked"
|
||||
),
|
||||
addCompilerPlugin(
|
||||
"org.typelevel" %% "kind-projector" % kindProjectorVersion cross CrossVersion.full
|
||||
)
|
||||
)
|
||||
.settings(
|
||||
|
@ -10,6 +10,7 @@ import project.Data.Time.Duration.Duration
|
||||
import project.Data.Time.Time_Of_Day.Time_Of_Day
|
||||
import project.Data.Time.Time_Zone.Time_Zone
|
||||
import project.Data.Vector.Vector
|
||||
import project.Nothing.Nothing
|
||||
import project.Polyglot.Java
|
||||
|
||||
import project.Error.Error as Base_Error
|
||||
@ -333,10 +334,22 @@ java_instance_check value typ =
|
||||
Returns the type of the given value.
|
||||
|
||||
Arguments:
|
||||
- value: the value to get the type of.
|
||||
- value: The value to get the type of.
|
||||
type_of : Any -> Any
|
||||
type_of value = @Builtin_Method "Meta.type_of"
|
||||
|
||||
## UNSTABLE
|
||||
ADVANCED
|
||||
|
||||
Given a type object, method name and a parameter name, return the associated annotation if it exists.
|
||||
|
||||
Arguments:
|
||||
- target: The value or type to get the attribute from.
|
||||
- method_name: The name of the method or constructor to get the attribute for.
|
||||
- parameter_name: The name of the parameter to get the attribute for.
|
||||
get_annotation : Any -> Text -> Text -> Any | Nothing
|
||||
get_annotation target method_name parameter_name = @Builtin_Method "Meta.get_annotation"
|
||||
|
||||
## Represents a polyglot language.
|
||||
type Language
|
||||
|
||||
|
@ -26,6 +26,11 @@ public final class EnsoCompiler implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
public IR.Module compile(CharSequence src) {
|
||||
var tree = parser.parse(src);
|
||||
return generateIR(tree);
|
||||
}
|
||||
|
||||
boolean isReady() {
|
||||
return parser != null;
|
||||
}
|
||||
|
@ -42,7 +42,8 @@ import org.enso.compiler.core.IR$Module$Scope$Import;
|
||||
import org.enso.compiler.core.IR$Module$Scope$Import$Module;
|
||||
import org.enso.compiler.core.IR$Module$Scope$Import$Polyglot;
|
||||
import org.enso.compiler.core.IR$Module$Scope$Import$Polyglot$Java;
|
||||
import org.enso.compiler.core.IR$Name$Annotation;
|
||||
import org.enso.compiler.core.IR$Name$BuiltinAnnotation;
|
||||
import org.enso.compiler.core.IR$Name$GenericAnnotation;
|
||||
import org.enso.compiler.core.IR$Name$Blank;
|
||||
import org.enso.compiler.core.IR$Name$Literal;
|
||||
import org.enso.compiler.core.IR$Name$Self;
|
||||
@ -222,6 +223,7 @@ final class TreeToIr {
|
||||
private List<IR$Module$Scope$Definition> translateModuleSymbolImpl(Tree inputAst, List<IR$Module$Scope$Definition> appendTo) throws SyntaxException {
|
||||
return switch (inputAst) {
|
||||
case null -> appendTo;
|
||||
|
||||
case Tree.TypeDef def -> {
|
||||
var typeName = buildName(def.getName(), true);
|
||||
List<IR> irBody = nil();
|
||||
@ -238,6 +240,7 @@ final class TreeToIr {
|
||||
);
|
||||
yield cons(type, appendTo);
|
||||
}
|
||||
|
||||
case Tree.Function fn -> {
|
||||
var methodRef = translateMethodReference(fn.getName(), false);
|
||||
var args = translateArgumentsDefinition(fn.getArgs());
|
||||
@ -256,6 +259,7 @@ final class TreeToIr {
|
||||
);
|
||||
yield cons(binding, appendTo);
|
||||
}
|
||||
|
||||
case Tree.ForeignFunction fn when fn.getBody() instanceof Tree.TextLiteral body -> {
|
||||
var name = fn.getName();
|
||||
var nameLoc = getIdentifiedLocation(name);
|
||||
@ -277,13 +281,21 @@ final class TreeToIr {
|
||||
}
|
||||
|
||||
case Tree.AnnotatedBuiltin anno -> {
|
||||
var annotation = new IR$Name$Annotation("@" + anno.getAnnotation().codeRepr(), getIdentifiedLocation(anno), meta(), diag());
|
||||
var annotation = new IR$Name$BuiltinAnnotation("@" + anno.getAnnotation().codeRepr(), getIdentifiedLocation(anno), meta(), diag());
|
||||
yield translateModuleSymbol(anno.getExpression(), cons(annotation, appendTo));
|
||||
}
|
||||
|
||||
case Tree.Annotated anno -> {
|
||||
var annotationArgument = translateExpression(anno.getArgument());
|
||||
var annotation = new IR$Name$GenericAnnotation(anno.getAnnotation().codeRepr(), annotationArgument, getIdentifiedLocation(anno), meta(), diag());
|
||||
yield translateModuleSymbol(anno.getExpression(), cons(annotation, appendTo));
|
||||
}
|
||||
|
||||
case Tree.Documented doc -> {
|
||||
var comment = translateComment(doc, doc.getDocumentation());
|
||||
yield translateModuleSymbol(doc.getExpression(), cons(comment, appendTo));
|
||||
}
|
||||
|
||||
case Tree.Assignment a -> {
|
||||
var reference = translateMethodReference(a.getPattern(), false);
|
||||
var body = translateExpression(a.getExpr());
|
||||
@ -307,6 +319,7 @@ final class TreeToIr {
|
||||
var ascription = new IR$Type$Ascription(methodReference, signature, getIdentifiedLocation(sig), meta(), diag());
|
||||
yield cons(ascription, appendTo);
|
||||
}
|
||||
|
||||
default -> {
|
||||
var error = translateSyntaxError(inputAst, IR$Error$Syntax$UnexpectedExpression$.MODULE$);
|
||||
yield cons(error, appendTo);
|
||||
@ -328,7 +341,7 @@ final class TreeToIr {
|
||||
var constructorName = buildName(inputAst, cons.getConstructor());
|
||||
List<IR.DefinitionArgument> args = translateArgumentsDefinition(cons.getArguments());
|
||||
var cAt = getIdentifiedLocation(inputAst);
|
||||
return new IR$Module$Scope$Definition$Data(constructorName, args, cAt, meta(), diag());
|
||||
return new IR$Module$Scope$Definition$Data(constructorName, args, nil(), cAt, meta(), diag());
|
||||
} catch (SyntaxException ex) {
|
||||
return ex.toError();
|
||||
}
|
||||
@ -353,12 +366,16 @@ final class TreeToIr {
|
||||
var inputAst = maybeManyParensed(exp);
|
||||
return switch (inputAst) {
|
||||
case null -> appendTo;
|
||||
|
||||
case Tree.ConstructorDefinition cons -> cons(translateConstructorDefinition(cons, inputAst), appendTo);
|
||||
|
||||
case Tree.TypeDef def -> {
|
||||
var ir = translateSyntaxError(def, IR$Error$Syntax$UnexpectedDeclarationInType$.MODULE$);
|
||||
yield cons(ir, appendTo);
|
||||
}
|
||||
|
||||
case Tree.ArgumentBlockApplication app -> appendTo;
|
||||
|
||||
case Tree.TypeSignature sig -> {
|
||||
var isMethod = false;
|
||||
if (sig.getVariable() instanceof Tree.Ident ident) {
|
||||
@ -368,6 +385,7 @@ final class TreeToIr {
|
||||
var ir = translateTypeSignature(sig, sig.getType(), typeName);
|
||||
yield cons(ir, appendTo);
|
||||
}
|
||||
|
||||
case Tree.Function fun -> {
|
||||
IR.Name name;
|
||||
if (fun.getName() instanceof Tree.Ident ident) {
|
||||
@ -379,6 +397,7 @@ final class TreeToIr {
|
||||
var ir = translateFunction(fun, name, fun.getArgs(), fun.getBody());
|
||||
yield cons(ir, appendTo);
|
||||
}
|
||||
|
||||
// In some cases this is a `Function` in IR, but an `Assignment` in Tree.
|
||||
// See: https://discord.com/channels/401396655599124480/1001476608957349917
|
||||
case Tree.Assignment assignment -> {
|
||||
@ -387,6 +406,7 @@ final class TreeToIr {
|
||||
var ir = translateFunction(assignment, name, args, assignment.getExpr());
|
||||
yield cons(ir, appendTo);
|
||||
}
|
||||
|
||||
case Tree.ForeignFunction fn when fn.getBody() instanceof Tree.TextLiteral body -> {
|
||||
var name = buildName(fn.getName());
|
||||
var args = translateArgumentsDefinition(fn.getArgs());
|
||||
@ -406,11 +426,19 @@ final class TreeToIr {
|
||||
var irDoc = translateComment(doc, doc.getDocumentation());
|
||||
yield translateTypeBodyExpression(doc.getExpression(), cons(irDoc, appendTo));
|
||||
}
|
||||
|
||||
case Tree.AnnotatedBuiltin anno -> {
|
||||
var ir = new IR$Name$Annotation("@" + anno.getAnnotation().codeRepr(), getIdentifiedLocation(anno), meta(), diag());
|
||||
var ir = new IR$Name$BuiltinAnnotation("@" + anno.getAnnotation().codeRepr(), getIdentifiedLocation(anno), meta(), diag());
|
||||
var annotation = translateAnnotation(ir, anno.getExpression(), nil());
|
||||
yield cons(annotation, appendTo);
|
||||
}
|
||||
|
||||
case Tree.Annotated anno -> {
|
||||
var annotationArgument = translateExpression(anno.getArgument());
|
||||
var annotation = new IR$Name$GenericAnnotation(anno.getAnnotation().codeRepr(), annotationArgument, getIdentifiedLocation(anno), meta(), diag());
|
||||
yield translateTypeBodyExpression(anno.getExpression(), cons(annotation, appendTo));
|
||||
}
|
||||
|
||||
default -> {
|
||||
var ir = translateSyntaxError(inputAst, IR$Error$Syntax$UnexpectedDeclarationInType$.MODULE$);
|
||||
yield cons(ir, appendTo);
|
||||
@ -937,7 +965,7 @@ final class TreeToIr {
|
||||
case Tree.TemplateFunction templ -> translateExpression(templ.getAst(), false);
|
||||
case Tree.Wildcard wild -> new IR$Name$Blank(getIdentifiedLocation(wild), meta(), diag());
|
||||
case Tree.AnnotatedBuiltin anno -> {
|
||||
var ir = new IR$Name$Annotation("@" + anno.getAnnotation().codeRepr(), getIdentifiedLocation(anno), meta(), diag());
|
||||
var ir = new IR$Name$BuiltinAnnotation("@" + anno.getAnnotation().codeRepr(), getIdentifiedLocation(anno), meta(), diag());
|
||||
yield translateAnnotation(ir, anno.getExpression(), nil());
|
||||
}
|
||||
// Documentation can be attached to an expression in a few cases, like if someone documents a line of an
|
||||
@ -1133,7 +1161,7 @@ final class TreeToIr {
|
||||
return new IR$Application$Prefix(pref.function(), withBlockArgs, pref.hasDefaultsSuspended(), pref.location(), meta(), diag());
|
||||
}
|
||||
|
||||
private IR$Application$Prefix translateAnnotation(IR$Name$Annotation ir, Tree expr, List<IR.CallArgument> callArgs) {
|
||||
private IR$Application$Prefix translateAnnotation(IR$Name$BuiltinAnnotation ir, Tree expr, List<IR.CallArgument> callArgs) {
|
||||
return switch (expr) {
|
||||
case Tree.App fn -> {
|
||||
var fnAsArg = translateCallArgument(fn.getArg());
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.enso.interpreter.node;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
|
||||
import com.oracle.truffle.api.dsl.ReportPolymorphism;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||
@ -26,7 +25,7 @@ public abstract class BaseNode extends Node {
|
||||
}
|
||||
}
|
||||
|
||||
private @CompilationFinal TailStatus tailStatus = TailStatus.NOT_TAIL;
|
||||
private @CompilerDirectives.CompilationFinal TailStatus tailStatus = TailStatus.NOT_TAIL;
|
||||
|
||||
/**
|
||||
* Sets the new tail position status for this node.
|
||||
|
@ -2,6 +2,7 @@ package org.enso.interpreter.node.expression.builtin.meta;
|
||||
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.callable.Annotation;
|
||||
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
|
||||
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
|
||||
import org.enso.interpreter.runtime.callable.atom.Atom;
|
||||
@ -9,7 +10,6 @@ import org.enso.interpreter.runtime.callable.atom.StructsLibrary;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
|
||||
import org.enso.interpreter.runtime.data.Array;
|
||||
import org.enso.interpreter.runtime.data.Vector;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
@ -19,12 +19,10 @@ import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||
import com.oracle.truffle.api.interop.TruffleObject;
|
||||
import com.oracle.truffle.api.interop.UnknownIdentifierException;
|
||||
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
||||
import com.oracle.truffle.api.library.ExportLibrary;
|
||||
import com.oracle.truffle.api.library.ExportMessage;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import com.oracle.truffle.api.nodes.RootNode;
|
||||
import com.oracle.truffle.api.profiles.ValueProfile;
|
||||
import org.enso.interpreter.node.callable.InvokeCallableNode;
|
||||
import org.enso.interpreter.runtime.state.State;
|
||||
|
||||
@ -96,7 +94,7 @@ public abstract class AtomWithAHoleNode extends Node {
|
||||
};
|
||||
}
|
||||
|
||||
@ExportMessage Object getMembers(boolean includeInternal) throws UnsupportedMessageException {
|
||||
@ExportMessage Object getMembers(boolean includeInternal) {
|
||||
return new Array("value", "fill");
|
||||
}
|
||||
|
||||
@ -118,7 +116,6 @@ public abstract class AtomWithAHoleNode extends Node {
|
||||
}
|
||||
static final class SwapAtomFieldNode extends RootNode {
|
||||
private final FunctionSchema schema;
|
||||
private final ValueProfile sameAtom = ValueProfile.createClassProfile();
|
||||
@CompilerDirectives.CompilationFinal
|
||||
private int lastIndex = -1;
|
||||
@Child private StructsLibrary structs = StructsLibrary.getFactory().createDispatched(10);
|
||||
@ -130,7 +127,7 @@ public abstract class AtomWithAHoleNode extends Node {
|
||||
new ArgumentDefinition(1, "value", ArgumentDefinition.ExecutionMode.EXECUTE)
|
||||
}, new boolean[]{
|
||||
true, false
|
||||
}, new CallArgumentInfo[0]);
|
||||
}, new CallArgumentInfo[0], new Annotation[0]);
|
||||
}
|
||||
|
||||
static SwapAtomFieldNode create() {
|
||||
|
@ -0,0 +1,76 @@
|
||||
package org.enso.interpreter.node.expression.builtin.meta;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.library.CachedLibrary;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.node.BaseNode;
|
||||
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
|
||||
import org.enso.interpreter.node.expression.builtin.text.util.ExpectStringNode;
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.callable.Annotation;
|
||||
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.data.Type;
|
||||
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||
import org.enso.interpreter.runtime.scope.ModuleScope;
|
||||
import org.enso.interpreter.runtime.state.State;
|
||||
|
||||
@BuiltinMethod(
|
||||
type = "Meta",
|
||||
name = "get_annotation",
|
||||
description = "Get annotation associated with an object",
|
||||
autoRegister = false)
|
||||
public abstract class GetAnnotationNode extends BaseNode {
|
||||
|
||||
abstract Object execute(
|
||||
VirtualFrame frame, State state, Object target, Object method, Object parameter);
|
||||
|
||||
@Specialization
|
||||
Object doExecute(
|
||||
VirtualFrame frame,
|
||||
State state,
|
||||
Object target,
|
||||
Object method,
|
||||
Object parameter,
|
||||
@CachedLibrary(limit = "3") TypesLibrary types,
|
||||
@Cached ThunkExecutorNode thunkExecutorNode,
|
||||
@Cached ExpectStringNode expectStringNode) {
|
||||
String methodName = expectStringNode.execute(method);
|
||||
Type targetType = types.getType(target);
|
||||
ModuleScope scope = targetType.getDefinitionScope();
|
||||
Function methodFunction = scope.lookupMethodDefinition(targetType, methodName);
|
||||
if (methodFunction != null) {
|
||||
String parameterName = expectStringNode.execute(parameter);
|
||||
Annotation annotation = methodFunction.getSchema().getAnnotation(parameterName);
|
||||
if (annotation != null) {
|
||||
Function thunk =
|
||||
Function.thunk(annotation.getExpression().getCallTarget(), frame.materialize());
|
||||
return thunkExecutorNode.executeThunk(thunk, state, getTailStatus());
|
||||
}
|
||||
}
|
||||
AtomConstructor constructor = getAtomConstructor(targetType, methodName);
|
||||
if (constructor != null) {
|
||||
Function constructorFunction = constructor.getConstructorFunction();
|
||||
String parameterName = expectStringNode.execute(parameter);
|
||||
Annotation annotation = constructorFunction.getSchema().getAnnotation(parameterName);
|
||||
if (annotation != null) {
|
||||
Function thunk =
|
||||
Function.thunk(annotation.getExpression().getCallTarget(), frame.materialize());
|
||||
return thunkExecutorNode.executeThunk(thunk, state, getTailStatus());
|
||||
}
|
||||
}
|
||||
return EnsoContext.get(this).getNothing();
|
||||
}
|
||||
|
||||
static GetAnnotationNode build() {
|
||||
return GetAnnotationNodeGen.create();
|
||||
}
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
private static AtomConstructor getAtomConstructor(Type type, String name) {
|
||||
return type.getConstructors().get(name);
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package org.enso.interpreter.runtime.callable;
|
||||
|
||||
import com.oracle.truffle.api.nodes.RootNode;
|
||||
|
||||
/** Annotation with callable expression. */
|
||||
public class Annotation {
|
||||
|
||||
private final RootNode expression;
|
||||
private final String name;
|
||||
|
||||
public Annotation(String name, RootNode expression) {
|
||||
this.name = name;
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
/** @return the annotation name. */
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/** @return the annotation expression. */
|
||||
public RootNode getExpression() {
|
||||
return expression;
|
||||
}
|
||||
}
|
@ -70,15 +70,15 @@ public final class CallArgumentInfo {
|
||||
* Represents a mapping between the defined arguments of a function and the call site arguments.
|
||||
*/
|
||||
public static class ArgumentMappingBuilder {
|
||||
private int[] appliedMapping;
|
||||
private int[] oversaturatedArgumentMapping;
|
||||
private boolean[] argumentShouldExecute;
|
||||
private ArgumentDefinition[] definitions;
|
||||
private CallArgumentInfo[] callArgs;
|
||||
private CallArgumentInfo[] existingOversaturatedArgs;
|
||||
private boolean[] argumentUsed;
|
||||
private boolean[] callSiteArgApplied;
|
||||
private FunctionSchema originalSchema;
|
||||
private final int[] appliedMapping;
|
||||
private final int[] oversaturatedArgumentMapping;
|
||||
private final boolean[] argumentShouldExecute;
|
||||
private final ArgumentDefinition[] definitions;
|
||||
private final CallArgumentInfo[] callArgs;
|
||||
private final CallArgumentInfo[] existingOversaturatedArgs;
|
||||
private final boolean[] argumentUsed;
|
||||
private final boolean[] callSiteArgApplied;
|
||||
private final FunctionSchema originalSchema;
|
||||
private int oversaturatedWritePosition = 0;
|
||||
|
||||
/**
|
||||
@ -220,7 +220,11 @@ public final class CallArgumentInfo {
|
||||
newOversaturatedArgInfo.length);
|
||||
|
||||
return new FunctionSchema(
|
||||
originalSchema.getCallerFrameAccess(), definitions, argumentUsed, oversaturatedArgInfo);
|
||||
originalSchema.getCallerFrameAccess(),
|
||||
definitions,
|
||||
argumentUsed,
|
||||
oversaturatedArgInfo,
|
||||
originalSchema.getAnnotations());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ import org.enso.interpreter.node.expression.atom.InstantiateNode;
|
||||
import org.enso.interpreter.node.expression.atom.QualifiedAccessorNode;
|
||||
import org.enso.interpreter.runtime.callable.atom.unboxing.Layout;
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.callable.Annotation;
|
||||
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
|
||||
@ -50,7 +51,7 @@ public final class AtomConstructor implements TruffleObject {
|
||||
|
||||
/**
|
||||
* Creates a new Atom constructor for a given name. The constructor is not valid until {@link
|
||||
* AtomConstructor#initializeFields(LocalScope, ExpressionNode[], ExpressionNode[],
|
||||
* AtomConstructor#initializeFields(LocalScope, ExpressionNode[], ExpressionNode[], Annotation[],
|
||||
* ArgumentDefinition...)} is called.
|
||||
*
|
||||
* @param name the name of the Atom constructor
|
||||
@ -62,7 +63,7 @@ public final class AtomConstructor implements TruffleObject {
|
||||
|
||||
/**
|
||||
* Creates a new Atom constructor for a given name. The constructor is not valid until {@link
|
||||
* AtomConstructor#initializeFields(LocalScope, ExpressionNode[], ExpressionNode[],
|
||||
* AtomConstructor#initializeFields(LocalScope, ExpressionNode[], ExpressionNode[], Annotation[],
|
||||
* ArgumentDefinition...)} is called.
|
||||
*
|
||||
* @param name the name of the Atom constructor
|
||||
@ -95,7 +96,8 @@ public final class AtomConstructor implements TruffleObject {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
reads[i] = ReadArgumentNode.build(i, null);
|
||||
}
|
||||
return initializeFields(LocalScope.root(), new ExpressionNode[0], reads, args);
|
||||
return initializeFields(
|
||||
LocalScope.root(), new ExpressionNode[0], reads, new Annotation[0], args);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -111,6 +113,7 @@ public final class AtomConstructor implements TruffleObject {
|
||||
LocalScope localScope,
|
||||
ExpressionNode[] assignments,
|
||||
ExpressionNode[] varReads,
|
||||
Annotation[] annotations,
|
||||
ArgumentDefinition... args) {
|
||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||
|
||||
@ -122,7 +125,8 @@ public final class AtomConstructor implements TruffleObject {
|
||||
if (Layout.isAritySupported(args.length)) {
|
||||
boxedLayout = Layout.create(args.length, 0);
|
||||
}
|
||||
this.constructorFunction = buildConstructorFunction(localScope, assignments, varReads, args);
|
||||
this.constructorFunction =
|
||||
buildConstructorFunction(localScope, assignments, varReads, annotations, args);
|
||||
generateQualifiedAccessor();
|
||||
return this;
|
||||
}
|
||||
@ -144,6 +148,7 @@ public final class AtomConstructor implements TruffleObject {
|
||||
LocalScope localScope,
|
||||
ExpressionNode[] assignments,
|
||||
ExpressionNode[] varReads,
|
||||
Annotation[] annotations,
|
||||
ArgumentDefinition[] args) {
|
||||
|
||||
ExpressionNode instantiateNode = InstantiateNode.build(this, varReads);
|
||||
@ -159,7 +164,7 @@ public final class AtomConstructor implements TruffleObject {
|
||||
null,
|
||||
false);
|
||||
RootCallTarget callTarget = rootNode.getCallTarget();
|
||||
return new Function(callTarget, null, new FunctionSchema(args));
|
||||
return new Function(callTarget, null, new FunctionSchema(annotations, args));
|
||||
}
|
||||
|
||||
private void generateQualifiedAccessor() {
|
||||
|
@ -16,6 +16,7 @@ import org.enso.interpreter.node.callable.InteropApplicationNode;
|
||||
import org.enso.interpreter.node.callable.dispatch.InvokeFunctionNode;
|
||||
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.callable.Annotation;
|
||||
import org.enso.interpreter.runtime.callable.CallerInfo;
|
||||
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
|
||||
import org.enso.interpreter.runtime.data.Array;
|
||||
@ -102,7 +103,8 @@ public final class Function implements TruffleObject {
|
||||
public static Function fromBuiltinRootNodeWithCallerFrameAccess(
|
||||
BuiltinRootNode node, ArgumentDefinition... args) {
|
||||
RootCallTarget callTarget = node.getCallTarget();
|
||||
FunctionSchema schema = new FunctionSchema(FunctionSchema.CallerFrameAccess.FULL, args);
|
||||
FunctionSchema schema =
|
||||
new FunctionSchema(FunctionSchema.CallerFrameAccess.FULL, new Annotation[0], args);
|
||||
return new Function(callTarget, null, schema);
|
||||
}
|
||||
|
||||
|
@ -3,9 +3,12 @@ package org.enso.interpreter.runtime.callable.function;
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
|
||||
import org.enso.interpreter.node.callable.InvokeCallableNode;
|
||||
import org.enso.interpreter.runtime.callable.Annotation;
|
||||
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
|
||||
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Holds the definition site argument information together with information on the partially applied
|
||||
* arguments positions.
|
||||
@ -34,32 +37,35 @@ public final class FunctionSchema {
|
||||
private final @CompilationFinal(dimensions = 1) ArgumentDefinition[] argumentInfos;
|
||||
private final @CompilationFinal(dimensions = 1) boolean[] hasPreApplied;
|
||||
private final @CompilationFinal(dimensions = 1) CallArgumentInfo[] oversaturatedArguments;
|
||||
private final @CompilationFinal(dimensions = 1) Annotation[] annotations;
|
||||
private final boolean hasAnyPreApplied;
|
||||
private final boolean hasOversaturatedArguments;
|
||||
private final CallerFrameAccess callerFrameAccess;
|
||||
|
||||
private final boolean isFullyApplied;
|
||||
|
||||
/**
|
||||
* Creates an {@link FunctionSchema} instance.
|
||||
*
|
||||
* @param callerFrameAccess the declaration of whether access to caller frame is required for this
|
||||
* function
|
||||
* @param argumentInfos Definition site arguments information
|
||||
* function.
|
||||
* @param argumentInfos Definition site arguments information.
|
||||
* @param hasPreApplied A flags collection such that {@code hasPreApplied[i]} is true iff a
|
||||
* function has a partially applied argument at position {@code i}
|
||||
* function has a partially applied argument at position {@code i}.
|
||||
* @param oversaturatedArguments information about any unused, oversaturated arguments passed to
|
||||
* this function so far
|
||||
* this function so far.
|
||||
* @param annotations the list of annotations defined on this function.
|
||||
*/
|
||||
public FunctionSchema(
|
||||
CallerFrameAccess callerFrameAccess,
|
||||
ArgumentDefinition[] argumentInfos,
|
||||
boolean[] hasPreApplied,
|
||||
CallArgumentInfo[] oversaturatedArguments) {
|
||||
CallArgumentInfo[] oversaturatedArguments,
|
||||
Annotation[] annotations) {
|
||||
this.argumentInfos = argumentInfos;
|
||||
this.oversaturatedArguments = oversaturatedArguments;
|
||||
this.hasPreApplied = hasPreApplied;
|
||||
this.callerFrameAccess = callerFrameAccess;
|
||||
this.annotations = annotations;
|
||||
boolean hasAnyPreApplied = false;
|
||||
for (boolean b : hasPreApplied) {
|
||||
if (b) {
|
||||
@ -77,15 +83,20 @@ public final class FunctionSchema {
|
||||
* Creates an {@link FunctionSchema} instance assuming the function has no partially applied
|
||||
* arguments.
|
||||
*
|
||||
* @param callerFrameAccess the declaration of need to access the caller frame from the function
|
||||
* @param argumentInfos Definition site arguments information
|
||||
* @param callerFrameAccess the declaration of need to access the caller frame from the function.
|
||||
* @param argumentInfos Definition site arguments information.
|
||||
* @param annotations the list of annotations defined on this function.
|
||||
*/
|
||||
public FunctionSchema(CallerFrameAccess callerFrameAccess, ArgumentDefinition... argumentInfos) {
|
||||
public FunctionSchema(
|
||||
CallerFrameAccess callerFrameAccess,
|
||||
Annotation[] annotations,
|
||||
ArgumentDefinition... argumentInfos) {
|
||||
this(
|
||||
callerFrameAccess,
|
||||
argumentInfos,
|
||||
new boolean[argumentInfos.length],
|
||||
new CallArgumentInfo[0]);
|
||||
new CallArgumentInfo[0],
|
||||
annotations);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -94,10 +105,23 @@ public final class FunctionSchema {
|
||||
*
|
||||
* <p>Caller frame access is assumed to be {@link CallerFrameAccess#NONE}.
|
||||
*
|
||||
* @param annotations the list of annotations defined on this function.
|
||||
* @param argumentInfos Definition site arguments information.
|
||||
*/
|
||||
public FunctionSchema(Annotation[] annotations, ArgumentDefinition... argumentInfos) {
|
||||
this(CallerFrameAccess.NONE, annotations, argumentInfos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link FunctionSchema} instance assuming the function has no annotations or
|
||||
* partially applied arguments.
|
||||
*
|
||||
* <p>Caller frame access is assumed to be {@link CallerFrameAccess#NONE}.
|
||||
*
|
||||
* @param argumentInfos Definition site arguments information
|
||||
*/
|
||||
public FunctionSchema(ArgumentDefinition... argumentInfos) {
|
||||
this(CallerFrameAccess.NONE, argumentInfos);
|
||||
this(CallerFrameAccess.NONE, new Annotation[0], argumentInfos);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -196,6 +220,25 @@ public final class FunctionSchema {
|
||||
return callerFrameAccess;
|
||||
}
|
||||
|
||||
/** @return annotations defined on this function. */
|
||||
public Annotation[] getAnnotations() {
|
||||
return annotations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds annotation by name.
|
||||
*
|
||||
* @param name the annotation name.
|
||||
* @return the matching annotation expression.
|
||||
*/
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
public Annotation getAnnotation(String name) {
|
||||
return Arrays.stream(annotations)
|
||||
.filter(annotation -> annotation.getName().equals(name))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the function is already fully applied.
|
||||
*
|
||||
|
@ -85,7 +85,8 @@ class Passes(
|
||||
AliasAnalysis,
|
||||
DataflowAnalysis,
|
||||
CachePreferenceAnalysis,
|
||||
UnusedBindings
|
||||
UnusedBindings,
|
||||
GenericAnnotations
|
||||
)
|
||||
)
|
||||
|
||||
@ -96,7 +97,11 @@ class Passes(
|
||||
* these dependencies.
|
||||
*/
|
||||
val passOrdering: List[PassGroup] = passes.getOrElse(
|
||||
List(moduleDiscoveryPasses, globalTypingPasses, functionBodyPasses)
|
||||
List(
|
||||
moduleDiscoveryPasses,
|
||||
globalTypingPasses,
|
||||
functionBodyPasses
|
||||
)
|
||||
)
|
||||
|
||||
/** The ordered representation of all passes run by the compiler. */
|
||||
|
@ -135,7 +135,10 @@ object AstToIr {
|
||||
def translateModuleSymbol(inputAst: AST): Module.Scope.Definition = {
|
||||
inputAst match {
|
||||
case AST.Ident.Annotation.any(annotation) =>
|
||||
IR.Name.Annotation(annotation.name, getIdentifiedLocation(annotation))
|
||||
IR.Name.BuiltinAnnotation(
|
||||
annotation.name,
|
||||
getIdentifiedLocation(annotation)
|
||||
)
|
||||
case AstView.Atom(consName, args) =>
|
||||
val newArgs = args.map(translateArgumentDefinition(_))
|
||||
|
||||
@ -306,16 +309,22 @@ object AstToIr {
|
||||
inputAst match {
|
||||
case AST.Ident.Cons.any(cons) =>
|
||||
IR.Module.Scope.Definition
|
||||
.Data(buildName(cons), List(), getIdentifiedLocation(inputAst))
|
||||
.Data(
|
||||
buildName(cons),
|
||||
List(),
|
||||
List(),
|
||||
getIdentifiedLocation(inputAst)
|
||||
)
|
||||
case AstView.SpacedList(AST.Ident.Cons.any(cons) :: args) =>
|
||||
IR.Module.Scope.Definition
|
||||
.Data(
|
||||
buildName(cons),
|
||||
args.map(translateArgumentDefinition(_)),
|
||||
List(),
|
||||
getIdentifiedLocation(inputAst)
|
||||
)
|
||||
case AST.Ident.Annotation.any(ann) =>
|
||||
IR.Name.Annotation(ann.name, getIdentifiedLocation(ann))
|
||||
IR.Name.BuiltinAnnotation(ann.name, getIdentifiedLocation(ann))
|
||||
case AstView.FunctionSugar(
|
||||
AST.Ident.Var("foreign"),
|
||||
header,
|
||||
@ -1040,7 +1049,7 @@ object AstToIr {
|
||||
buildName(identifier)
|
||||
}
|
||||
case AST.Ident.Annotation(name) =>
|
||||
Name.Annotation(name, getIdentifiedLocation(identifier))
|
||||
Name.BuiltinAnnotation(name, getIdentifiedLocation(identifier))
|
||||
case AST.Ident.Cons(name) =>
|
||||
if (name == Constants.Names.SELF_TYPE_ARGUMENT) {
|
||||
Name.SelfType(getIdentifiedLocation(identifier))
|
||||
|
@ -23,6 +23,7 @@ import org.enso.compiler.pass.analyse.{
|
||||
import org.enso.compiler.pass.optimise.ApplicationSaturation
|
||||
import org.enso.compiler.pass.resolve.{
|
||||
ExpressionAnnotations,
|
||||
GenericAnnotations,
|
||||
GlobalNames,
|
||||
MethodDefinitions,
|
||||
Patterns,
|
||||
@ -67,6 +68,7 @@ import org.enso.interpreter.runtime.callable.function.{
|
||||
Function => RuntimeFunction
|
||||
}
|
||||
import org.enso.interpreter.runtime.callable.{
|
||||
Annotation => RuntimeAnnotation,
|
||||
UnresolvedConversion,
|
||||
UnresolvedSymbol
|
||||
}
|
||||
@ -80,6 +82,7 @@ import org.enso.interpreter.runtime.scope.{
|
||||
import org.enso.interpreter.{Constants, EnsoLanguage}
|
||||
|
||||
import java.math.BigInteger
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.collection.mutable
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
@ -87,8 +90,7 @@ import scala.jdk.OptionConverters._
|
||||
import scala.jdk.CollectionConverters._
|
||||
|
||||
/** This is an implementation of a codegeneration pass that lowers the Enso
|
||||
* [[IR]] into the truffle [[org.enso.compiler.core.Core.Node]] structures that
|
||||
* are actually executed.
|
||||
* [[IR]] into the truffle structures that are actually executed.
|
||||
*
|
||||
* It should be noted that, as is, there is no support for cross-module links,
|
||||
* with each lowering pass operating solely on a single module.
|
||||
@ -258,11 +260,42 @@ class IrToTruffle(
|
||||
}
|
||||
|
||||
val (assignments, reads) = argumentExpressions.unzip
|
||||
// build annotations
|
||||
val annotations = atomDefn.annotations.map { annotation =>
|
||||
val scopeElements = Seq(
|
||||
tpDef.name.name,
|
||||
atomDefn.name.name,
|
||||
annotation.name
|
||||
)
|
||||
val scopeName =
|
||||
scopeElements.mkString(Constants.SCOPE_SEPARATOR)
|
||||
val expressionProcessor = new ExpressionProcessor(
|
||||
scopeName,
|
||||
scopeInfo.graph,
|
||||
scopeInfo.graph.rootScope,
|
||||
dataflowInfo
|
||||
)
|
||||
val expressionNode =
|
||||
expressionProcessor.run(annotation.expression)
|
||||
val closureName = s"<default::$scopeName>"
|
||||
val closureRootNode = ClosureRootNode.build(
|
||||
language,
|
||||
expressionProcessor.scope,
|
||||
moduleScope,
|
||||
expressionNode,
|
||||
makeSection(moduleScope, annotation.location),
|
||||
closureName,
|
||||
true,
|
||||
false
|
||||
)
|
||||
new RuntimeAnnotation(annotation.name, closureRootNode)
|
||||
}
|
||||
if (!atomCons.isInitialized) {
|
||||
atomCons.initializeFields(
|
||||
localScope,
|
||||
assignments.toArray,
|
||||
reads.toArray,
|
||||
annotations.toArray,
|
||||
argDefs: _*
|
||||
)
|
||||
}
|
||||
@ -384,7 +417,7 @@ class IrToTruffle(
|
||||
.map(fOpt =>
|
||||
// Register builtin iff it has not been automatically registered at an early stage
|
||||
// of builtins initialization.
|
||||
fOpt.filter(m => !m.isAutoRegister()).map(m => m.getFunction)
|
||||
fOpt.filter(m => !m.isAutoRegister).map(m => m.getFunction)
|
||||
)
|
||||
case fn: IR.Function =>
|
||||
val bodyBuilder =
|
||||
@ -405,12 +438,63 @@ class IrToTruffle(
|
||||
)
|
||||
val callTarget = rootNode.getCallTarget
|
||||
val arguments = bodyBuilder.args()
|
||||
// build annotations
|
||||
val annotations =
|
||||
methodDef.getMetadata(GenericAnnotations).toVector.flatMap {
|
||||
meta =>
|
||||
meta.annotations
|
||||
.collect { case annotation: IR.Name.GenericAnnotation =>
|
||||
val scopeElements = Seq(
|
||||
cons.getName,
|
||||
methodDef.methodName.name,
|
||||
annotation.name
|
||||
)
|
||||
val scopeName =
|
||||
scopeElements.mkString(Constants.SCOPE_SEPARATOR)
|
||||
val scopeInfo = annotation
|
||||
.unsafeGetMetadata(
|
||||
AliasAnalysis,
|
||||
s"Missing scope information for annotation " +
|
||||
s"${annotation.name} of method " +
|
||||
scopeElements.init.mkString(Constants.SCOPE_SEPARATOR)
|
||||
)
|
||||
.unsafeAs[AliasAnalysis.Info.Scope.Root]
|
||||
val dataflowInfo = annotation.unsafeGetMetadata(
|
||||
DataflowAnalysis,
|
||||
"Missing dataflow information for annotation " +
|
||||
s"${annotation.name} of method " +
|
||||
scopeElements.init.mkString(Constants.SCOPE_SEPARATOR)
|
||||
)
|
||||
val expressionProcessor = new ExpressionProcessor(
|
||||
scopeName,
|
||||
scopeInfo.graph,
|
||||
scopeInfo.graph.rootScope,
|
||||
dataflowInfo
|
||||
)
|
||||
val expressionNode =
|
||||
expressionProcessor.run(annotation.expression)
|
||||
val closureName =
|
||||
s"<default::${expressionProcessor.scopeName}>"
|
||||
val closureRootNode = ClosureRootNode.build(
|
||||
language,
|
||||
expressionProcessor.scope,
|
||||
moduleScope,
|
||||
expressionNode,
|
||||
makeSection(moduleScope, annotation.location),
|
||||
closureName,
|
||||
true,
|
||||
false
|
||||
)
|
||||
new RuntimeAnnotation(annotation.name, closureRootNode)
|
||||
}
|
||||
}
|
||||
|
||||
Right(
|
||||
Some(
|
||||
new RuntimeFunction(
|
||||
callTarget,
|
||||
null,
|
||||
new FunctionSchema(arguments: _*)
|
||||
new FunctionSchema(annotations.toArray, arguments: _*)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -1655,7 +1739,7 @@ class IrToTruffle(
|
||||
* @param application the function application to generate code for
|
||||
* @return the truffle nodes corresponding to `application`
|
||||
*/
|
||||
def processApplication(
|
||||
private def processApplication(
|
||||
application: IR.Application,
|
||||
subjectToInstrumentation: Boolean
|
||||
): RuntimeExpression =
|
||||
|
@ -21,7 +21,6 @@ class FreshNameSupply {
|
||||
|
||||
/** Generates a name guaranteed not to exist in this program.
|
||||
*
|
||||
* @param isReferent whether or not the name should be marked as referent.
|
||||
* @param isMethod whether or not the name should represent a method name.
|
||||
* @return a new name
|
||||
*/
|
||||
|
@ -75,6 +75,7 @@ final class SuggestionBuilder[A: IndexedSource](
|
||||
arguments,
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
_
|
||||
) =>
|
||||
buildAtomConstructor(
|
||||
|
@ -11,6 +11,7 @@ import org.enso.interpreter.epb.EpbParser
|
||||
import org.enso.syntax.text.{AST, Debug, Location}
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** [[IR]] is a temporary and fairly unsophisticated internal representation
|
||||
@ -1068,6 +1069,7 @@ object IR {
|
||||
*
|
||||
* @param name the name of the atom
|
||||
* @param arguments the arguments to the atom constructor
|
||||
* @param annotations the list of annotations
|
||||
* @param location the source location that the node corresponds to
|
||||
* @param passData the pass metadata associated with this node
|
||||
* @param diagnostics compiler diagnostics for this node
|
||||
@ -1075,6 +1077,7 @@ object IR {
|
||||
sealed case class Data(
|
||||
name: IR.Name,
|
||||
arguments: List[DefinitionArgument],
|
||||
annotations: List[IR.Name.GenericAnnotation],
|
||||
override val location: Option[IdentifiedLocation],
|
||||
override val passData: MetadataStorage = MetadataStorage(),
|
||||
override val diagnostics: DiagnosticStorage = DiagnosticStorage()
|
||||
@ -1086,6 +1089,7 @@ object IR {
|
||||
*
|
||||
* @param name the name of the atom
|
||||
* @param arguments the arguments to the atom constructor
|
||||
* @param annotations the list of annotations
|
||||
* @param location the source location that the node corresponds to
|
||||
* @param passData the pass metadata associated with this node
|
||||
* @param diagnostics compiler diagnostics for this node
|
||||
@ -1093,14 +1097,22 @@ object IR {
|
||||
* @return a copy of `this`, updated with the specified values
|
||||
*/
|
||||
def copy(
|
||||
name: IR.Name = name,
|
||||
arguments: List[DefinitionArgument] = arguments,
|
||||
location: Option[IdentifiedLocation] = location,
|
||||
passData: MetadataStorage = passData,
|
||||
diagnostics: DiagnosticStorage = diagnostics,
|
||||
id: Identifier = id
|
||||
name: IR.Name = name,
|
||||
arguments: List[DefinitionArgument] = arguments,
|
||||
annotations: List[IR.Name.GenericAnnotation] = annotations,
|
||||
location: Option[IdentifiedLocation] = location,
|
||||
passData: MetadataStorage = passData,
|
||||
diagnostics: DiagnosticStorage = diagnostics,
|
||||
id: Identifier = id
|
||||
): Data = {
|
||||
val res = Data(name, arguments, location, passData, diagnostics)
|
||||
val res = Data(
|
||||
name,
|
||||
arguments,
|
||||
annotations,
|
||||
location,
|
||||
passData,
|
||||
diagnostics
|
||||
)
|
||||
res.id = id
|
||||
res
|
||||
}
|
||||
@ -1142,17 +1154,19 @@ object IR {
|
||||
/** @inheritdoc */
|
||||
override def mapExpressions(fn: Expression => Expression): Data = {
|
||||
copy(
|
||||
name = name.mapExpressions(fn),
|
||||
arguments = arguments.map(_.mapExpressions(fn))
|
||||
name = name.mapExpressions(fn),
|
||||
arguments = arguments.map(_.mapExpressions(fn)),
|
||||
annotations = annotations.map(_.mapExpressions(fn))
|
||||
)
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
override def toString: String =
|
||||
s"""
|
||||
|IR.Module.Scope.Definition.Atom(
|
||||
|IR.Module.Scope.Definition.Data(
|
||||
|name = $name,
|
||||
|arguments = $arguments,
|
||||
|annotations = $annotations,
|
||||
|location = $location,
|
||||
|passData = ${this.showPassData},
|
||||
|diagnostics = $diagnostics,
|
||||
@ -1161,7 +1175,7 @@ object IR {
|
||||
|""".toSingleLine
|
||||
|
||||
/** @inheritdoc */
|
||||
override def children: List[IR] = name :: arguments
|
||||
override def children: List[IR] = name :: arguments ::: annotations
|
||||
|
||||
/** @inheritdoc */
|
||||
override def showCode(indent: Int): String = {
|
||||
@ -2754,20 +2768,37 @@ object IR {
|
||||
override def showCode(indent: Int): String = name
|
||||
}
|
||||
|
||||
/** The representation of an annotation name.
|
||||
/** Base trait for annotations. */
|
||||
sealed trait Annotation extends Name with IR.Module.Scope.Definition {
|
||||
|
||||
/** @inheritdoc */
|
||||
override def mapExpressions(fn: Expression => Expression): Annotation
|
||||
|
||||
/** @inheritdoc */
|
||||
override def setLocation(location: Option[IdentifiedLocation]): Annotation
|
||||
|
||||
/** @inheritdoc */
|
||||
override def duplicate(
|
||||
keepLocations: Boolean = true,
|
||||
keepMetadata: Boolean = true,
|
||||
keepDiagnostics: Boolean = true,
|
||||
keepIdentifiers: Boolean = false
|
||||
): Annotation
|
||||
}
|
||||
|
||||
/** The representation of builtin annotation.
|
||||
*
|
||||
* @param name the annotation text of the name
|
||||
* @param location the source location that the node corresponds to
|
||||
* @param passData the pass metadata associated with this node
|
||||
* @param diagnostics compiler diagnostics for this node
|
||||
*/
|
||||
sealed case class Annotation(
|
||||
sealed case class BuiltinAnnotation(
|
||||
override val name: String,
|
||||
override val location: Option[IdentifiedLocation],
|
||||
override val passData: MetadataStorage = MetadataStorage(),
|
||||
override val diagnostics: DiagnosticStorage = DiagnosticStorage()
|
||||
) extends Name
|
||||
with IR.Module.Scope.Definition
|
||||
) extends Annotation
|
||||
with IRKind.Primitive {
|
||||
override protected var id: Identifier = randomId
|
||||
|
||||
@ -2786,8 +2817,8 @@ object IR {
|
||||
passData: MetadataStorage = passData,
|
||||
diagnostics: DiagnosticStorage = diagnostics,
|
||||
id: Identifier = id
|
||||
): Annotation = {
|
||||
val res = Annotation(name, location, passData, diagnostics)
|
||||
): BuiltinAnnotation = {
|
||||
val res = BuiltinAnnotation(name, location, passData, diagnostics)
|
||||
res.id = id
|
||||
res
|
||||
}
|
||||
@ -2798,7 +2829,7 @@ object IR {
|
||||
keepMetadata: Boolean = true,
|
||||
keepDiagnostics: Boolean = true,
|
||||
keepIdentifiers: Boolean = false
|
||||
): Annotation =
|
||||
): BuiltinAnnotation =
|
||||
copy(
|
||||
location = if (keepLocations) location else None,
|
||||
passData =
|
||||
@ -2811,17 +2842,19 @@ object IR {
|
||||
/** @inheritdoc */
|
||||
override def setLocation(
|
||||
location: Option[IdentifiedLocation]
|
||||
): Annotation =
|
||||
): BuiltinAnnotation =
|
||||
copy(location = location)
|
||||
|
||||
/** @inheritdoc */
|
||||
override def mapExpressions(fn: Expression => Expression): Annotation =
|
||||
override def mapExpressions(
|
||||
fn: Expression => Expression
|
||||
): BuiltinAnnotation =
|
||||
this
|
||||
|
||||
/** @inheritdoc */
|
||||
override def toString: String =
|
||||
s"""
|
||||
|IR.Name.Annotation(
|
||||
|IR.Name.BuiltinAnnotation(
|
||||
|name = $name,
|
||||
|location = $location,
|
||||
|passData = ${this.showPassData},
|
||||
@ -2834,7 +2867,97 @@ object IR {
|
||||
override def children: List[IR] = List()
|
||||
|
||||
/** @inheritdoc */
|
||||
override def showCode(indent: Int): String = name
|
||||
override def showCode(indent: Int): String = s"@$name"
|
||||
}
|
||||
|
||||
/** Common annotations of form `@name expression`.
|
||||
*
|
||||
* @param name the annotation text of the name
|
||||
* @param expression the annotation expression
|
||||
* @param location the source location that the node corresponds to
|
||||
* @param passData the pass metadata associated with this node
|
||||
* @param diagnostics compiler diagnostics for this node
|
||||
*/
|
||||
sealed case class GenericAnnotation(
|
||||
override val name: String,
|
||||
expression: Expression,
|
||||
override val location: Option[IdentifiedLocation],
|
||||
override val passData: MetadataStorage = MetadataStorage(),
|
||||
override val diagnostics: DiagnosticStorage = DiagnosticStorage()
|
||||
) extends Annotation {
|
||||
override protected var id: Identifier = randomId
|
||||
|
||||
/** Creates a copy of `this`.
|
||||
*
|
||||
* @param name the annotation text of the name
|
||||
* @param expression the annotation expression
|
||||
* @param location the source location that the node corresponds to
|
||||
* @param passData the pass metadata associated with this node
|
||||
* @param diagnostics compiler diagnostics for this node
|
||||
* @param id the identifier for the new node
|
||||
* @return a copy of `this`, updated with the specified values
|
||||
*/
|
||||
def copy(
|
||||
name: String = name,
|
||||
expression: Expression = expression,
|
||||
location: Option[IdentifiedLocation] = location,
|
||||
passData: MetadataStorage = passData,
|
||||
diagnostics: DiagnosticStorage = diagnostics,
|
||||
id: Identifier = id
|
||||
): GenericAnnotation = {
|
||||
val res =
|
||||
GenericAnnotation(name, expression, location, passData, diagnostics)
|
||||
res.id = id
|
||||
res
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
override def duplicate(
|
||||
keepLocations: Boolean = true,
|
||||
keepMetadata: Boolean = true,
|
||||
keepDiagnostics: Boolean = true,
|
||||
keepIdentifiers: Boolean = false
|
||||
): GenericAnnotation =
|
||||
copy(
|
||||
location = if (keepLocations) location else None,
|
||||
passData =
|
||||
if (keepMetadata) passData.duplicate else MetadataStorage(),
|
||||
diagnostics =
|
||||
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
|
||||
id = if (keepIdentifiers) id else randomId
|
||||
)
|
||||
|
||||
/** @inheritdoc */
|
||||
override def setLocation(
|
||||
location: Option[IdentifiedLocation]
|
||||
): GenericAnnotation =
|
||||
copy(location = location)
|
||||
|
||||
/** @inheritdoc */
|
||||
override def mapExpressions(
|
||||
fn: Expression => Expression
|
||||
): GenericAnnotation =
|
||||
copy(expression = fn(expression))
|
||||
|
||||
/** @inheritdoc */
|
||||
override def toString: String =
|
||||
s"""
|
||||
|IR.Name.GenericAnnotation(
|
||||
|name = $name,
|
||||
|expression = $expression,
|
||||
|location = $location,
|
||||
|passData = ${this.showPassData},
|
||||
|diagnostics = $diagnostics,
|
||||
|id = $id
|
||||
|)
|
||||
|""".toSingleLine
|
||||
|
||||
/** @inheritdoc */
|
||||
override def children: List[IR] = List(expression)
|
||||
|
||||
/** @inheritdoc */
|
||||
override def showCode(indent: Int): String =
|
||||
s"@$name ${expression.showCode(indent)}"
|
||||
}
|
||||
|
||||
/** A representation of the name `self`, used to refer to the current type.
|
||||
@ -4420,7 +4543,7 @@ object IR {
|
||||
/** @inheritdoc */
|
||||
override def toString: String =
|
||||
s"""
|
||||
|IR.Function.Sugar(
|
||||
|IR.Function.Binding(
|
||||
|name = $name,
|
||||
|arguments = $arguments,
|
||||
|body = $body,
|
||||
@ -7512,7 +7635,7 @@ object IR {
|
||||
|
||||
/** A representation of an Enso syntax error.
|
||||
*
|
||||
* @param ast the erroneous AST
|
||||
* @param at the erroneous AST
|
||||
* @param reason the cause of this error
|
||||
* @param passData the pass metadata associated with this node
|
||||
* @param diagnostics compiler diagnostics for this node
|
||||
@ -8863,7 +8986,7 @@ object IR {
|
||||
@throws[CompilerError]
|
||||
def unsafeGetMetadata[K <: IRPass](
|
||||
pass: IRPass,
|
||||
msg: String
|
||||
msg: => String
|
||||
): pass.Metadata = {
|
||||
ir.passData.getUnsafe(pass)(msg)
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ class MetadataStorage(
|
||||
@throws[CompilerError]
|
||||
def getUnsafe[K <: IRPass](
|
||||
pass: K
|
||||
)(msg: String = s"Missing metadata for pass $pass"): pass.Metadata = {
|
||||
)(msg: => String = s"Missing metadata for pass $pass"): pass.Metadata = {
|
||||
get(pass).getOrElse(throw new CompilerError(msg))
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ class PassManager(
|
||||
* @throws CompilerError if a valid pass ordering cannot be computed
|
||||
* @return a valid pass ordering for the compiler, based on `passes`
|
||||
*/
|
||||
def verifyPassOrdering(passes: List[IRPass]): List[IRPass] = {
|
||||
private def verifyPassOrdering(passes: List[IRPass]): List[IRPass] = {
|
||||
var validPasses: Set[IRPass] = Set()
|
||||
|
||||
passes.foreach(pass => {
|
||||
@ -161,7 +161,7 @@ class PassManager(
|
||||
* @param passGroup the pass group being run
|
||||
* @return `true` if the condition holds, otherwise `false`
|
||||
*/
|
||||
def isLastRunOf(
|
||||
private def isLastRunOf(
|
||||
indexOfPassInGroup: Int,
|
||||
pass: IRPass,
|
||||
passGroup: PassGroup
|
||||
|
@ -14,7 +14,6 @@ import org.enso.syntax.text.Debug
|
||||
|
||||
import java.io.Serializable
|
||||
import scala.collection.mutable
|
||||
import scala.collection.mutable.ListBuffer
|
||||
import scala.reflect.ClassTag
|
||||
|
||||
/** This pass performs scope identification and analysis, as well as symbol
|
||||
@ -257,12 +256,23 @@ case object AliasAnalysis extends IRPass {
|
||||
),
|
||||
members = t.members.map(d => {
|
||||
val graph = new Graph
|
||||
d.copy(arguments =
|
||||
analyseArgumentDefs(
|
||||
d.copy(
|
||||
arguments = analyseArgumentDefs(
|
||||
d.arguments,
|
||||
graph,
|
||||
graph.rootScope
|
||||
)
|
||||
),
|
||||
annotations = d.annotations.map { ann =>
|
||||
ann
|
||||
.copy(
|
||||
expression = analyseExpression(
|
||||
ann.expression,
|
||||
topLevelGraph,
|
||||
topLevelGraph.rootScope
|
||||
)
|
||||
)
|
||||
.updateMetadata(this -->> Info.Scope.Root(topLevelGraph))
|
||||
}
|
||||
).updateMetadata(this -->> Info.Scope.Root(graph))
|
||||
})
|
||||
).updateMetadata(this -->> Info.Scope.Root(topLevelGraph))
|
||||
@ -280,11 +290,21 @@ case object AliasAnalysis extends IRPass {
|
||||
"Type signatures should not exist at the top level during " +
|
||||
"alias analysis."
|
||||
)
|
||||
case _: IR.Name.Annotation =>
|
||||
case _: IR.Name.BuiltinAnnotation =>
|
||||
throw new CompilerError(
|
||||
"Annotations should already be associated by the point of alias " +
|
||||
"analysis."
|
||||
)
|
||||
case ann: IR.Name.GenericAnnotation =>
|
||||
ann
|
||||
.copy(expression =
|
||||
analyseExpression(
|
||||
ann.expression,
|
||||
topLevelGraph,
|
||||
topLevelGraph.rootScope
|
||||
)
|
||||
)
|
||||
.updateMetadata(this -->> Info.Scope.Root(topLevelGraph))
|
||||
case err: IR.Error => err
|
||||
}
|
||||
}
|
||||
@ -561,7 +581,7 @@ case object AliasAnalysis extends IRPass {
|
||||
* @param parentScope the scope in which the arguments are defined
|
||||
* @return `args`, with aliasing information attached to each argument
|
||||
*/
|
||||
def analyseCallArguments(
|
||||
private def analyseCallArguments(
|
||||
args: List[IR.CallArgument],
|
||||
graph: AliasAnalysis.Graph,
|
||||
parentScope: AliasAnalysis.Graph.Scope
|
||||
@ -1207,7 +1227,8 @@ case object AliasAnalysis extends IRPass {
|
||||
mapping.get(this) match {
|
||||
case Some(newCorrespondingScope) => newCorrespondingScope
|
||||
case None =>
|
||||
val childScopeCopies: mutable.ListBuffer[Scope] = ListBuffer()
|
||||
val childScopeCopies: mutable.ListBuffer[Scope] =
|
||||
mutable.ListBuffer()
|
||||
this.childScopes.foreach(scope =>
|
||||
childScopeCopies += scope.deepCopy(mapping)
|
||||
)
|
||||
|
@ -117,12 +117,13 @@ case object CachePreferenceAnalysis extends IRPass {
|
||||
"Type signatures should not exist at the top level during " +
|
||||
"cache preference analysis."
|
||||
)
|
||||
case _: IR.Name.Annotation =>
|
||||
case _: IR.Name.BuiltinAnnotation =>
|
||||
throw new CompilerError(
|
||||
"Annotations should already be associated by the point of " +
|
||||
"cache preference analysis."
|
||||
)
|
||||
case err: IR.Error => err
|
||||
case ann: IR.Name.GenericAnnotation => ann
|
||||
case err: IR.Error => err
|
||||
}
|
||||
|
||||
/** Performs preference analysis on an arbitrary expression.
|
||||
|
@ -149,22 +149,21 @@ case object DataflowAnalysis extends IRPass {
|
||||
info.dependencies.updateAt(tpDep, Set(paramDep))
|
||||
analyseDefinitionArgument(param, info)
|
||||
}
|
||||
val newMembers = members.map {
|
||||
case data @ IR.Module.Scope.Definition.Data(_, arguments, _, _, _) =>
|
||||
val dataDep = asStatic(data)
|
||||
info.dependents.updateAt(dataDep, Set(tpDep))
|
||||
info.dependencies.updateAt(tpDep, Set(dataDep))
|
||||
arguments.foreach(arg => {
|
||||
val argDep = asStatic(arg)
|
||||
info.dependents.updateAt(argDep, Set(dataDep))
|
||||
info.dependencies.updateAt(dataDep, Set(argDep))
|
||||
})
|
||||
val newMembers = members.map { data =>
|
||||
val dataDep = asStatic(data)
|
||||
info.dependents.updateAt(dataDep, Set(tpDep))
|
||||
info.dependencies.updateAt(tpDep, Set(dataDep))
|
||||
data.arguments.foreach(arg => {
|
||||
val argDep = asStatic(arg)
|
||||
info.dependents.updateAt(argDep, Set(dataDep))
|
||||
info.dependencies.updateAt(dataDep, Set(argDep))
|
||||
})
|
||||
|
||||
data
|
||||
.copy(
|
||||
arguments = arguments.map(analyseDefinitionArgument(_, info))
|
||||
)
|
||||
.updateMetadata(this -->> info)
|
||||
data
|
||||
.copy(
|
||||
arguments = data.arguments.map(analyseDefinitionArgument(_, info))
|
||||
)
|
||||
.updateMetadata(this -->> info)
|
||||
}
|
||||
tp.copy(params = newParams, members = newMembers)
|
||||
.updateMetadata(this -->> info)
|
||||
@ -187,11 +186,15 @@ case object DataflowAnalysis extends IRPass {
|
||||
"Type signatures should not exist at the top level during " +
|
||||
"dataflow analysis."
|
||||
)
|
||||
case _: IR.Name.Annotation =>
|
||||
case _: IR.Name.BuiltinAnnotation =>
|
||||
throw new CompilerError(
|
||||
"Annotations should already be associated by the point of " +
|
||||
"dataflow analysis."
|
||||
)
|
||||
case ann: IR.Name.GenericAnnotation =>
|
||||
ann
|
||||
.copy(expression = analyseExpression(ann.expression, info))
|
||||
.updateMetadata(this -->> info)
|
||||
case err: IR.Error => err
|
||||
}
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ case object TailCall extends IRPass {
|
||||
* @param definition the top-level definition to analyse
|
||||
* @return `definition`, annotated with tail call information
|
||||
*/
|
||||
def analyseModuleBinding(
|
||||
private def analyseModuleBinding(
|
||||
definition: IR.Module.Scope.Definition
|
||||
): IR.Module.Scope.Definition = {
|
||||
definition match {
|
||||
@ -126,11 +126,17 @@ case object TailCall extends IRPass {
|
||||
"Type signatures should not exist at the top level during " +
|
||||
"tail call analysis."
|
||||
)
|
||||
case _: IR.Name.Annotation =>
|
||||
case _: IR.Name.BuiltinAnnotation =>
|
||||
throw new CompilerError(
|
||||
"Annotations should already be associated by the point of " +
|
||||
"tail call analysis."
|
||||
)
|
||||
case ann: IR.Name.GenericAnnotation =>
|
||||
ann
|
||||
.copy(expression =
|
||||
analyseExpression(ann.expression, isInTailPosition = true)
|
||||
)
|
||||
.updateMetadata(this -->> TailPosition.Tail)
|
||||
case err: IR.Error => err
|
||||
}
|
||||
}
|
||||
|
@ -27,8 +27,6 @@ import org.enso.compiler.pass.resolve.{
|
||||
}
|
||||
import org.enso.compiler.core.ir.MetadataStorage._
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** Desugars complex type definitions to simple type definitions in the module
|
||||
* scope.
|
||||
*
|
||||
@ -75,7 +73,7 @@ case object ComplexType extends IRPass {
|
||||
*/
|
||||
override def runModule(
|
||||
ir: IR.Module,
|
||||
@unused moduleContext: ModuleContext
|
||||
moduleContext: ModuleContext
|
||||
): IR.Module =
|
||||
ir.copy(
|
||||
bindings = ir.bindings.flatMap {
|
||||
@ -94,12 +92,12 @@ case object ComplexType extends IRPass {
|
||||
*/
|
||||
override def runExpression(
|
||||
ir: IR.Expression,
|
||||
@unused inlineContext: InlineContext
|
||||
inlineContext: InlineContext
|
||||
): IR.Expression = ir
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
@ -110,12 +108,25 @@ case object ComplexType extends IRPass {
|
||||
* @param typ the type definition to desugar
|
||||
* @return the top-level definitions corresponding to the desugaring of `typ`
|
||||
*/
|
||||
def desugarComplexType(
|
||||
private def desugarComplexType(
|
||||
typ: IR.Module.Scope.Definition.SugaredType
|
||||
): List[IR.Module.Scope.Definition] = {
|
||||
val annotations = typ.getMetadata(ModuleAnnotations)
|
||||
val annotations = typ.getMetadata(ModuleAnnotations)
|
||||
var lastAnnotations = Seq.empty[IR.Name.GenericAnnotation]
|
||||
var seenAnnotations = Set.empty[IR.Name.GenericAnnotation]
|
||||
val atomDefs = typ.body
|
||||
.collect { case d: IR.Module.Scope.Definition.Data => d }
|
||||
.flatMap {
|
||||
case ann: IR.Name.GenericAnnotation =>
|
||||
lastAnnotations :+= ann
|
||||
None
|
||||
case d: IR.Module.Scope.Definition.Data =>
|
||||
val res = Some(d.copy(annotations = d.annotations ++ lastAnnotations))
|
||||
seenAnnotations ++= lastAnnotations
|
||||
lastAnnotations = Seq()
|
||||
res
|
||||
case _ =>
|
||||
None
|
||||
}
|
||||
// TODO[MK] this is probably removable
|
||||
.map(atom =>
|
||||
annotations
|
||||
@ -133,6 +144,7 @@ case object ComplexType extends IRPass {
|
||||
|
||||
val remainingEntities = typ.body.filterNot {
|
||||
case _: IR.Module.Scope.Definition.Data => true
|
||||
case ann: IR.Name.GenericAnnotation => seenAnnotations.contains(ann)
|
||||
case _ => false
|
||||
}
|
||||
|
||||
@ -185,7 +197,8 @@ case object ComplexType extends IRPass {
|
||||
matchSignaturesAndGenerate(name, binding)
|
||||
case funSugar @ IR.Function.Binding(name, _, _, _, _, _, _) =>
|
||||
matchSignaturesAndGenerate(name, funSugar)
|
||||
case err: IR.Error => Seq(err)
|
||||
case err: IR.Error => Seq(err)
|
||||
case ann: IR.Name.GenericAnnotation => Seq(ann)
|
||||
case _ =>
|
||||
throw new CompilerError("Unexpected IR node in complex type body.")
|
||||
}
|
||||
@ -217,11 +230,11 @@ case object ComplexType extends IRPass {
|
||||
* The signature _must_ correctly match the method definition.
|
||||
*
|
||||
* @param ir the definition to generate a method from
|
||||
* @param names the names on which the method is being defined
|
||||
* @param typeName the type name on which the method is being defined
|
||||
* @param signature the type signature for the method, if it exists
|
||||
* @return `ir` as a method
|
||||
*/
|
||||
def genMethodDef(
|
||||
private def genMethodDef(
|
||||
ir: IR,
|
||||
typeName: IR.Name,
|
||||
signature: Option[IR.Type.Ascription]
|
||||
@ -280,7 +293,7 @@ case object ComplexType extends IRPass {
|
||||
* @param signature the method's type signature, if it exists
|
||||
* @return a top-level method definition
|
||||
*/
|
||||
def genForName(
|
||||
private def genForName(
|
||||
typeName: IR.Name,
|
||||
name: IR.Name,
|
||||
args: List[IR.DefinitionArgument],
|
||||
|
@ -18,8 +18,6 @@ import org.enso.compiler.pass.optimise.LambdaConsolidate
|
||||
import org.enso.compiler.pass.resolve.IgnoredBindings
|
||||
import org.enso.interpreter.Constants
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** This pass handles the desugaring of long-form function and method
|
||||
* definitions into standard bindings using lambdas.
|
||||
*
|
||||
@ -64,7 +62,7 @@ case object FunctionBinding extends IRPass {
|
||||
*/
|
||||
override def runModule(
|
||||
ir: IR.Module,
|
||||
@unused moduleContext: ModuleContext
|
||||
moduleContext: ModuleContext
|
||||
): IR.Module = ir.copy(bindings = ir.bindings.map(desugarModuleSymbol))
|
||||
|
||||
/** Runs desugaring of function bindings on an arbitrary expression.
|
||||
@ -77,12 +75,12 @@ case object FunctionBinding extends IRPass {
|
||||
*/
|
||||
override def runExpression(
|
||||
ir: IR.Expression,
|
||||
@unused inlineContext: InlineContext
|
||||
inlineContext: InlineContext
|
||||
): IR.Expression = desugarExpression(ir)
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
@ -319,13 +317,14 @@ case object FunctionBinding extends IRPass {
|
||||
"Documentation should not be present during function binding" +
|
||||
"desugaring."
|
||||
)
|
||||
case _: IR.Name.Annotation =>
|
||||
case _: IR.Name.BuiltinAnnotation =>
|
||||
throw new CompilerError(
|
||||
"Annotations should already be associated by the point of " +
|
||||
"function binding desugaring."
|
||||
)
|
||||
case a: IR.Type.Ascription => a
|
||||
case e: IR.Error => e
|
||||
case a: IR.Name.GenericAnnotation => a
|
||||
case a: IR.Type.Ascription => a
|
||||
case e: IR.Error => e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,6 @@ import org.enso.compiler.exception.CompilerError
|
||||
import org.enso.compiler.pass.IRPass
|
||||
import org.enso.compiler.pass.desugar.{ComplexType, GenerateMethodBodies}
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** Associates doc comments with the commented entities as metadata.
|
||||
*
|
||||
* If the first module definition is a documentation comment, it is treated as
|
||||
@ -61,7 +59,7 @@ case object DocumentationComments extends IRPass {
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
@ -94,6 +92,8 @@ case object DocumentationComments extends IRPass {
|
||||
private def resolveList[T <: IR](items: List[T]): List[T] = {
|
||||
var lastDoc: Option[IR.Comment.Documentation] = None
|
||||
items.flatMap {
|
||||
case annotation: IR.Name.Annotation =>
|
||||
Some(annotation.asInstanceOf[T])
|
||||
case doc: IR.Comment.Documentation =>
|
||||
lastDoc = Some(doc)
|
||||
None
|
||||
@ -158,10 +158,11 @@ case object DocumentationComments extends IRPass {
|
||||
method.copy(body = resolveExpression(method.body))
|
||||
case tpe: IR.Module.Scope.Definition.SugaredType =>
|
||||
tpe.copy(body = resolveList(tpe.body).map(resolveIr))
|
||||
case doc: IR.Comment.Documentation => doc
|
||||
case tySig: IR.Type.Ascription => tySig
|
||||
case err: IR.Error => err
|
||||
case _: IR.Name.Annotation =>
|
||||
case doc: IR.Comment.Documentation => doc
|
||||
case tySig: IR.Type.Ascription => tySig
|
||||
case err: IR.Error => err
|
||||
case ann: IR.Name.GenericAnnotation => ann
|
||||
case _: IR.Name.BuiltinAnnotation =>
|
||||
throw new CompilerError(
|
||||
"Annotations should already be associated by the point of " +
|
||||
"documentation comment resolution."
|
||||
|
@ -8,8 +8,6 @@ import org.enso.compiler.pass.IRPass
|
||||
import org.enso.compiler.pass.analyse.AliasAnalysis
|
||||
import org.enso.compiler.pass.resolve.ModuleAnnotations.Annotations
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
case object ExpressionAnnotations extends IRPass {
|
||||
val tailCallName = "@Tail_Call"
|
||||
val builtinMethodName = "@Builtin_Method"
|
||||
@ -62,7 +60,7 @@ case object ExpressionAnnotations extends IRPass {
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
@ -71,7 +69,7 @@ case object ExpressionAnnotations extends IRPass {
|
||||
): IR.Expression =
|
||||
ir.transformExpressions {
|
||||
case app @ IR.Application.Prefix(
|
||||
ann: IR.Name.Annotation,
|
||||
ann: IR.Name.BuiltinAnnotation,
|
||||
arguments,
|
||||
_,
|
||||
_,
|
||||
@ -104,7 +102,7 @@ case object ExpressionAnnotations extends IRPass {
|
||||
IR.Error.Resolution(ann, IR.Error.Resolution.UnknownAnnotation)
|
||||
app.copy(function = err)
|
||||
}
|
||||
case ann: IR.Name.Annotation =>
|
||||
case ann: IR.Name.BuiltinAnnotation =>
|
||||
if (isKnownAnnotation(ann.name)) {
|
||||
IR.Error.Resolution(
|
||||
ann,
|
||||
@ -120,7 +118,7 @@ case object ExpressionAnnotations extends IRPass {
|
||||
* @param name the annotation name to check
|
||||
* @return `true` if `name` is a known annotation, otherwise `false`
|
||||
*/
|
||||
def isKnownAnnotation(name: String): Boolean = {
|
||||
private def isKnownAnnotation(name: String): Boolean = {
|
||||
knownAnnotations.contains(name)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,89 @@
|
||||
package org.enso.compiler.pass.resolve
|
||||
|
||||
import org.enso.compiler.context.{InlineContext, ModuleContext}
|
||||
import org.enso.compiler.core.IR
|
||||
import org.enso.compiler.core.IR.Module.Scope.Definition
|
||||
import org.enso.compiler.core.ir.MetadataStorage._
|
||||
import org.enso.compiler.exception.CompilerError
|
||||
import org.enso.compiler.pass.IRPass
|
||||
|
||||
/** A pass responsible for the discovery of [[IR.Name.GenericAnnotation]]
|
||||
* annotations, and for associating them with the corresponding construct.
|
||||
*
|
||||
* Compilation pipeline of generic annotations:
|
||||
* - [[ModuleAnnotations]] pass ignores generic annotations and leaves them in
|
||||
* the tree so that the consequent passes are able to process the annotation
|
||||
* expression.
|
||||
* - [[org.enso.compiler.pass.desugar.ComplexType]] pass associates generic
|
||||
* annotations with the type constructor definitions.
|
||||
* - [[GenericAnnotations]] pass associates generic annotations that are left
|
||||
* in the tree with the appropriate definitions.
|
||||
*/
|
||||
case object GenericAnnotations extends IRPass {
|
||||
override type Metadata = ModuleAnnotations.Annotations
|
||||
override type Config = IRPass.Configuration.Default
|
||||
override val precursorPasses: Seq[IRPass] = Seq()
|
||||
override val invalidatedPasses: Seq[IRPass] = Seq()
|
||||
|
||||
/** Resolves annotations.
|
||||
*
|
||||
* @param ir the Enso IR to process
|
||||
* @param moduleContext a context object that contains the information needed
|
||||
* to process a module
|
||||
* @return `ir`, possibly having made transformations or annotations to that
|
||||
* IR.
|
||||
*/
|
||||
override def runModule(
|
||||
ir: IR.Module,
|
||||
moduleContext: ModuleContext
|
||||
): IR.Module = {
|
||||
var lastAnnotations: Seq[IR.Name.GenericAnnotation] = Seq()
|
||||
val newBindings = ir.bindings.map {
|
||||
case _: IR.Name.BuiltinAnnotation =>
|
||||
throw new CompilerError(
|
||||
s"Builtin annotations should not be present at generic annotations pass."
|
||||
)
|
||||
case _: Definition.SugaredType =>
|
||||
throw new CompilerError(
|
||||
s"Sugared types should not be present at generic annotations pass."
|
||||
)
|
||||
case _: IR.Comment =>
|
||||
throw new CompilerError(
|
||||
"Comments should not be present at generic annotations pass."
|
||||
)
|
||||
case ann: IR.Name.GenericAnnotation =>
|
||||
lastAnnotations :+= ann
|
||||
None
|
||||
case entity =>
|
||||
val res = Some(
|
||||
entity.updateMetadata(
|
||||
this -->> ModuleAnnotations.Annotations(lastAnnotations)
|
||||
)
|
||||
)
|
||||
lastAnnotations = Seq()
|
||||
res
|
||||
}
|
||||
ir.copy(bindings = newBindings.flatten)
|
||||
}
|
||||
|
||||
/** Execute the pass on an expression.
|
||||
*
|
||||
* As the pass only deals with module-level annotations this is a no-op.
|
||||
*
|
||||
* @param ir the Enso IR to process
|
||||
* @param inlineContext a context object that contains the information needed
|
||||
* for inline evaluation
|
||||
* @return `ir`, possibly having made transformations or annotations to that
|
||||
* IR.
|
||||
*/
|
||||
override def runExpression(
|
||||
ir: IR.Expression,
|
||||
inlineContext: InlineContext
|
||||
): IR.Expression = ir
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
}
|
@ -15,8 +15,6 @@ import org.enso.compiler.pass.IRPass
|
||||
import org.enso.compiler.pass.analyse.{AliasAnalysis, BindingAnalysis}
|
||||
import org.enso.interpreter.Constants
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** Resolves name occurences in non-pattern contexts.
|
||||
*
|
||||
* 1. Attaches resolution metadata to encountered constructors, modules,
|
||||
@ -61,7 +59,7 @@ case object GlobalNames extends IRPass {
|
||||
)
|
||||
val freshNameSupply = moduleContext.freshNameSupply.getOrElse(
|
||||
throw new CompilerError(
|
||||
"No fresh name supply passed to UppercaseNames resolver."
|
||||
"No fresh name supply passed to GlobalNames resolver."
|
||||
)
|
||||
)
|
||||
val new_bindings =
|
||||
@ -96,7 +94,7 @@ case object GlobalNames extends IRPass {
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
@ -139,7 +137,7 @@ case object GlobalNames extends IRPass {
|
||||
freshNameSupply: FreshNameSupply,
|
||||
selfTypeResolution: Option[Resolution],
|
||||
isInsideApplication: Boolean = false
|
||||
): IR.Expression =
|
||||
): IR.Expression = {
|
||||
ir.transformExpressions {
|
||||
case selfTp: IR.Name.SelfType =>
|
||||
selfTypeResolution
|
||||
@ -239,6 +237,7 @@ case object GlobalNames extends IRPass {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private def resolveReferantApplication(
|
||||
app: IR.Application.Prefix,
|
||||
|
@ -13,8 +13,6 @@ import org.enso.compiler.pass.desugar.{
|
||||
GenerateMethodBodies
|
||||
}
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** A pass responsible for the discovery of module annotations, and for
|
||||
* associating them with the corresponding construct.
|
||||
*/
|
||||
@ -34,7 +32,7 @@ case object ModuleAnnotations extends IRPass {
|
||||
* @param ir the Enso IR to process
|
||||
* @param moduleContext a context object that contains the information needed
|
||||
* to process a module
|
||||
* @return `ir`, possibly having made transformations or annotations to that
|
||||
* @return `ir`, possibly having made transformations or annotations to that
|
||||
* IR.
|
||||
*/
|
||||
override def runModule(
|
||||
@ -42,27 +40,27 @@ case object ModuleAnnotations extends IRPass {
|
||||
moduleContext: ModuleContext
|
||||
): IR.Module = {
|
||||
var lastAnnotations: Seq[IR.Name.Annotation] = Seq()
|
||||
val newBindings = for (binding <- ir.bindings) yield {
|
||||
binding match {
|
||||
case ann: Name.Annotation =>
|
||||
lastAnnotations :+= ann
|
||||
None
|
||||
case comment: IR.Comment => Some(comment)
|
||||
case typ: Definition.SugaredType =>
|
||||
val res = Some(
|
||||
resolveComplexType(typ).updateMetadata(
|
||||
this -->> Annotations(lastAnnotations)
|
||||
)
|
||||
val newBindings = ir.bindings.map {
|
||||
case ann: Name.BuiltinAnnotation =>
|
||||
lastAnnotations :+= ann
|
||||
None
|
||||
case ann: Name.GenericAnnotation =>
|
||||
Some(ann)
|
||||
case comment: IR.Comment => Some(comment)
|
||||
case typ: Definition.SugaredType =>
|
||||
val res = Some(
|
||||
resolveComplexType(typ).updateMetadata(
|
||||
this -->> Annotations(lastAnnotations)
|
||||
)
|
||||
lastAnnotations = Seq()
|
||||
res
|
||||
case entity =>
|
||||
val res = Some(
|
||||
entity.updateMetadata(this -->> Annotations(lastAnnotations))
|
||||
)
|
||||
lastAnnotations = Seq()
|
||||
res
|
||||
}
|
||||
)
|
||||
lastAnnotations = Seq()
|
||||
res
|
||||
case entity =>
|
||||
val res = Some(
|
||||
entity.updateMetadata(this -->> Annotations(lastAnnotations))
|
||||
)
|
||||
lastAnnotations = Seq()
|
||||
res
|
||||
}
|
||||
ir.copy(bindings = newBindings.flatten)
|
||||
}
|
||||
@ -72,14 +70,16 @@ case object ModuleAnnotations extends IRPass {
|
||||
* @param typ the type in which to resolve annotations
|
||||
* @return `typ` with all top-level annotations resolved
|
||||
*/
|
||||
def resolveComplexType(
|
||||
private def resolveComplexType(
|
||||
typ: Definition.SugaredType
|
||||
): Definition.SugaredType = {
|
||||
var lastAnnotations: Seq[IR.Name.Annotation] = Seq()
|
||||
val newBodyElems = typ.body.flatMap {
|
||||
case ann: Name.Annotation =>
|
||||
case ann: Name.BuiltinAnnotation =>
|
||||
lastAnnotations :+= ann
|
||||
None
|
||||
case ann: Name.GenericAnnotation =>
|
||||
Some(ann)
|
||||
case comment: IR.Comment => Some(comment)
|
||||
case entity =>
|
||||
val res = Some(
|
||||
@ -98,17 +98,17 @@ case object ModuleAnnotations extends IRPass {
|
||||
* @param ir the Enso IR to process
|
||||
* @param inlineContext a context object that contains the information needed
|
||||
* for inline evaluation
|
||||
* @return `ir`, possibly having made transformations or annotations to that
|
||||
* @return `ir`, possibly having made transformations or annotations to that
|
||||
* IR.
|
||||
*/
|
||||
override def runExpression(
|
||||
ir: IR.Expression,
|
||||
@unused inlineContext: InlineContext
|
||||
inlineContext: InlineContext
|
||||
): IR.Expression = ir
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
|
@ -2,10 +2,10 @@ package org.enso.compiler.pass.resolve
|
||||
|
||||
import org.enso.compiler.context.{InlineContext, ModuleContext}
|
||||
import org.enso.compiler.core.IR
|
||||
import org.enso.compiler.exception.CompilerError
|
||||
import org.enso.compiler.pass.IRPass
|
||||
import org.enso.compiler.pass.desugar.{ComplexType, GenerateMethodBodies}
|
||||
|
||||
import scala.annotation.unused
|
||||
import scala.collection.mutable
|
||||
|
||||
/** This pass performs static detection of method overloads and emits errors
|
||||
@ -45,59 +45,56 @@ case object OverloadsResolution extends IRPass {
|
||||
*/
|
||||
override def runModule(
|
||||
ir: IR.Module,
|
||||
@unused moduleContext: ModuleContext
|
||||
moduleContext: ModuleContext
|
||||
): IR.Module = {
|
||||
var seenTypes: Set[String] = Set()
|
||||
var seenMethods: Map[Option[String], Set[(String, Boolean)]] = Map()
|
||||
|
||||
val types = ir.bindings.collect {
|
||||
case tp: IR.Module.Scope.Definition.Type => tp
|
||||
}
|
||||
|
||||
val newTypes: List[IR.Module.Scope.Definition] = types.map(tp => {
|
||||
if (seenTypes.contains(tp.name.name)) {
|
||||
IR.Error.Redefined.Type(tp.name, tp.location)
|
||||
} else {
|
||||
seenTypes = seenTypes + tp.name.name
|
||||
case tp: IR.Module.Scope.Definition.Type =>
|
||||
tp
|
||||
}
|
||||
})
|
||||
|
||||
val methods = ir.bindings.collect {
|
||||
}
|
||||
ir.bindings.collect {
|
||||
case meth: IR.Module.Scope.Definition.Method.Explicit =>
|
||||
seenMethods = seenMethods + (meth.typeName.map(_.name) -> Set())
|
||||
seenMethods += meth.typeName.map(_.name) -> Set()
|
||||
meth
|
||||
}
|
||||
|
||||
val newMethods: List[IR.Module.Scope.Definition] = methods.map(method => {
|
||||
if (
|
||||
seenMethods(method.typeName.map(_.name))
|
||||
.contains((method.methodName.name, method.isStatic))
|
||||
) {
|
||||
IR.Error.Redefined
|
||||
.Method(method.typeName, method.methodName, method.location)
|
||||
} else {
|
||||
types.find(_.name.name.equals(method.methodName.name)) match {
|
||||
case Some(clashedAtom) if method.typeName.isEmpty =>
|
||||
IR.Error.Redefined.MethodClashWithAtom(
|
||||
clashedAtom.name,
|
||||
method.methodName,
|
||||
method.location
|
||||
)
|
||||
case _ =>
|
||||
val currentMethods: Set[(String, Boolean)] =
|
||||
seenMethods(method.typeName.map(_.name))
|
||||
seenMethods = seenMethods + (method.typeName.map(_.name) ->
|
||||
(currentMethods + ((method.methodName.name, method.isStatic))))
|
||||
method
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
val conversionsForType: mutable.Map[Option[String], Set[String]] =
|
||||
mutable.Map()
|
||||
|
||||
val conversions: List[IR.Module.Scope.Definition] = ir.bindings.collect {
|
||||
val newBindings = ir.bindings.map {
|
||||
case tp: IR.Module.Scope.Definition.Type =>
|
||||
if (seenTypes.contains(tp.name.name)) {
|
||||
IR.Error.Redefined.Type(tp.name, tp.location)
|
||||
} else {
|
||||
seenTypes += tp.name.name
|
||||
tp
|
||||
}
|
||||
|
||||
case method: IR.Module.Scope.Definition.Method.Explicit =>
|
||||
if (
|
||||
seenMethods(method.typeName.map(_.name))
|
||||
.contains((method.methodName.name, method.isStatic))
|
||||
) {
|
||||
IR.Error.Redefined
|
||||
.Method(method.typeName, method.methodName, method.location)
|
||||
} else {
|
||||
types.find(_.name.name.equals(method.methodName.name)) match {
|
||||
case Some(clashedAtom) if method.typeName.isEmpty =>
|
||||
IR.Error.Redefined.MethodClashWithAtom(
|
||||
clashedAtom.name,
|
||||
method.methodName,
|
||||
method.location
|
||||
)
|
||||
case _ =>
|
||||
val currentMethods: Set[(String, Boolean)] =
|
||||
seenMethods(method.typeName.map(_.name))
|
||||
seenMethods += (method.typeName.map(_.name) ->
|
||||
(currentMethods + ((method.methodName.name, method.isStatic))))
|
||||
method
|
||||
}
|
||||
}
|
||||
|
||||
case m: IR.Module.Scope.Definition.Method.Conversion =>
|
||||
val fromName = m.sourceTypeName.asInstanceOf[IR.Name]
|
||||
conversionsForType.get(m.typeName.map(_.name)) match {
|
||||
@ -115,15 +112,32 @@ case object OverloadsResolution extends IRPass {
|
||||
conversionsForType.put(m.typeName.map(_.name), Set(fromName.name))
|
||||
m
|
||||
}
|
||||
|
||||
case diagnostic: IR.Diagnostic => diagnostic
|
||||
case ann: IR.Name.GenericAnnotation => ann
|
||||
case _: IR.Type.Ascription =>
|
||||
throw new CompilerError(
|
||||
"Type ascriptions should not be present during the overloads resolution."
|
||||
)
|
||||
case _: IR.Module.Scope.Definition.Method.Binding =>
|
||||
throw new CompilerError(
|
||||
"Method bindings should not be present during the overloads resolution."
|
||||
)
|
||||
case _: IR.Name.BuiltinAnnotation =>
|
||||
throw new CompilerError(
|
||||
"Builtin annotations should not be present during the overloads resolution."
|
||||
)
|
||||
case _: IR.Comment.Documentation =>
|
||||
throw new CompilerError(
|
||||
"Documentation comments should not be present during the overloads resolution."
|
||||
)
|
||||
case _: IR.Module.Scope.Definition.SugaredType =>
|
||||
throw new CompilerError(
|
||||
"Sugared types should not be present during the overloads resolution."
|
||||
)
|
||||
}
|
||||
|
||||
val diagnostics = ir.bindings.collect { case diag: IR.Diagnostic =>
|
||||
diag
|
||||
}
|
||||
|
||||
ir.copy(
|
||||
bindings = newTypes ::: newMethods ::: conversions ::: diagnostics
|
||||
)
|
||||
ir.copy(bindings = newBindings)
|
||||
}
|
||||
|
||||
/** This pass does nothing for the expression flow.
|
||||
@ -141,7 +155,7 @@ case object OverloadsResolution extends IRPass {
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
}
|
||||
|
@ -13,8 +13,6 @@ import org.enso.compiler.pass.lint.UnusedBindings
|
||||
import org.enso.compiler.pass.optimise.LambdaConsolidate
|
||||
import org.enso.compiler.pass.resolve.TypeSignatures.Signature
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** This pass is responsible for analysing type signatures to determine which
|
||||
* arguments in a function definition are suspended.
|
||||
*
|
||||
@ -69,7 +67,7 @@ case object SuspendedArguments extends IRPass {
|
||||
*/
|
||||
override def runModule(
|
||||
ir: IR.Module,
|
||||
@unused moduleContext: ModuleContext
|
||||
moduleContext: ModuleContext
|
||||
): IR.Module =
|
||||
ir.copy(
|
||||
bindings = ir.bindings.map(resolveModuleBinding)
|
||||
@ -85,12 +83,12 @@ case object SuspendedArguments extends IRPass {
|
||||
*/
|
||||
override def runExpression(
|
||||
ir: IR.Expression,
|
||||
@unused inlineContext: InlineContext
|
||||
inlineContext: InlineContext
|
||||
): IR.Expression = resolveExpression(ir)
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
@ -104,7 +102,7 @@ case object SuspendedArguments extends IRPass {
|
||||
* @param binding the top-level binding to resolve suspensions in
|
||||
* @return `binding`, with any suspended arguments resolved
|
||||
*/
|
||||
def resolveModuleBinding(
|
||||
private def resolveModuleBinding(
|
||||
binding: IR.Module.Scope.Definition
|
||||
): IR.Module.Scope.Definition = {
|
||||
binding match {
|
||||
@ -193,11 +191,12 @@ case object SuspendedArguments extends IRPass {
|
||||
throw new CompilerError("Type ascriptions should not be present.")
|
||||
case _: IR.Comment =>
|
||||
throw new CompilerError("Comments should not be present.")
|
||||
case _: IR.Name.Annotation =>
|
||||
case _: IR.Name.BuiltinAnnotation =>
|
||||
throw new CompilerError(
|
||||
"Annotations should already be associated by the point of " +
|
||||
"suspended arguments analysis."
|
||||
)
|
||||
case ann: IR.Name.GenericAnnotation => ann
|
||||
}
|
||||
}
|
||||
|
||||
@ -206,7 +205,7 @@ case object SuspendedArguments extends IRPass {
|
||||
* @param expression the expression to perform resolution in
|
||||
* @return `expression`, with any suspended arguments resolved
|
||||
*/
|
||||
def resolveExpression(expression: IR.Expression): IR.Expression = {
|
||||
private def resolveExpression(expression: IR.Expression): IR.Expression = {
|
||||
expression.transformExpressions {
|
||||
case bind @ IR.Expression.Binding(_, expr, _, _, _) =>
|
||||
val newExpr = bind.getMetadata(TypeSignatures) match {
|
||||
@ -244,7 +243,7 @@ case object SuspendedArguments extends IRPass {
|
||||
* @param signature the type signature to split
|
||||
* @return the segments of `signature`
|
||||
*/
|
||||
def toSegments(signature: IR.Expression): List[IR.Expression] = {
|
||||
private def toSegments(signature: IR.Expression): List[IR.Expression] = {
|
||||
signature match {
|
||||
case IR.Type.Function(args, ret, _, _, _) => args :+ ret
|
||||
case _ => List(signature)
|
||||
@ -270,7 +269,7 @@ case object SuspendedArguments extends IRPass {
|
||||
* @param pair an argument and its corresponding type signature segment
|
||||
* @return the argument from `pair`, with its suspension marked appropriately
|
||||
*/
|
||||
def markSuspended(
|
||||
private def markSuspended(
|
||||
pair: (IR.DefinitionArgument, IR.Expression)
|
||||
): IR.DefinitionArgument =
|
||||
pair match {
|
||||
@ -289,7 +288,7 @@ case object SuspendedArguments extends IRPass {
|
||||
* @param signature the signature of the function
|
||||
* @return `args`, appropriately marked as suspended or not
|
||||
*/
|
||||
def computeSuspensions(
|
||||
private def computeSuspensions(
|
||||
args: List[IR.DefinitionArgument],
|
||||
signature: IR.Expression
|
||||
): List[IR.DefinitionArgument] = {
|
||||
|
@ -9,8 +9,6 @@ import org.enso.compiler.pass.IRPass
|
||||
import org.enso.compiler.pass.analyse._
|
||||
import org.enso.compiler.pass.lint.UnusedBindings
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** This pass is responsible for resolving type signatures and associating
|
||||
* them as metadata with the typed object.
|
||||
*
|
||||
@ -49,7 +47,7 @@ case object TypeSignatures extends IRPass {
|
||||
*/
|
||||
override def runModule(
|
||||
ir: IR.Module,
|
||||
@unused moduleContext: ModuleContext
|
||||
moduleContext: ModuleContext
|
||||
): IR.Module = resolveModule(ir)
|
||||
|
||||
/** Resolves type signatures in an expression.
|
||||
@ -62,12 +60,12 @@ case object TypeSignatures extends IRPass {
|
||||
*/
|
||||
override def runExpression(
|
||||
ir: IR.Expression,
|
||||
@unused inlineContext: InlineContext
|
||||
inlineContext: InlineContext
|
||||
): IR.Expression = resolveExpression(ir)
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
@ -78,7 +76,7 @@ case object TypeSignatures extends IRPass {
|
||||
* @param mod the module to resolve signatures in
|
||||
* @return `mod`, with type signatures resolved
|
||||
*/
|
||||
def resolveModule(mod: IR.Module): IR.Module = {
|
||||
private def resolveModule(mod: IR.Module): IR.Module = {
|
||||
var lastSignature: Option[IR.Type.Ascription] = None
|
||||
|
||||
val newBindings: List[IR.Module.Scope.Definition] = mod.bindings.flatMap {
|
||||
@ -133,13 +131,14 @@ case object TypeSignatures extends IRPass {
|
||||
res
|
||||
case ut: IR.Module.Scope.Definition.Type =>
|
||||
Some(ut.mapExpressions(resolveExpression))
|
||||
case err: IR.Error => Some(err)
|
||||
case err: IR.Error => Some(err)
|
||||
case ann: IR.Name.GenericAnnotation => Some(ann)
|
||||
case _: IR.Module.Scope.Definition.SugaredType =>
|
||||
throw new CompilerError(
|
||||
"Complex type definitions should not be present during type " +
|
||||
"signature resolution."
|
||||
)
|
||||
case _: IR.Name.Annotation =>
|
||||
case _: IR.Name.BuiltinAnnotation =>
|
||||
throw new CompilerError(
|
||||
"Annotations should already be associated by the point of " +
|
||||
"type signature resolution."
|
||||
@ -163,7 +162,7 @@ case object TypeSignatures extends IRPass {
|
||||
* @param expr the expression to resolve signatures in
|
||||
* @return `expr`, with any type signatures resolved
|
||||
*/
|
||||
def resolveExpression(expr: IR.Expression): IR.Expression = {
|
||||
private def resolveExpression(expr: IR.Expression): IR.Expression = {
|
||||
expr.transformExpressions {
|
||||
case block: IR.Expression.Block => resolveBlock(block)
|
||||
case sig: IR.Type.Ascription => resolveAscription(sig)
|
||||
@ -175,7 +174,7 @@ case object TypeSignatures extends IRPass {
|
||||
* @param sig the signature to convert
|
||||
* @return the typed expression in `sig`, with `signature` attached
|
||||
*/
|
||||
def resolveAscription(sig: IR.Type.Ascription): IR.Expression = {
|
||||
private def resolveAscription(sig: IR.Type.Ascription): IR.Expression = {
|
||||
val newTyped = sig.typed.mapExpressions(resolveExpression)
|
||||
val newSig = sig.signature.mapExpressions(resolveExpression)
|
||||
newTyped.updateMetadata(this -->> Signature(newSig))
|
||||
@ -186,7 +185,7 @@ case object TypeSignatures extends IRPass {
|
||||
* @param block the block to resolve signatures in
|
||||
* @return `block`, with any type signatures resolved
|
||||
*/
|
||||
def resolveBlock(block: IR.Expression.Block): IR.Expression.Block = {
|
||||
private def resolveBlock(block: IR.Expression.Block): IR.Expression.Block = {
|
||||
var lastSignature: Option[IR.Type.Ascription] = None
|
||||
val allBlockExpressions =
|
||||
block.expressions :+ block.returnValue
|
||||
|
@ -0,0 +1,97 @@
|
||||
package org.enso.compiler;
|
||||
|
||||
import org.enso.compiler.core.IR$Function$Binding;
|
||||
import org.enso.compiler.core.IR$Module$Scope$Definition$Data;
|
||||
import org.enso.compiler.core.IR$Module$Scope$Definition$SugaredType;
|
||||
import org.enso.compiler.core.IR$Name$Annotation;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class AnnotationsCompilerTest extends CompilerTest {
|
||||
|
||||
@Test
|
||||
public void testModuleMethod() throws Exception {
|
||||
var ir = parse("""
|
||||
@a expr
|
||||
@b (x y)
|
||||
foo a b = a b
|
||||
""");
|
||||
|
||||
var annotation1 = (IR$Name$Annotation) ir.bindings().apply(0);
|
||||
var annotation2 = (IR$Name$Annotation) ir.bindings().apply(1);
|
||||
|
||||
assertEquals(annotation1.name(), "a");
|
||||
assertEquals(annotation2.name(), "b");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtensionMethod() throws Exception {
|
||||
var ir = parse("""
|
||||
@a expr
|
||||
@b (x y)
|
||||
Foo.foo a b = a b
|
||||
""");
|
||||
|
||||
var annotation1 = (IR$Name$Annotation) ir.bindings().apply(0);
|
||||
var annotation2 = (IR$Name$Annotation) ir.bindings().apply(1);
|
||||
|
||||
assertEquals(annotation1.name(), "a");
|
||||
assertEquals(annotation2.name(), "b");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTypeMethod() throws Exception {
|
||||
var ir = parse("""
|
||||
type Foo
|
||||
@a foo
|
||||
@b bar
|
||||
method a b = a b
|
||||
""");
|
||||
|
||||
var typeDefinition = (IR$Module$Scope$Definition$SugaredType) ir.bindings().apply(0);
|
||||
|
||||
var annotation1 = (IR$Name$Annotation) typeDefinition.body().apply(0);
|
||||
var annotation2 = (IR$Name$Annotation) typeDefinition.body().apply(1);
|
||||
var function = (IR$Function$Binding) typeDefinition.body().apply(2);
|
||||
|
||||
assertEquals(annotation1.name(), "a");
|
||||
assertEquals(annotation2.name(), "b");
|
||||
assertEquals(function.name().name(), "method");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructor() throws Exception {
|
||||
var ir = parse("""
|
||||
type Foo
|
||||
@a foo
|
||||
@b bar
|
||||
Cons a b = a b
|
||||
""");
|
||||
|
||||
var typeDefinition = (IR$Module$Scope$Definition$SugaredType) ir.bindings().apply(0);
|
||||
|
||||
var annotation1 = (IR$Name$Annotation) typeDefinition.body().apply(0);
|
||||
var annotation2 = (IR$Name$Annotation) typeDefinition.body().apply(1);
|
||||
var constructor = (IR$Module$Scope$Definition$Data) typeDefinition.body().apply(2);
|
||||
|
||||
assertEquals(annotation1.name(), "a");
|
||||
assertEquals(annotation2.name(), "b");
|
||||
assertEquals(constructor.name().name(), "Cons");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidComplexType() throws Exception {
|
||||
var ir = parse("""
|
||||
type Foo
|
||||
bar a =
|
||||
""");
|
||||
|
||||
var typeDefinition = (IR$Module$Scope$Definition$SugaredType) ir.bindings().apply(0);
|
||||
var method = (IR$Function$Binding) typeDefinition.body().apply(0);
|
||||
|
||||
assertEquals(method.name().name(), "bar");
|
||||
// FIXME method body is null. Should be `IR.Error.Syntax.UnexpectedDeclarationInType`
|
||||
assertEquals(method.body(), null);
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package org.enso.compiler;
|
||||
|
||||
import com.oracle.truffle.api.source.Source;
|
||||
import org.enso.compiler.core.IR;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
public abstract class CompilerTest {
|
||||
|
||||
protected static EnsoCompiler ensoCompiler;
|
||||
|
||||
@BeforeClass
|
||||
public static void initEnsoCompiler() {
|
||||
ensoCompiler = new EnsoCompiler();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void closeEnsoCompiler() throws Exception {
|
||||
ensoCompiler.close();
|
||||
}
|
||||
|
||||
protected static IR.Module parse(String code) throws IOException {
|
||||
var src =
|
||||
Source.newBuilder("enso", code, "test-" + Integer.toHexString(code.hashCode()) + ".enso")
|
||||
.build();
|
||||
IR.Module ir = ensoCompiler.compile(src);
|
||||
assertNotNull("IR was generated", ir);
|
||||
return ir;
|
||||
}
|
||||
}
|
@ -1229,7 +1229,6 @@ public class EnsoCompilerTest {
|
||||
equivalenceTest("a = x", "a = SKIP FREEZE x + y");
|
||||
equivalenceTest("a = x", "a = SKIP FREEZE x.f");
|
||||
equivalenceTest("a = x", "a = SKIP FREEZE x.f y");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1,9 +1,5 @@
|
||||
package org.enso.compiler;
|
||||
|
||||
import com.oracle.truffle.api.source.Source;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.enso.compiler.core.IR;
|
||||
import org.enso.compiler.core.IR$Error$Syntax;
|
||||
import org.enso.compiler.core.IR$Error$Syntax$InvalidEscapeSequence$;
|
||||
@ -14,42 +10,28 @@ import org.enso.compiler.core.IR$Error$Syntax$UnrecognizedToken$;
|
||||
import org.enso.compiler.core.IR$Error$Syntax$UnsupportedSyntax;
|
||||
import org.enso.syntax.text.Location;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import scala.collection.immutable.List;
|
||||
|
||||
public class ErrorCompilerTest {
|
||||
private static EnsoCompiler ensoCompiler;
|
||||
|
||||
@BeforeClass
|
||||
public static void initEnsoCompiler() {
|
||||
ensoCompiler = new EnsoCompiler();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void closeEnsoCompiler() throws Exception {
|
||||
ensoCompiler.close();
|
||||
}
|
||||
public class ErrorCompilerTest extends CompilerTest {
|
||||
|
||||
@Test
|
||||
public void spaceRequired() throws Exception {
|
||||
var ir = parseTest("foo = if cond.x else.y");
|
||||
var ir = parse("foo = if cond.x else.y");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 6, 8);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incompleteTypeDefinition() throws Exception {
|
||||
var ir = parseTest("type");
|
||||
var ir = parse("type");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 0, 4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void badCase1() throws Exception {
|
||||
var ir = parseTest("""
|
||||
var ir = parse("""
|
||||
foo = case x of
|
||||
4
|
||||
""");
|
||||
@ -58,7 +40,7 @@ public class ErrorCompilerTest {
|
||||
|
||||
@Test
|
||||
public void badCase2() throws Exception {
|
||||
var ir = parseTest("""
|
||||
var ir = parse("""
|
||||
foo = case x of
|
||||
4 ->
|
||||
""");
|
||||
@ -67,7 +49,7 @@ public class ErrorCompilerTest {
|
||||
|
||||
@Test
|
||||
public void badCase3() throws Exception {
|
||||
var ir = parseTest("""
|
||||
var ir = parse("""
|
||||
foo = case x of
|
||||
4->
|
||||
""");
|
||||
@ -76,7 +58,7 @@ public class ErrorCompilerTest {
|
||||
|
||||
@Test
|
||||
public void badCase4() throws Exception {
|
||||
var ir = parseTest("""
|
||||
var ir = parse("""
|
||||
main =
|
||||
case value of
|
||||
-1 ->"minus one"
|
||||
@ -86,253 +68,253 @@ public class ErrorCompilerTest {
|
||||
|
||||
@Test
|
||||
public void malformedSequence1() throws Exception {
|
||||
var ir = parseTest("(1, )");
|
||||
var ir = parse("(1, )");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 0, 5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedSequence2() throws Exception {
|
||||
var ir = parseTest("foo = (1, )");
|
||||
var ir = parse("foo = (1, )");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 7, 9);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unmatchedDemiliter1() throws Exception {
|
||||
var ir = parseTest("(");
|
||||
var ir = parse("(");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 0, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unmatchedDemiliter2() throws Exception {
|
||||
var ir = parseTest(")");
|
||||
var ir = parse(")");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 0, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unmatchedDemiliter3() throws Exception {
|
||||
var ir = parseTest("[");
|
||||
var ir = parse("[");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 0, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unmatchedDemiliter4() throws Exception {
|
||||
var ir = parseTest("[");
|
||||
var ir = parse("[");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 0, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unmatchedDemiliter5() throws Exception {
|
||||
var ir = parseTest("foo = (");
|
||||
var ir = parse("foo = (");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 6, 7);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unmatchedDemiliter6() throws Exception {
|
||||
var ir = parseTest("foo = )");
|
||||
var ir = parse("foo = )");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 6, 7);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unmatchedDemiliter7() throws Exception {
|
||||
var ir = parseTest("foo = [");
|
||||
var ir = parse("foo = [");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 6, 7);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unmatchedDemiliter8() throws Exception {
|
||||
var ir = parseTest("foo = ]");
|
||||
var ir = parse("foo = ]");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 6, 7);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unexpectedSpecialOperator() throws Exception {
|
||||
var ir = parseTest("foo = 1, 2");
|
||||
var ir = parse("foo = 1, 2");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 6, 10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedImport1() throws Exception {
|
||||
var ir = parseTest("import");
|
||||
var ir = parse("import");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 0, 6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedImport2() throws Exception {
|
||||
var ir = parseTest("import as Foo");
|
||||
var ir = parse("import as Foo");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 0, 13);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedImport3() throws Exception {
|
||||
var ir = parseTest("import Foo as Foo, Bar");
|
||||
var ir = parse("import Foo as Foo, Bar");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$InvalidImport$.MODULE$, "Imports must have a valid module path.", 14, 22);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedImport4() throws Exception {
|
||||
var ir = parseTest("import Foo as Foo.Bar");
|
||||
var ir = parse("import Foo as Foo.Bar");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$InvalidImport$.MODULE$, "Imports must have a valid module path.", 14, 21);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedImport5() throws Exception {
|
||||
var ir = parseTest("import Foo as");
|
||||
var ir = parse("import Foo as");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$InvalidImport$.MODULE$, "Imports must have a valid module path.", 13, 13);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedImport6() throws Exception {
|
||||
var ir = parseTest("import Foo as Bar.Baz");
|
||||
var ir = parse("import Foo as Bar.Baz");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$InvalidImport$.MODULE$, "Imports must have a valid module path.", 14, 21);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedImport7() throws Exception {
|
||||
var ir = parseTest("import Foo hiding");
|
||||
var ir = parse("import Foo hiding");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$InvalidImport$.MODULE$, "Imports must have a valid module path.", 17, 17);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedImport8() throws Exception {
|
||||
var ir = parseTest("import Foo hiding X,");
|
||||
var ir = parse("import Foo hiding X,");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$InvalidImport$.MODULE$, "Imports must have a valid module path.", 18, 20);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedImport9() throws Exception {
|
||||
var ir = parseTest("polyglot import Foo");
|
||||
var ir = parse("polyglot import Foo");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnrecognizedToken$.MODULE$, "Unrecognized token.", 0, 19);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedImport10() throws Exception {
|
||||
var ir = parseTest("polyglot java import");
|
||||
var ir = parse("polyglot java import");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 0, 20);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedImport11() throws Exception {
|
||||
var ir = parseTest("from import all");
|
||||
var ir = parse("from import all");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$InvalidImport$.MODULE$, "Imports must have a valid module path.", 4, 4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedImport12() throws Exception {
|
||||
var ir = parseTest("from Foo import all hiding");
|
||||
var ir = parse("from Foo import all hiding");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$InvalidImport$.MODULE$, "Imports must have a valid module path.", 26, 26);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedImport13() throws Exception {
|
||||
var ir = parseTest("from Foo import all hiding X.Y");
|
||||
var ir = parse("from Foo import all hiding X.Y");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$InvalidImport$.MODULE$, "Imports must have a valid module path.", 27, 30);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedExport1() throws Exception {
|
||||
var ir = parseTest("export");
|
||||
var ir = parse("export");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 0, 6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedExport2() throws Exception {
|
||||
var ir = parseTest("export as Foo");
|
||||
var ir = parse("export as Foo");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 0, 13);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedExport3() throws Exception {
|
||||
var ir = parseTest("export Foo as Foo, Bar");
|
||||
var ir = parse("export Foo as Foo, Bar");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$InvalidImport$.MODULE$, "Imports must have a valid module path.", 14, 22);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedExport4() throws Exception {
|
||||
var ir = parseTest("export Foo as Foo.Bar");
|
||||
var ir = parse("export Foo as Foo.Bar");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$InvalidImport$.MODULE$, "Imports must have a valid module path.", 14, 21);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedExport5() throws Exception {
|
||||
var ir = parseTest("export Foo as");
|
||||
var ir = parse("export Foo as");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$InvalidImport$.MODULE$, "Imports must have a valid module path.", 13, 13);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedExport6() throws Exception {
|
||||
var ir = parseTest("export Foo as Bar.Baz");
|
||||
var ir = parse("export Foo as Bar.Baz");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$InvalidImport$.MODULE$, "Imports must have a valid module path.", 14, 21);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedExport7() throws Exception {
|
||||
var ir = parseTest("export Foo hiding");
|
||||
var ir = parse("export Foo hiding");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$InvalidImport$.MODULE$, "Imports must have a valid module path.", 7, 17);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedExport8() throws Exception {
|
||||
var ir = parseTest("export Foo hiding X,");
|
||||
var ir = parse("export Foo hiding X,");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$InvalidImport$.MODULE$, "Imports must have a valid module path.", 7, 20);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedExport9() throws Exception {
|
||||
var ir = parseTest("from export all");
|
||||
var ir = parse("from export all");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$InvalidImport$.MODULE$, "Imports must have a valid module path.", 4, 4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedExport10() throws Exception {
|
||||
var ir = parseTest("from Foo export all hiding");
|
||||
var ir = parse("from Foo export all hiding");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$InvalidImport$.MODULE$, "Imports must have a valid module path.", 26, 26);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void malformedExport11() throws Exception {
|
||||
var ir = parseTest("from Foo export all hiding X.Y");
|
||||
var ir = parse("from Foo export all hiding X.Y");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$InvalidImport$.MODULE$, "Imports must have a valid module path.", 27, 30);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidToken1() throws Exception {
|
||||
var ir = parseTest("`");
|
||||
var ir = parse("`");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 0, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidToken2() throws Exception {
|
||||
var ir = parseTest("splice_outside_text = `");
|
||||
var ir = parse("splice_outside_text = `");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 22, 23);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void illegalForeignBody1() throws Exception {
|
||||
var ir = parseTest("foreign 4");
|
||||
var ir = parse("foreign 4");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 0, 9);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void illegalForeignBody2() throws Exception {
|
||||
var ir = parseTest("foreign 4 * 4");
|
||||
var ir = parse("foreign 4 * 4");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 0, 13);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void illegalForeignBody3() throws Exception {
|
||||
var ir = parseTest("foreign foo = \"4\"");
|
||||
var ir = parse("foreign foo = \"4\"");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 0, 17);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void illegalForeignBody4() throws Exception {
|
||||
var ir = parseTest("foreign js foo = 4");
|
||||
var ir = parse("foreign js foo = 4");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$UnexpectedExpression$.MODULE$, "Unexpected expression.", 0, 18);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void illegalEscapeSequence() throws Exception {
|
||||
var ir = parseTest("""
|
||||
var ir = parse("""
|
||||
escape = 'wrong \\c sequence'
|
||||
""");
|
||||
assertSingleSyntaxError(ir, IR$Error$Syntax$InvalidEscapeSequence$.MODULE$.apply("wrong sequence"), "Invalid escape sequence wrong sequence.", 9, 28);
|
||||
@ -340,7 +322,7 @@ public class ErrorCompilerTest {
|
||||
|
||||
@Test
|
||||
public void testNPE183814303() throws Exception {
|
||||
var ir = parseTest("""
|
||||
var ir = parse("""
|
||||
from Standard.Base import all
|
||||
|
||||
main =
|
||||
@ -353,7 +335,7 @@ public class ErrorCompilerTest {
|
||||
|
||||
@Test
|
||||
public void testNPE183863754() throws Exception {
|
||||
var ir = parseTest("""
|
||||
var ir = parse("""
|
||||
main =
|
||||
# meh
|
||||
42
|
||||
@ -380,13 +362,4 @@ public class ErrorCompilerTest {
|
||||
assertEquals("Expecting errors: " + errors, count, errors.size());
|
||||
return errors;
|
||||
}
|
||||
|
||||
private static IR.Module parseTest(String code) throws IOException {
|
||||
var src =
|
||||
Source.newBuilder("enso", code, "test-" + Integer.toHexString(code.hashCode()) + ".enso")
|
||||
.build();
|
||||
var ir = ensoCompiler.compile(src);
|
||||
assertNotNull("IR was generated", ir);
|
||||
return ir;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.enso.compiler.test
|
||||
|
||||
import org.enso.compiler.EnsoCompiler
|
||||
import org.enso.compiler.codegen.AstToIr
|
||||
import org.enso.compiler.context.{FreshNameSupply, InlineContext, ModuleContext}
|
||||
import org.enso.compiler.core.IR
|
||||
@ -18,6 +19,8 @@ import org.enso.pkg.QualifiedName
|
||||
trait CompilerTest extends AnyWordSpecLike with Matchers with CompilerRunner
|
||||
trait CompilerRunner {
|
||||
|
||||
def useRustParser: Boolean = false
|
||||
|
||||
// === IR Utilities =========================================================
|
||||
|
||||
/** Adds an extension method for converting a string to its AST
|
||||
@ -61,7 +64,13 @@ trait CompilerRunner {
|
||||
* @return the [[IR]] representing [[source]]
|
||||
*/
|
||||
def toIrModule: IR.Module = {
|
||||
AstToIr.translate(source.toAst)
|
||||
if (useRustParser) {
|
||||
val compiler = new EnsoCompiler()
|
||||
try compiler.compile(source)
|
||||
finally compiler.close()
|
||||
} else {
|
||||
AstToIr.translate(source.toAst)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,6 +217,7 @@ trait CompilerRunner {
|
||||
None
|
||||
)
|
||||
),
|
||||
List(),
|
||||
None
|
||||
)
|
||||
}
|
||||
|
@ -1041,7 +1041,7 @@ class AstToIrTest extends CompilerTest with Inside {
|
||||
|type Foo a b
|
||||
|""".stripMargin.toIrModule
|
||||
|
||||
ir.bindings.head shouldBe an[IR.Name.Annotation]
|
||||
ir.bindings.head shouldBe an[IR.Name.BuiltinAnnotation]
|
||||
ir.bindings(1) shouldBe an[IR.Module.Scope.Definition.SugaredType]
|
||||
}
|
||||
|
||||
@ -1059,8 +1059,8 @@ class AstToIrTest extends CompilerTest with Inside {
|
||||
val complexType =
|
||||
ir.bindings.head.asInstanceOf[IR.Module.Scope.Definition.SugaredType]
|
||||
|
||||
complexType.body.head shouldBe an[IR.Name.Annotation]
|
||||
complexType.body(2) shouldBe an[IR.Name.Annotation]
|
||||
complexType.body.head shouldBe an[IR.Name.BuiltinAnnotation]
|
||||
complexType.body(2) shouldBe an[IR.Name.BuiltinAnnotation]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,8 @@ class ModuleAnnotationsTest extends CompilerTest {
|
||||
|
||||
// === Test Setup ===========================================================
|
||||
|
||||
override val useRustParser = true
|
||||
|
||||
val passes = new Passes(defaultConfig)
|
||||
|
||||
val precursorPasses: PassGroup = passes.getPrecursors(ModuleAnnotations).get
|
||||
@ -115,60 +117,62 @@ class ModuleAnnotationsTest extends CompilerTest {
|
||||
anns.length shouldEqual 1
|
||||
anns.head.asInstanceOf[IR.Name].name shouldEqual "@My_Annotation"
|
||||
}
|
||||
|
||||
"not associate generic annotations with method definitions" in {
|
||||
val ir =
|
||||
"""@a expr_1
|
||||
|@b expr_2
|
||||
|My_Type.add a b = this.frob(a + b)
|
||||
|""".stripMargin.preprocessModule.resolve
|
||||
|
||||
ir.bindings.length shouldEqual 3
|
||||
ir.bindings(0) shouldBe a[IR.Name.GenericAnnotation]
|
||||
ir.bindings(1) shouldBe a[IR.Name.GenericAnnotation]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
"Annotation desugaring in complex types" should {
|
||||
implicit val moduleContext: ModuleContext = mkModuleContext
|
||||
|
||||
"associate annotations with atom definitions" in {
|
||||
"not associate generic annotations with atom definitions" in {
|
||||
val ir =
|
||||
"""@My_Annotation
|
||||
|type Foo
|
||||
| @My_Annotation
|
||||
| @my annotation
|
||||
| Bar
|
||||
|""".stripMargin.preprocessModule.resolve
|
||||
|
||||
ir.bindings.length shouldEqual 1
|
||||
ir.bindings.head shouldBe a[Definition.SugaredType]
|
||||
val typ = ir.bindings.head.asInstanceOf[Definition.SugaredType]
|
||||
typ.body.length shouldEqual 1
|
||||
typ.body.head shouldBe a[Definition.Data]
|
||||
typ.body.head
|
||||
.unsafeGetMetadata(ModuleAnnotations, "")
|
||||
.annotations
|
||||
.head
|
||||
.asInstanceOf[IR.Name]
|
||||
.name shouldEqual "@My_Annotation"
|
||||
typ.body.length shouldEqual 2
|
||||
typ.body(0) shouldBe an[IR.Name.GenericAnnotation]
|
||||
typ.body(1) shouldBe a[Definition.Data]
|
||||
}
|
||||
|
||||
"associate annotations with method definitions" in {
|
||||
"not associate generic annotations with method definitions" in {
|
||||
val ir =
|
||||
"""type Foo
|
||||
| Foo
|
||||
|
|
||||
| @My_Annotation
|
||||
| @a expr
|
||||
| my_method a = a
|
||||
|""".stripMargin.preprocessModule.resolve
|
||||
|
||||
ir.bindings.length shouldEqual 1
|
||||
ir.bindings.head shouldBe a[Definition.SugaredType]
|
||||
val typ = ir.bindings.head.asInstanceOf[Definition.SugaredType]
|
||||
typ.body.length shouldEqual 2
|
||||
typ.body(1) shouldBe an[IR.Function.Binding]
|
||||
typ
|
||||
.body(1)
|
||||
.unsafeGetMetadata(ModuleAnnotations, "")
|
||||
.annotations
|
||||
.head
|
||||
.asInstanceOf[IR.Name]
|
||||
.name shouldEqual "@My_Annotation"
|
||||
typ.body.length shouldEqual 3
|
||||
typ.body(1) shouldBe an[IR.Name.GenericAnnotation]
|
||||
typ.body(2) shouldBe an[IR.Function.Binding]
|
||||
}
|
||||
|
||||
"not associate annotations with comments" in {
|
||||
val ir =
|
||||
"""
|
||||
|type Foo
|
||||
| @My_Annotation
|
||||
| @my annotation
|
||||
| ## Doc comment
|
||||
| Foo
|
||||
|""".stripMargin.preprocessModule.resolve
|
||||
@ -176,16 +180,10 @@ class ModuleAnnotationsTest extends CompilerTest {
|
||||
ir.bindings.length shouldEqual 1
|
||||
ir.bindings.head shouldBe a[Definition.SugaredType]
|
||||
val typ = ir.bindings.head.asInstanceOf[Definition.SugaredType]
|
||||
typ.body.length shouldEqual 2
|
||||
typ.body.head shouldBe an[IR.Comment]
|
||||
typ.body(1) shouldBe a[Definition.Data]
|
||||
typ
|
||||
.body(1)
|
||||
.unsafeGetMetadata(ModuleAnnotations, "")
|
||||
.annotations
|
||||
.head
|
||||
.asInstanceOf[IR.Name]
|
||||
.name shouldEqual "@My_Annotation"
|
||||
typ.body.length shouldEqual 3
|
||||
typ.body(0) shouldBe an[IR.Name.GenericAnnotation]
|
||||
typ.body(1) shouldBe an[IR.Comment]
|
||||
typ.body(2) shouldBe a[Definition.Data]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,10 +14,27 @@ import Standard.Test.Extensions
|
||||
from Standard.Base.Error.Common import Uninitialized_State
|
||||
|
||||
type My_Type
|
||||
@foo (test_method)
|
||||
@baz (My_Type.Value 1 2 3)
|
||||
Value foo bar baz
|
||||
|
||||
@param (test_method 5 6)
|
||||
first_method self param = param
|
||||
|
||||
second_method self param = param
|
||||
|
||||
@a (test_method 5)
|
||||
@b (self -> self.foo)
|
||||
other_method self a = a
|
||||
|
||||
@self ("se" + "lf")
|
||||
My_Type.my_method self = self.foo + self.bar + self.baz
|
||||
|
||||
@a (test_method 3 4)
|
||||
@b (Test_Type.Value 49)
|
||||
@c (Error.throw "Error Value")
|
||||
test_method a b = a + b
|
||||
|
||||
type Test_Type
|
||||
Value x
|
||||
|
||||
@ -172,6 +189,26 @@ spec =
|
||||
(Test_Type.Value a)==(Test_Type.Value b) . should_be_true
|
||||
(Test_Type.Value a)==(Test_Type.Value c) . should_be_false
|
||||
|
||||
Test.specify "get annotations" <|
|
||||
Meta.get_annotation Meta_Spec "test_method" "a" . should_equal 7
|
||||
Meta.get_annotation Meta_Spec "test_method" "b" . should_equal (Test_Type.Value 49)
|
||||
Meta.get_annotation Meta_Spec "test_method" "c" . should_fail_with "Error Value"
|
||||
Meta.get_annotation Meta_Spec "test_method" "x" . should_equal Nothing
|
||||
|
||||
value = My_Type.Value 99 "bar" True
|
||||
Meta.get_annotation value "first_method" "param" . should_equal 11
|
||||
Meta.get_annotation value "second_method" "param" . should_equal Nothing
|
||||
Meta.get_annotation value "third_method" "param" . should_equal Nothing
|
||||
Meta.get_annotation value "other_method" "a" 7 . should_equal 12
|
||||
Meta.get_annotation value "other_method" "b" value . should_equal 99
|
||||
Meta.get_annotation value "other_method" "c" . should_equal Nothing
|
||||
|
||||
Meta.get_annotation value "my_method" "self" . should_equal "self"
|
||||
|
||||
Meta.get_annotation value "Value" "foo" 7 8 . should_equal 15
|
||||
Meta.get_annotation value "Value" "bar" . should_equal Nothing
|
||||
Meta.get_annotation value "Value" "baz" . should_equal (My_Type.Value 1 2 3)
|
||||
|
||||
Test.group "Atom with holes" <|
|
||||
Test.specify "construct and fill" <|
|
||||
pair = Meta.atom_with_hole (e -> My_Type.Value 1 e 3)
|
||||
|
Loading…
Reference in New Issue
Block a user