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:
Dmitry Bushev 2023-01-24 21:28:33 +03:00 committed by GitHub
parent 5b5a2be829
commit bf9508603f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 1072 additions and 368 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
*/

View File

@ -75,6 +75,7 @@ final class SuggestionBuilder[A: IndexedSource](
arguments,
_,
_,
_,
_
) =>
buildAtomConstructor(

View File

@ -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
@ -1095,12 +1099,20 @@ object IR {
def copy(
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
}
@ -1143,16 +1155,18 @@ object IR {
override def mapExpressions(fn: Expression => Expression): Data = {
copy(
name = name.mapExpressions(fn),
arguments = arguments.map(_.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)
}

View File

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

View File

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

View File

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

View File

@ -117,11 +117,12 @@ 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 ann: IR.Name.GenericAnnotation => ann
case err: IR.Error => err
}

View File

@ -149,12 +149,11 @@ 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 newMembers = members.map { data =>
val dataDep = asStatic(data)
info.dependents.updateAt(dataDep, Set(tpDep))
info.dependencies.updateAt(tpDep, Set(dataDep))
arguments.foreach(arg => {
data.arguments.foreach(arg => {
val argDep = asStatic(arg)
info.dependents.updateAt(argDep, Set(dataDep))
info.dependencies.updateAt(dataDep, Set(argDep))
@ -162,7 +161,7 @@ case object DataflowAnalysis extends IRPass {
data
.copy(
arguments = arguments.map(analyseDefinitionArgument(_, info))
arguments = data.arguments.map(analyseDefinitionArgument(_, info))
)
.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
}
}

View File

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

View File

@ -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)
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
}
@ -186,6 +198,7 @@ case object ComplexType extends IRPass {
case funSugar @ IR.Function.Binding(name, _, _, _, _, _, _) =>
matchSignaturesAndGenerate(name, funSugar)
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],

View File

@ -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,11 +317,12 @@ 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.Name.GenericAnnotation => a
case a: IR.Type.Ascription => a
case e: IR.Error => e
}

View File

@ -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
@ -161,7 +161,8 @@ case object DocumentationComments extends IRPass {
case doc: IR.Comment.Documentation => doc
case tySig: IR.Type.Ascription => tySig
case err: IR.Error => err
case _: IR.Name.Annotation =>
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."

View File

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

View File

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

View File

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

View File

@ -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.
*/
@ -42,11 +40,12 @@ 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 =>
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(
@ -63,7 +62,6 @@ case object ModuleAnnotations extends IRPass {
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(
@ -103,12 +103,12 @@ case object ModuleAnnotations 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

View File

@ -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,31 +45,33 @@ 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
case tp: IR.Module.Scope.Definition.Type =>
tp
}
ir.bindings.collect {
case meth: IR.Module.Scope.Definition.Method.Explicit =>
seenMethods += meth.typeName.map(_.name) -> Set()
meth
}
val conversionsForType: mutable.Map[Option[String], Set[String]] =
mutable.Map()
val newTypes: List[IR.Module.Scope.Definition] = types.map(tp => {
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 = seenTypes + tp.name.name
seenTypes += tp.name.name
tp
}
})
val methods = ir.bindings.collect {
case meth: IR.Module.Scope.Definition.Method.Explicit =>
seenMethods = seenMethods + (meth.typeName.map(_.name) -> Set())
meth
}
val newMethods: List[IR.Module.Scope.Definition] = methods.map(method => {
case method: IR.Module.Scope.Definition.Method.Explicit =>
if (
seenMethods(method.typeName.map(_.name))
.contains((method.methodName.name, method.isStatic))
@ -87,17 +89,12 @@ case object OverloadsResolution extends IRPass {
case _ =>
val currentMethods: Set[(String, Boolean)] =
seenMethods(method.typeName.map(_.name))
seenMethods = seenMethods + (method.typeName.map(_.name) ->
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 {
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
}
}
val diagnostics = ir.bindings.collect { case diag: IR.Diagnostic =>
diag
}
ir.copy(
bindings = newTypes ::: newMethods ::: conversions ::: diagnostics
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."
)
}
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
}

View File

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

View File

@ -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 {
@ -134,12 +132,13 @@ case object TypeSignatures extends IRPass {
case ut: IR.Module.Scope.Definition.Type =>
Some(ut.mapExpressions(resolveExpression))
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

View File

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

View File

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

View File

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

View File

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

View File

@ -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,9 +64,15 @@ trait CompilerRunner {
* @return the [[IR]] representing [[source]]
*/
def toIrModule: IR.Module = {
if (useRustParser) {
val compiler = new EnsoCompiler()
try compiler.compile(source)
finally compiler.close()
} else {
AstToIr.translate(source.toAst)
}
}
}
/** An extension method to allow converting string source code to IR as an
* expression.
@ -208,6 +217,7 @@ trait CompilerRunner {
None
)
),
List(),
None
)
}

View File

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

View File

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

View File

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