mirror of
https://github.com/enso-org/enso.git
synced 2024-11-26 08:52:58 +03:00
Qualified names & uppercase name resolution (#1062)
This commit is contained in:
parent
c64298cb8e
commit
ddb43af5a2
@ -398,7 +398,12 @@ need to follow these steps:
|
|||||||
and add them to `truffleRunOptions` in [`build.sbt`](build.sbt). Remove the
|
and add them to `truffleRunOptions` in [`build.sbt`](build.sbt). Remove the
|
||||||
portion of these options after `suspend=y`, including the comma. They are
|
portion of these options after `suspend=y`, including the comma. They are
|
||||||
placeholders that we don't use.
|
placeholders that we don't use.
|
||||||
6. Now, when you want to debug something, you can place a breakpoint as usual in
|
6. Alternatively, certain tasks, such as `run`, `benchOnly` and `testOnly` can
|
||||||
|
be used through the `withDebug` SBT command. For this to work, your remote
|
||||||
|
configuration must specify the host of `localhost` and the port `5005`.
|
||||||
|
The command syntax is `withDebug --debugger TASK_NAME -- TASK_PARAMETERS`,
|
||||||
|
e.g. `withDebug --debugger testOnly -- *AtomConstructors*`.
|
||||||
|
7. Now, when you want to debug something, you can place a breakpoint as usual in
|
||||||
IntelliJ, and then execute your remote debugging configuration. Now, in the
|
IntelliJ, and then execute your remote debugging configuration. Now, in the
|
||||||
SBT shell, run a command to execute the code you want to debug (e.g.
|
SBT shell, run a command to execute the code you want to debug (e.g.
|
||||||
`testOnly *CurryingTest*`). This will open the standard debugger interface
|
`testOnly *CurryingTest*`). This will open the standard debugger interface
|
||||||
|
@ -25,6 +25,12 @@ public class AtomBenchmarks {
|
|||||||
main.mainFunction().value().execute(main.mainConstructor(), fixtures.million());
|
main.mainFunction().value().execute(main.mainConstructor(), fixtures.million());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void benchGenerateListQualified() {
|
||||||
|
DefaultInterpreterRunner.MainMethod main = fixtures.generateListQualified();
|
||||||
|
main.mainFunction().value().execute(main.mainConstructor(), fixtures.million());
|
||||||
|
}
|
||||||
|
|
||||||
private void benchOnList(DefaultInterpreterRunner.MainMethod main) {
|
private void benchOnList(DefaultInterpreterRunner.MainMethod main) {
|
||||||
main.mainFunction().value().execute(main.mainConstructor(), fixtures.millionElementList());
|
main.mainFunction().value().execute(main.mainConstructor(), fixtures.millionElementList());
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,16 @@ class AtomFixtures extends DefaultInterpreterRunner {
|
|||||||
""".stripMargin
|
""".stripMargin
|
||||||
val generateList = getMain(generateListCode)
|
val generateList = getMain(generateListCode)
|
||||||
|
|
||||||
|
val generateListQualifiedCode =
|
||||||
|
"""
|
||||||
|
|main = length ->
|
||||||
|
| generator = acc -> i -> if i == 0 then acc else generator (Builtins.cons i acc) (i - 1)
|
||||||
|
|
|
||||||
|
| res = generator Builtins.nil length
|
||||||
|
| res
|
||||||
|
""".stripMargin
|
||||||
|
val generateListQualified = getMain(generateListQualifiedCode)
|
||||||
|
|
||||||
val reverseListCode =
|
val reverseListCode =
|
||||||
"""
|
"""
|
||||||
|main = list ->
|
|main = list ->
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
package org.enso.interpreter.node.expression.atom;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.TruffleLanguage;
|
||||||
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
|
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||||
|
import com.oracle.truffle.api.nodes.RootNode;
|
||||||
|
import org.enso.interpreter.runtime.callable.atom.Atom;
|
||||||
|
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
|
||||||
|
import org.enso.interpreter.runtime.callable.function.Function;
|
||||||
|
import org.enso.interpreter.runtime.state.Stateful;
|
||||||
|
|
||||||
|
@NodeInfo(
|
||||||
|
shortName = "get_cons",
|
||||||
|
description = "A base for auto-generated module-level atom constructor getters.")
|
||||||
|
public class QualifiedAccessorNode extends RootNode {
|
||||||
|
private final AtomConstructor atomConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of this node.
|
||||||
|
*
|
||||||
|
* @param language the current language instance.
|
||||||
|
* @param atomConstructor the constructor to return.
|
||||||
|
*/
|
||||||
|
public QualifiedAccessorNode(TruffleLanguage<?> language, AtomConstructor atomConstructor) {
|
||||||
|
super(language);
|
||||||
|
this.atomConstructor = atomConstructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the node, returning the predefined constructor.
|
||||||
|
*
|
||||||
|
* @param frame current execution frame
|
||||||
|
* @return the constant constructor
|
||||||
|
*/
|
||||||
|
public Stateful execute(VirtualFrame frame) {
|
||||||
|
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
|
||||||
|
return new Stateful(state, atomConstructor);
|
||||||
|
}
|
||||||
|
}
|
@ -323,7 +323,7 @@ public class Module implements TruffleObject {
|
|||||||
Types.extractArguments(args, AtomConstructor.class, String.class);
|
Types.extractArguments(args, AtomConstructor.class, String.class);
|
||||||
AtomConstructor cons = arguments.getFirst();
|
AtomConstructor cons = arguments.getFirst();
|
||||||
String name = arguments.getSecond();
|
String name = arguments.getSecond();
|
||||||
return scope.getMethods().get(cons).get(name);
|
return scope.getMethods().get(cons).get(name.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AtomConstructor getConstructor(ModuleScope scope, Object[] args)
|
private static AtomConstructor getConstructor(ModuleScope scope, Object[] args)
|
||||||
|
@ -13,6 +13,7 @@ import org.enso.interpreter.node.ExpressionNode;
|
|||||||
import org.enso.interpreter.node.callable.argument.ReadArgumentNode;
|
import org.enso.interpreter.node.callable.argument.ReadArgumentNode;
|
||||||
import org.enso.interpreter.node.expression.atom.GetFieldNode;
|
import org.enso.interpreter.node.expression.atom.GetFieldNode;
|
||||||
import org.enso.interpreter.node.expression.atom.InstantiateNode;
|
import org.enso.interpreter.node.expression.atom.InstantiateNode;
|
||||||
|
import org.enso.interpreter.node.expression.atom.QualifiedAccessorNode;
|
||||||
import org.enso.interpreter.node.expression.builtin.InstantiateAtomNode;
|
import org.enso.interpreter.node.expression.builtin.InstantiateAtomNode;
|
||||||
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
|
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
|
||||||
import org.enso.interpreter.runtime.callable.function.Function;
|
import org.enso.interpreter.runtime.callable.function.Function;
|
||||||
@ -82,11 +83,26 @@ public class AtomConstructor implements TruffleObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void generateMethods(ArgumentDefinition[] args) {
|
private void generateMethods(ArgumentDefinition[] args) {
|
||||||
|
generateQualifiedAccessor();
|
||||||
for (ArgumentDefinition arg : args) {
|
for (ArgumentDefinition arg : args) {
|
||||||
definitionScope.registerMethod(this, arg.getName(), generateGetter(arg.getPosition()));
|
definitionScope.registerMethod(this, arg.getName(), generateGetter(arg.getPosition()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void generateQualifiedAccessor() {
|
||||||
|
QualifiedAccessorNode node = new QualifiedAccessorNode(null, this);
|
||||||
|
RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(node);
|
||||||
|
Function function =
|
||||||
|
new Function(
|
||||||
|
callTarget,
|
||||||
|
null,
|
||||||
|
new FunctionSchema(
|
||||||
|
FunctionSchema.CallStrategy.ALWAYS_DIRECT,
|
||||||
|
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE)));
|
||||||
|
definitionScope.registerMethod(
|
||||||
|
definitionScope.getAssociatedType(), this.name.toLowerCase(), function);
|
||||||
|
}
|
||||||
|
|
||||||
private Function generateGetter(int position) {
|
private Function generateGetter(int position) {
|
||||||
GetFieldNode node = new GetFieldNode(null, position);
|
GetFieldNode node = new GetFieldNode(null, position);
|
||||||
RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(node);
|
RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(node);
|
||||||
|
@ -105,6 +105,7 @@ public class ModuleScope {
|
|||||||
* @param function the {@link Function} associated with this definition
|
* @param function the {@link Function} associated with this definition
|
||||||
*/
|
*/
|
||||||
public void registerMethod(AtomConstructor atom, String method, Function function) {
|
public void registerMethod(AtomConstructor atom, String method, Function function) {
|
||||||
|
method = method.toLowerCase();
|
||||||
Map<String, Function> methodMap = ensureMethodMapFor(atom);
|
Map<String, Function> methodMap = ensureMethodMapFor(atom);
|
||||||
|
|
||||||
if (methodMap.containsKey(method)) {
|
if (methodMap.containsKey(method)) {
|
||||||
@ -147,16 +148,17 @@ public class ModuleScope {
|
|||||||
*/
|
*/
|
||||||
@CompilerDirectives.TruffleBoundary
|
@CompilerDirectives.TruffleBoundary
|
||||||
public Function lookupMethodDefinition(AtomConstructor atom, String name) {
|
public Function lookupMethodDefinition(AtomConstructor atom, String name) {
|
||||||
Function definedWithAtom = atom.getDefinitionScope().getMethodMapFor(atom).get(name);
|
String lowerName = name.toLowerCase();
|
||||||
|
Function definedWithAtom = atom.getDefinitionScope().getMethodMapFor(atom).get(lowerName);
|
||||||
if (definedWithAtom != null) {
|
if (definedWithAtom != null) {
|
||||||
return definedWithAtom;
|
return definedWithAtom;
|
||||||
}
|
}
|
||||||
Function definedHere = getMethodMapFor(atom).get(name);
|
Function definedHere = getMethodMapFor(atom).get(lowerName);
|
||||||
if (definedHere != null) {
|
if (definedHere != null) {
|
||||||
return definedHere;
|
return definedHere;
|
||||||
}
|
}
|
||||||
return imports.stream()
|
return imports.stream()
|
||||||
.map(scope -> scope.getMethodMapFor(atom).get(name))
|
.map(scope -> scope.getMethodMapFor(atom).get(lowerName))
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
@ -179,6 +181,11 @@ public class ModuleScope {
|
|||||||
return methods;
|
return methods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return the polyglot symbols imported into this scope. */
|
||||||
|
public Map<String, Object> getPolyglotSymbols() {
|
||||||
|
return polyglotSymbols;
|
||||||
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
imports = new HashSet<>();
|
imports = new HashSet<>();
|
||||||
methods = new HashMap<>();
|
methods = new HashMap<>();
|
||||||
|
@ -42,6 +42,8 @@ class Passes(passes: Option[List[PassGroup]] = None) {
|
|||||||
TypeFunctions,
|
TypeFunctions,
|
||||||
TypeSignatures,
|
TypeSignatures,
|
||||||
AliasAnalysis,
|
AliasAnalysis,
|
||||||
|
UppercaseNames,
|
||||||
|
AliasAnalysis,
|
||||||
LambdaConsolidate,
|
LambdaConsolidate,
|
||||||
AliasAnalysis,
|
AliasAnalysis,
|
||||||
SuspendedArguments,
|
SuspendedArguments,
|
||||||
|
@ -116,7 +116,7 @@ object AstToIr {
|
|||||||
case AstView.Atom(consName, args) =>
|
case AstView.Atom(consName, args) =>
|
||||||
Module.Scope.Definition
|
Module.Scope.Definition
|
||||||
.Atom(
|
.Atom(
|
||||||
Name.Literal(consName.name, getIdentifiedLocation(consName)),
|
buildName(consName),
|
||||||
args.map(translateArgumentDefinition(_)),
|
args.map(translateArgumentDefinition(_)),
|
||||||
getIdentifiedLocation(inputAst)
|
getIdentifiedLocation(inputAst)
|
||||||
)
|
)
|
||||||
@ -131,7 +131,7 @@ object AstToIr {
|
|||||||
|
|
||||||
if (containsAtomDefOrInclude && !hasArgs) {
|
if (containsAtomDefOrInclude && !hasArgs) {
|
||||||
Module.Scope.Definition.Type(
|
Module.Scope.Definition.Type(
|
||||||
Name.Literal(typeName.name, getIdentifiedLocation(typeName)),
|
buildName(typeName),
|
||||||
args.map(translateArgumentDefinition(_)),
|
args.map(translateArgumentDefinition(_)),
|
||||||
translatedBody,
|
translatedBody,
|
||||||
getIdentifiedLocation(inputAst)
|
getIdentifiedLocation(inputAst)
|
||||||
@ -148,14 +148,9 @@ object AstToIr {
|
|||||||
val pathSegments = targetPath.collect {
|
val pathSegments = targetPath.collect {
|
||||||
case AST.Ident.Cons.any(c) => c
|
case AST.Ident.Cons.any(c) => c
|
||||||
}
|
}
|
||||||
val pathNames = pathSegments.map(c =>
|
val pathNames = pathSegments.map(buildName)
|
||||||
IR.Name.Literal(c.name, getIdentifiedLocation(c))
|
|
||||||
)
|
|
||||||
|
|
||||||
val methodSegments = pathNames :+ Name.Literal(
|
val methodSegments = pathNames :+ buildName(nameStr)
|
||||||
nameStr.name,
|
|
||||||
getIdentifiedLocation(nameStr)
|
|
||||||
)
|
|
||||||
|
|
||||||
val typeSegments = methodSegments.init
|
val typeSegments = methodSegments.init
|
||||||
|
|
||||||
@ -168,10 +163,8 @@ object AstToIr {
|
|||||||
MethodReference.genLocation(methodSegments)
|
MethodReference.genLocation(methodSegments)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
val typeName = Name.Here(None)
|
val typeName = Name.Here(None)
|
||||||
val methodName =
|
val methodName = buildName(nameStr)
|
||||||
Name.Literal(nameStr.name, getIdentifiedLocation(nameStr))
|
|
||||||
|
|
||||||
Name.MethodReference(
|
Name.MethodReference(
|
||||||
typeName,
|
typeName,
|
||||||
methodName,
|
methodName,
|
||||||
@ -187,7 +180,7 @@ object AstToIr {
|
|||||||
)
|
)
|
||||||
case AstView.FunctionSugar(name, args, body) =>
|
case AstView.FunctionSugar(name, args, body) =>
|
||||||
val typeName = Name.Here(None)
|
val typeName = Name.Here(None)
|
||||||
val methodName = Name.Literal(name.name, getIdentifiedLocation(name))
|
val methodName = buildName(name)
|
||||||
|
|
||||||
val methodReference = Name.MethodReference(
|
val methodReference = Name.MethodReference(
|
||||||
typeName,
|
typeName,
|
||||||
@ -205,10 +198,10 @@ object AstToIr {
|
|||||||
case AstView.TypeAscription(typed, sig) =>
|
case AstView.TypeAscription(typed, sig) =>
|
||||||
typed match {
|
typed match {
|
||||||
case AST.Ident.any(ident) =>
|
case AST.Ident.any(ident) =>
|
||||||
val typeName = Name.Here(None)
|
val typeName = Name.Here(None)
|
||||||
val methodName = Name.Literal(ident.name, getIdentifiedLocation(ident))
|
val methodName = buildName(ident)
|
||||||
val methodReference = Name.MethodReference(
|
val methodReference = Name.MethodReference(
|
||||||
typeName,
|
typeName,
|
||||||
methodName,
|
methodName,
|
||||||
methodName.location
|
methodName.location
|
||||||
)
|
)
|
||||||
@ -322,7 +315,7 @@ object AstToIr {
|
|||||||
)
|
)
|
||||||
case _ =>
|
case _ =>
|
||||||
IR.Application.Prefix(
|
IR.Application.Prefix(
|
||||||
IR.Name.Literal("negate", None),
|
IR.Name.Literal("negate", isReferent = false, None),
|
||||||
List(
|
List(
|
||||||
IR.CallArgument.Specified(
|
IR.CallArgument.Specified(
|
||||||
None,
|
None,
|
||||||
@ -344,7 +337,7 @@ object AstToIr {
|
|||||||
case AstView
|
case AstView
|
||||||
.SuspendedBlock(name, block @ AstView.Block(lines, lastLine)) =>
|
.SuspendedBlock(name, block @ AstView.Block(lines, lastLine)) =>
|
||||||
Expression.Binding(
|
Expression.Binding(
|
||||||
Name.Literal(name.name, getIdentifiedLocation(name)),
|
buildName(name),
|
||||||
Expression.Block(
|
Expression.Block(
|
||||||
lines.map(translateExpression),
|
lines.map(translateExpression),
|
||||||
translateExpression(lastLine),
|
translateExpression(lastLine),
|
||||||
@ -366,7 +359,7 @@ object AstToIr {
|
|||||||
|
|
||||||
// Note [Uniform Call Syntax Translation]
|
// Note [Uniform Call Syntax Translation]
|
||||||
Application.Prefix(
|
Application.Prefix(
|
||||||
translateExpression(name),
|
translateIdent(name),
|
||||||
(target :: validArguments).map(translateCallArgument),
|
(target :: validArguments).map(translateCallArgument),
|
||||||
hasDefaultsSuspended = hasDefaultsSuspended,
|
hasDefaultsSuspended = hasDefaultsSuspended,
|
||||||
getIdentifiedLocation(inputAst)
|
getIdentifiedLocation(inputAst)
|
||||||
@ -556,7 +549,7 @@ object AstToIr {
|
|||||||
case AstView.AssignedArgument(left, right) =>
|
case AstView.AssignedArgument(left, right) =>
|
||||||
CallArgument
|
CallArgument
|
||||||
.Specified(
|
.Specified(
|
||||||
Some(Name.Literal(left.name, getIdentifiedLocation(left))),
|
Some(buildName(left)),
|
||||||
translateExpression(right),
|
translateExpression(right),
|
||||||
getIdentifiedLocation(arg)
|
getIdentifiedLocation(arg)
|
||||||
)
|
)
|
||||||
@ -631,7 +624,7 @@ object AstToIr {
|
|||||||
} else {
|
} else {
|
||||||
Application.Operator.Binary(
|
Application.Operator.Binary(
|
||||||
leftArg,
|
leftArg,
|
||||||
Name.Literal(fn.name, getIdentifiedLocation(fn)),
|
buildName(fn),
|
||||||
rightArg,
|
rightArg,
|
||||||
getIdentifiedLocation(callable)
|
getIdentifiedLocation(callable)
|
||||||
)
|
)
|
||||||
@ -680,13 +673,13 @@ object AstToIr {
|
|||||||
} else {
|
} else {
|
||||||
Application.Operator.Section.Left(
|
Application.Operator.Section.Left(
|
||||||
leftArg,
|
leftArg,
|
||||||
Name.Literal(left.opr.name, getIdentifiedLocation(left.opr)),
|
buildName(left.opr),
|
||||||
getIdentifiedLocation(left)
|
getIdentifiedLocation(left)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case AST.App.Section.Sides.any(sides) =>
|
case AST.App.Section.Sides.any(sides) =>
|
||||||
Application.Operator.Section.Sides(
|
Application.Operator.Section.Sides(
|
||||||
Name.Literal(sides.opr.name, getIdentifiedLocation(sides.opr)),
|
buildName(sides.opr),
|
||||||
getIdentifiedLocation(sides)
|
getIdentifiedLocation(sides)
|
||||||
)
|
)
|
||||||
case AST.App.Section.Right.any(right) =>
|
case AST.App.Section.Right.any(right) =>
|
||||||
@ -696,7 +689,7 @@ object AstToIr {
|
|||||||
Error.Syntax(section, Error.Syntax.NamedArgInSection)
|
Error.Syntax(section, Error.Syntax.NamedArgInSection)
|
||||||
} else {
|
} else {
|
||||||
Application.Operator.Section.Right(
|
Application.Operator.Section.Right(
|
||||||
Name.Literal(right.opr.name, getIdentifiedLocation(right.opr)),
|
buildName(right.opr),
|
||||||
translateCallArgument(right.arg),
|
translateCallArgument(right.arg),
|
||||||
getIdentifiedLocation(right)
|
getIdentifiedLocation(right)
|
||||||
)
|
)
|
||||||
@ -718,10 +711,10 @@ object AstToIr {
|
|||||||
} else if (name == "here") {
|
} else if (name == "here") {
|
||||||
Name.Here(getIdentifiedLocation(identifier))
|
Name.Here(getIdentifiedLocation(identifier))
|
||||||
} else {
|
} else {
|
||||||
Name.Literal(name, getIdentifiedLocation(identifier))
|
buildName(identifier)
|
||||||
}
|
}
|
||||||
case AST.Ident.Cons(name) =>
|
case AST.Ident.Cons(_) =>
|
||||||
Name.Literal(name, getIdentifiedLocation(identifier))
|
buildName(identifier)
|
||||||
case AST.Ident.Blank(_) =>
|
case AST.Ident.Blank(_) =>
|
||||||
Name.Blank(getIdentifiedLocation(identifier))
|
Name.Blank(getIdentifiedLocation(identifier))
|
||||||
case AST.Ident.Opr.any(_) =>
|
case AST.Ident.Opr.any(_) =>
|
||||||
@ -802,9 +795,14 @@ object AstToIr {
|
|||||||
*/
|
*/
|
||||||
def translatePattern(pattern: AST): Pattern = {
|
def translatePattern(pattern: AST): Pattern = {
|
||||||
AstView.MaybeManyParensed.unapply(pattern).getOrElse(pattern) match {
|
AstView.MaybeManyParensed.unapply(pattern).getOrElse(pattern) match {
|
||||||
case AstView.ConstructorPattern(cons, fields) =>
|
case AstView.ConstructorPattern(conses, fields) =>
|
||||||
|
val irConses = conses.map(translateIdent(_).asInstanceOf[IR.Name])
|
||||||
|
val name = irConses match {
|
||||||
|
case List(n) => n
|
||||||
|
case _ => IR.Name.Qualified(irConses, None)
|
||||||
|
}
|
||||||
Pattern.Constructor(
|
Pattern.Constructor(
|
||||||
translateIdent(cons).asInstanceOf[IR.Name],
|
name,
|
||||||
fields.map(translatePattern),
|
fields.map(translatePattern),
|
||||||
getIdentifiedLocation(pattern)
|
getIdentifiedLocation(pattern)
|
||||||
)
|
)
|
||||||
@ -904,4 +902,13 @@ object AstToIr {
|
|||||||
throw new UnhandledEntity(comment, "processComment")
|
throw new UnhandledEntity(comment, "processComment")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def isReferant(ident: AST.Ident): Boolean =
|
||||||
|
ident match {
|
||||||
|
case AST.Ident.Cons.any(_) => true
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
|
|
||||||
|
private def buildName(ident: AST.Ident): IR.Name.Literal =
|
||||||
|
IR.Name.Literal(ident.name, isReferant(ident), getIdentifiedLocation(ident))
|
||||||
}
|
}
|
||||||
|
@ -443,6 +443,13 @@ object AstView {
|
|||||||
|
|
||||||
object MethodCall {
|
object MethodCall {
|
||||||
|
|
||||||
|
private def consToVar(ast: AST.Ident): AST.Ident =
|
||||||
|
ast match {
|
||||||
|
case AST.Ident.Cons(c) =>
|
||||||
|
AST.Ident.Var(c).setLocation(ast.location).setID(ast.id)
|
||||||
|
case _ => ast
|
||||||
|
}
|
||||||
|
|
||||||
/** Matches on a method call.
|
/** Matches on a method call.
|
||||||
*
|
*
|
||||||
* A method call has the form `<obj>.<fn-name> <args...>` where `<obj>` is
|
* A method call has the form `<obj>.<fn-name> <args...>` where `<obj>` is
|
||||||
@ -456,14 +463,14 @@ object AstView {
|
|||||||
def unapply(ast: AST): Option[(AST, AST.Ident, List[AST])] =
|
def unapply(ast: AST): Option[(AST, AST.Ident, List[AST])] =
|
||||||
ast match {
|
ast match {
|
||||||
case OperatorDot(target, Application(ConsOrVar(ident), args)) =>
|
case OperatorDot(target, Application(ConsOrVar(ident), args)) =>
|
||||||
Some((target, ident, args))
|
Some((target, consToVar(ident), args))
|
||||||
case AST.App.Section.Left(
|
case AST.App.Section.Left(
|
||||||
MethodCall(target, ident, List()),
|
MethodCall(target, ident, List()),
|
||||||
susp @ SuspendDefaultsOperator(_)
|
susp @ SuspendDefaultsOperator(_)
|
||||||
) =>
|
) =>
|
||||||
Some((target, ident, List(susp)))
|
Some((target, ident, List(susp)))
|
||||||
case OperatorDot(target, ConsOrVar(ident)) =>
|
case OperatorDot(target, ConsOrVar(ident)) =>
|
||||||
Some((target, ident, List()))
|
Some((target, consToVar(ident), List()))
|
||||||
case _ => None
|
case _ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -792,6 +799,17 @@ object AstView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object QualifiedName {
|
||||||
|
def unapply(ast: AST): Option[List[AST.Ident.Cons]] =
|
||||||
|
ast match {
|
||||||
|
case OperatorDot(l, AST.Ident.Cons.any(name)) =>
|
||||||
|
unapply(l).map(_ :+ name)
|
||||||
|
case AST.Ident.Cons.any(name) =>
|
||||||
|
Some(List(name))
|
||||||
|
case _ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object ConstructorPattern {
|
object ConstructorPattern {
|
||||||
|
|
||||||
/** Matches on a constructor pattern.
|
/** Matches on a constructor pattern.
|
||||||
@ -803,12 +821,12 @@ object AstView {
|
|||||||
* @param ast the structure to try and match on
|
* @param ast the structure to try and match on
|
||||||
* @return the pattern
|
* @return the pattern
|
||||||
*/
|
*/
|
||||||
def unapply(ast: AST): Option[(AST.Ident, List[AST])] = {
|
def unapply(ast: AST): Option[(List[AST.Ident.Cons], List[AST])] = {
|
||||||
MaybeManyParensed.unapply(ast).getOrElse(ast) match {
|
MaybeManyParensed.unapply(ast).getOrElse(ast) match {
|
||||||
case AST.Ident.Cons.any(cons) => Some((cons, List()))
|
case QualifiedName(cons) => Some((cons, List()))
|
||||||
case SpacedList(elems) if elems.nonEmpty =>
|
case SpacedList(elems) if elems.nonEmpty =>
|
||||||
elems.head match {
|
elems.head match {
|
||||||
case AST.Ident.Cons.any(refName) =>
|
case QualifiedName(refName) =>
|
||||||
val allFieldsValid = elems.tail.forall {
|
val allFieldsValid = elems.tail.forall {
|
||||||
case Pattern(_) => true
|
case Pattern(_) => true
|
||||||
case _ => false
|
case _ => false
|
||||||
|
@ -15,7 +15,11 @@ import org.enso.compiler.pass.analyse.{
|
|||||||
TailCall
|
TailCall
|
||||||
}
|
}
|
||||||
import org.enso.compiler.pass.optimise.ApplicationSaturation
|
import org.enso.compiler.pass.optimise.ApplicationSaturation
|
||||||
import org.enso.compiler.pass.resolve.{MethodDefinitions, Patterns}
|
import org.enso.compiler.pass.resolve.{
|
||||||
|
MethodDefinitions,
|
||||||
|
Patterns,
|
||||||
|
UppercaseNames
|
||||||
|
}
|
||||||
import org.enso.interpreter.node.callable.argument.ReadArgumentNode
|
import org.enso.interpreter.node.callable.argument.ReadArgumentNode
|
||||||
import org.enso.interpreter.node.callable.function.{
|
import org.enso.interpreter.node.callable.function.{
|
||||||
BlockNode,
|
BlockNode,
|
||||||
@ -60,7 +64,6 @@ import org.enso.interpreter.{Constants, Language}
|
|||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
import scala.collection.mutable.ArrayBuffer
|
import scala.collection.mutable.ArrayBuffer
|
||||||
import scala.jdk.OptionConverters._
|
|
||||||
|
|
||||||
/** This is an implementation of a codegeneration pass that lowers the Enso
|
/** This is an implementation of a codegeneration pass that lowers the Enso
|
||||||
* [[IR]] into the truffle [[org.enso.compiler.core.Core.Node]] structures that
|
* [[IR]] into the truffle [[org.enso.compiler.core.Core.Node]] structures that
|
||||||
@ -205,12 +208,21 @@ class IrToTruffle(
|
|||||||
methodDef.methodReference.typePointer
|
methodDef.methodReference.typePointer
|
||||||
.getMetadata(MethodDefinitions)
|
.getMetadata(MethodDefinitions)
|
||||||
.map {
|
.map {
|
||||||
case BindingsMap.Resolution(BindingsMap.ResolvedModule(module)) =>
|
res =>
|
||||||
module.getScope.getAssociatedType
|
res.target match {
|
||||||
case BindingsMap.Resolution(
|
case BindingsMap.ResolvedModule(module) =>
|
||||||
BindingsMap.ResolvedConstructor(definitionModule, cons)
|
module.getScope.getAssociatedType
|
||||||
) =>
|
case BindingsMap.ResolvedConstructor(definitionModule, cons) =>
|
||||||
definitionModule.getScope.getConstructors.get(cons.name)
|
definitionModule.getScope.getConstructors.get(cons.name)
|
||||||
|
case BindingsMap.ResolvedPolyglotSymbol(_, _) =>
|
||||||
|
throw new CompilerError(
|
||||||
|
"Impossible polyglot symbol, should be caught by MethodDefinitions pass."
|
||||||
|
)
|
||||||
|
case _: BindingsMap.ResolvedMethod =>
|
||||||
|
throw new CompilerError(
|
||||||
|
"Impossible here, should be caught by MethodDefinitions pass."
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
consOpt.foreach {
|
consOpt.foreach {
|
||||||
@ -555,6 +567,22 @@ class IrToTruffle(
|
|||||||
)
|
)
|
||||||
) =>
|
) =>
|
||||||
Right(mod.getScope.getConstructors.get(cons.name))
|
Right(mod.getScope.getConstructors.get(cons.name))
|
||||||
|
case Some(
|
||||||
|
BindingsMap.Resolution(
|
||||||
|
BindingsMap.ResolvedPolyglotSymbol(_, _)
|
||||||
|
)
|
||||||
|
) =>
|
||||||
|
throw new CompilerError(
|
||||||
|
"Impossible polyglot symbol here, should be caught by Patterns resolution pass."
|
||||||
|
)
|
||||||
|
case Some(
|
||||||
|
BindingsMap.Resolution(
|
||||||
|
BindingsMap.ResolvedMethod(_, _)
|
||||||
|
)
|
||||||
|
) =>
|
||||||
|
throw new CompilerError(
|
||||||
|
"Impossible method here, should be caught by Patterns resolution pass."
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -685,7 +713,7 @@ class IrToTruffle(
|
|||||||
*/
|
*/
|
||||||
def processName(name: IR.Name): RuntimeExpression = {
|
def processName(name: IR.Name): RuntimeExpression = {
|
||||||
val nameExpr = name match {
|
val nameExpr = name match {
|
||||||
case IR.Name.Literal(nameStr, _, _, _) =>
|
case IR.Name.Literal(nameStr, _, _, _, _) =>
|
||||||
val useInfo = name
|
val useInfo = name
|
||||||
.unsafeGetMetadata(
|
.unsafeGetMetadata(
|
||||||
AliasAnalysis,
|
AliasAnalysis,
|
||||||
@ -693,17 +721,28 @@ class IrToTruffle(
|
|||||||
)
|
)
|
||||||
.unsafeAs[AliasAnalysis.Info.Occurrence]
|
.unsafeAs[AliasAnalysis.Info.Occurrence]
|
||||||
|
|
||||||
val slot = scope.getFramePointer(useInfo.id)
|
val slot = scope.getFramePointer(useInfo.id)
|
||||||
val atomCons = moduleScope.getConstructor(nameStr).toScala
|
val global = name.getMetadata(UppercaseNames)
|
||||||
val polySymbol = moduleScope.lookupPolyglotSymbol(nameStr).toScala
|
if (slot.isDefined) {
|
||||||
if (nameStr == Constants.Names.CURRENT_MODULE) {
|
|
||||||
ConstructorNode.build(moduleScope.getAssociatedType)
|
|
||||||
} else if (slot.isDefined) {
|
|
||||||
ReadLocalVariableNode.build(slot.get)
|
ReadLocalVariableNode.build(slot.get)
|
||||||
} else if (atomCons.isDefined) {
|
} else if (global.isDefined) {
|
||||||
ConstructorNode.build(atomCons.get)
|
val resolution = global.get.target
|
||||||
} else if (polySymbol.isDefined) {
|
resolution match {
|
||||||
ConstantObjectNode.build(polySymbol.get)
|
case BindingsMap.ResolvedConstructor(definitionModule, cons) =>
|
||||||
|
ConstructorNode.build(
|
||||||
|
definitionModule.getScope.getConstructors.get(cons.name)
|
||||||
|
)
|
||||||
|
case BindingsMap.ResolvedModule(module) =>
|
||||||
|
ConstructorNode.build(module.getScope.getAssociatedType)
|
||||||
|
case BindingsMap.ResolvedPolyglotSymbol(module, symbol) =>
|
||||||
|
ConstantObjectNode.build(
|
||||||
|
module.getScope.getPolyglotSymbols.get(symbol.name)
|
||||||
|
)
|
||||||
|
case BindingsMap.ResolvedMethod(_, _) =>
|
||||||
|
throw new CompilerError(
|
||||||
|
"Impossible here, should be desugared by UppercaseNames resolver"
|
||||||
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
DynamicSymbolNode.build(
|
DynamicSymbolNode.build(
|
||||||
UnresolvedSymbol.build(nameStr, moduleScope)
|
UnresolvedSymbol.build(nameStr, moduleScope)
|
||||||
@ -713,7 +752,12 @@ class IrToTruffle(
|
|||||||
ConstructorNode.build(moduleScope.getAssociatedType)
|
ConstructorNode.build(moduleScope.getAssociatedType)
|
||||||
case IR.Name.This(location, passData, _) =>
|
case IR.Name.This(location, passData, _) =>
|
||||||
processName(
|
processName(
|
||||||
IR.Name.Literal(Constants.Names.THIS_ARGUMENT, location, passData)
|
IR.Name.Literal(
|
||||||
|
Constants.Names.THIS_ARGUMENT,
|
||||||
|
isReferent = false,
|
||||||
|
location,
|
||||||
|
passData
|
||||||
|
)
|
||||||
)
|
)
|
||||||
case _: IR.Name.Blank =>
|
case _: IR.Name.Blank =>
|
||||||
throw new CompilerError(
|
throw new CompilerError(
|
||||||
@ -727,7 +771,7 @@ class IrToTruffle(
|
|||||||
throw new CompilerError(
|
throw new CompilerError(
|
||||||
"Qualified names should not be present at codegen time."
|
"Qualified names should not be present at codegen time."
|
||||||
)
|
)
|
||||||
case _: IR.Error.Resolution => throw new RuntimeException("todo")
|
case err: IR.Error.Resolution => processError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
setLocation(nameExpr, name.location)
|
setLocation(nameExpr, name.location)
|
||||||
@ -768,7 +812,8 @@ class IrToTruffle(
|
|||||||
context.getBuiltins.error().compileError().newInstance(err.message)
|
context.getBuiltins.error().compileError().newInstance(err.message)
|
||||||
case err: Error.Unexpected.TypeSignature =>
|
case err: Error.Unexpected.TypeSignature =>
|
||||||
context.getBuiltins.error().compileError().newInstance(err.message)
|
context.getBuiltins.error().compileError().newInstance(err.message)
|
||||||
case _: Error.Resolution => throw new RuntimeException("bleee")
|
case err: Error.Resolution =>
|
||||||
|
context.getBuiltins.error().compileError().newInstance(err.message)
|
||||||
case _: Error.Pattern =>
|
case _: Error.Pattern =>
|
||||||
throw new CompilerError(
|
throw new CompilerError(
|
||||||
"Impossible here, should be handled in the pattern match."
|
"Impossible here, should be handled in the pattern match."
|
||||||
|
@ -13,17 +13,20 @@ class FreshNameSupply {
|
|||||||
* @param numId the numeric identifier to use in the name
|
* @param numId the numeric identifier to use in the name
|
||||||
* @return a new name
|
* @return a new name
|
||||||
*/
|
*/
|
||||||
private def mkName(numId: Long): IR.Name.Literal =
|
private def mkName(numId: Long, isReferent: Boolean): IR.Name.Literal = {
|
||||||
IR.Name.Literal(s"<internal-${numId}>", None)
|
val refMarker = if (isReferent) "ref" else ""
|
||||||
|
IR.Name.Literal(s"<internal-$refMarker-${numId}>", isReferent, None)
|
||||||
|
}
|
||||||
|
|
||||||
/** Generates a name guaranteed not to exist in this program.
|
/** Generates a name guaranteed not to exist in this program.
|
||||||
*
|
*
|
||||||
|
* @param isReferent whether or not the name should be marked as referent.
|
||||||
* @return a new name
|
* @return a new name
|
||||||
*/
|
*/
|
||||||
def newName(): IR.Name.Literal = {
|
def newName(isReferent: Boolean = false): IR.Name.Literal = {
|
||||||
val num = counter
|
val num = counter
|
||||||
counter += 1
|
counter += 1
|
||||||
|
|
||||||
mkName(num)
|
mkName(num, isReferent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1439,25 +1439,21 @@ object IR {
|
|||||||
keepDiagnostics: Boolean = true
|
keepDiagnostics: Boolean = true
|
||||||
): Name
|
): Name
|
||||||
|
|
||||||
/** Checks whether a name is in referant form.
|
/** Checks whether a name is in referent form.
|
||||||
*
|
*
|
||||||
* Please see the syntax specification for more details on this form.
|
* Please see the syntax specification for more details on this form.
|
||||||
*
|
*
|
||||||
* @return `true` if `this` is in referant form, otherwise `false`
|
* @return `true` if `this` is in referent form, otherwise `false`
|
||||||
*/
|
*/
|
||||||
def isReferant: Boolean = {
|
def isReferent: Boolean
|
||||||
name.split("_").filterNot(_.isEmpty).forall(_.head.isUpper)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Checks whether a name is in variable form.
|
/** Checks whether a name is in variable form.
|
||||||
*
|
*
|
||||||
* Please see the syntax specification for more details on this form.
|
* Please see the syntax specification for more details on this form.
|
||||||
*
|
*
|
||||||
* @return `true` if `this` is in referant form, otherwise `false`
|
* @return `true` if `this` is in referent form, otherwise `false`
|
||||||
*/
|
*/
|
||||||
def isVariable: Boolean = !isReferant
|
def isVariable: Boolean = !isReferent
|
||||||
|
|
||||||
// TODO [AA] toReferant and toVariable for converting forms
|
|
||||||
}
|
}
|
||||||
object Name {
|
object Name {
|
||||||
|
|
||||||
@ -1510,6 +1506,8 @@ object IR {
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def isReferent: Boolean = true
|
||||||
|
|
||||||
override def duplicate(
|
override def duplicate(
|
||||||
keepLocations: Boolean = true,
|
keepLocations: Boolean = true,
|
||||||
keepMetadata: Boolean = true,
|
keepMetadata: Boolean = true,
|
||||||
@ -1621,6 +1619,8 @@ object IR {
|
|||||||
override def setLocation(location: Option[IdentifiedLocation]): Name =
|
override def setLocation(location: Option[IdentifiedLocation]): Name =
|
||||||
copy(location = location)
|
copy(location = location)
|
||||||
|
|
||||||
|
override def isReferent: Boolean = true
|
||||||
|
|
||||||
/** Creates a copy of `this`.
|
/** Creates a copy of `this`.
|
||||||
*
|
*
|
||||||
* @param parts the segments of the name
|
* @param parts the segments of the name
|
||||||
@ -1706,6 +1706,8 @@ object IR {
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def isReferent: Boolean = false
|
||||||
|
|
||||||
override def duplicate(
|
override def duplicate(
|
||||||
keepLocations: Boolean = true,
|
keepLocations: Boolean = true,
|
||||||
keepMetadata: Boolean = true,
|
keepMetadata: Boolean = true,
|
||||||
@ -1744,12 +1746,14 @@ object IR {
|
|||||||
/** The representation of a literal name.
|
/** The representation of a literal name.
|
||||||
*
|
*
|
||||||
* @param name the literal text of the name
|
* @param name the literal text of the name
|
||||||
|
* @param isReferent is this a referent name
|
||||||
* @param location the source location that the node corresponds to
|
* @param location the source location that the node corresponds to
|
||||||
* @param passData the pass metadata associated with this node
|
* @param passData the pass metadata associated with this node
|
||||||
* @param diagnostics compiler diagnostics for this node
|
* @param diagnostics compiler diagnostics for this node
|
||||||
*/
|
*/
|
||||||
sealed case class Literal(
|
sealed case class Literal(
|
||||||
override val name: String,
|
override val name: String,
|
||||||
|
override val isReferent: Boolean,
|
||||||
override val location: Option[IdentifiedLocation],
|
override val location: Option[IdentifiedLocation],
|
||||||
override val passData: MetadataStorage = MetadataStorage(),
|
override val passData: MetadataStorage = MetadataStorage(),
|
||||||
override val diagnostics: DiagnosticStorage = DiagnosticStorage()
|
override val diagnostics: DiagnosticStorage = DiagnosticStorage()
|
||||||
@ -1759,6 +1763,7 @@ object IR {
|
|||||||
/** Creates a copy of `this`.
|
/** Creates a copy of `this`.
|
||||||
*
|
*
|
||||||
* @param name the literal text of the name
|
* @param name the literal text of the name
|
||||||
|
* @param isReferent is this a referent name
|
||||||
* @param location the source location that the node corresponds to
|
* @param location the source location that the node corresponds to
|
||||||
* @param passData the pass metadata associated with this node
|
* @param passData the pass metadata associated with this node
|
||||||
* @param diagnostics compiler diagnostics for this node
|
* @param diagnostics compiler diagnostics for this node
|
||||||
@ -1767,12 +1772,13 @@ object IR {
|
|||||||
*/
|
*/
|
||||||
def copy(
|
def copy(
|
||||||
name: String = name,
|
name: String = name,
|
||||||
|
isReferent: Boolean = isReferent,
|
||||||
location: Option[IdentifiedLocation] = location,
|
location: Option[IdentifiedLocation] = location,
|
||||||
passData: MetadataStorage = passData,
|
passData: MetadataStorage = passData,
|
||||||
diagnostics: DiagnosticStorage = diagnostics,
|
diagnostics: DiagnosticStorage = diagnostics,
|
||||||
id: Identifier = id
|
id: Identifier = id
|
||||||
): Literal = {
|
): Literal = {
|
||||||
val res = Literal(name, location, passData, diagnostics)
|
val res = Literal(name, isReferent, location, passData, diagnostics)
|
||||||
res.id = id
|
res.id = id
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
@ -1800,6 +1806,7 @@ object IR {
|
|||||||
s"""
|
s"""
|
||||||
|IR.Name.Literal(
|
|IR.Name.Literal(
|
||||||
|name = $name,
|
|name = $name,
|
||||||
|
|isReferent = $isReferent,
|
||||||
|location = $location,
|
|location = $location,
|
||||||
|passData = ${this.showPassData},
|
|passData = ${this.showPassData},
|
||||||
|diagnostics = $diagnostics,
|
|diagnostics = $diagnostics,
|
||||||
@ -1826,6 +1833,8 @@ object IR {
|
|||||||
override protected var id: Identifier = randomId
|
override protected var id: Identifier = randomId
|
||||||
override val name: String = "this"
|
override val name: String = "this"
|
||||||
|
|
||||||
|
override def isReferent: Boolean = false
|
||||||
|
|
||||||
/** Creates a copy of `this`.
|
/** Creates a copy of `this`.
|
||||||
*
|
*
|
||||||
* @param location the source location that the node corresponds to
|
* @param location the source location that the node corresponds to
|
||||||
@ -1894,6 +1903,8 @@ object IR {
|
|||||||
override protected var id: Identifier = randomId
|
override protected var id: Identifier = randomId
|
||||||
override val name: String = "here"
|
override val name: String = "here"
|
||||||
|
|
||||||
|
override def isReferent: Boolean = false
|
||||||
|
|
||||||
/** Creates a copy of `this`.
|
/** Creates a copy of `this`.
|
||||||
*
|
*
|
||||||
* @param location the source location that the node corresponds to
|
* @param location the source location that the node corresponds to
|
||||||
@ -4995,6 +5006,8 @@ object IR {
|
|||||||
with IR.Name {
|
with IR.Name {
|
||||||
override val name: String = originalName.name
|
override val name: String = originalName.name
|
||||||
|
|
||||||
|
override def isReferent: Boolean = originalName.isReferent
|
||||||
|
|
||||||
override def mapExpressions(fn: Expression => Expression): Resolution =
|
override def mapExpressions(fn: Expression => Expression): Resolution =
|
||||||
this
|
this
|
||||||
|
|
||||||
@ -5052,19 +5065,51 @@ object IR {
|
|||||||
|
|
||||||
object Resolution {
|
object Resolution {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A representation of a symbol resolution error.
|
||||||
|
*/
|
||||||
|
sealed trait Reason {
|
||||||
|
def explain(originalName: IR.Name): String
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An error coming from an unexpected occurence of a polyglot symbol.
|
||||||
|
*
|
||||||
|
* @param context the description of a context in which the error
|
||||||
|
* happened.
|
||||||
|
*/
|
||||||
|
case class UnexpectedPolyglot(context: String) extends Reason {
|
||||||
|
override def explain(originalName: Name): String =
|
||||||
|
s"The name ${originalName.name} resolved to a polyglot symbol," +
|
||||||
|
s"but polyglot symbols are not allowed in $context."
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An error coming from an unexpected occurence of a static method.
|
||||||
|
*
|
||||||
|
* @param context the description of a context in which the error
|
||||||
|
* happened.
|
||||||
|
*/
|
||||||
|
case class UnexpectedMethod(context: String) extends Reason {
|
||||||
|
override def explain(originalName: Name): String =
|
||||||
|
s"The name ${originalName.name} resolved to a method," +
|
||||||
|
s"but methods are not allowed in $context."
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An error coming from name resolver.
|
* An error coming from name resolver.
|
||||||
*
|
*
|
||||||
* @param err the original error.
|
* @param err the original error.
|
||||||
*/
|
*/
|
||||||
case class Reason(err: BindingsMap.ResolutionError) {
|
case class ResolverError(err: BindingsMap.ResolutionError)
|
||||||
|
extends Reason {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a human-readable explanation of the error.
|
* Provides a human-readable explanation of the error.
|
||||||
* @param originalName the original unresolved name.
|
* @param originalName the original unresolved name.
|
||||||
* @return a human-readable message.
|
* @return a human-readable message.
|
||||||
*/
|
*/
|
||||||
def explain(originalName: IR.Name): String =
|
override def explain(originalName: IR.Name): String =
|
||||||
err match {
|
err match {
|
||||||
case BindingsMap.ResolutionAmbiguous(candidates) =>
|
case BindingsMap.ResolutionAmbiguous(candidates) =>
|
||||||
val firstLine =
|
val firstLine =
|
||||||
@ -5077,6 +5122,10 @@ object IR {
|
|||||||
s" Type ${cons.name} defined in module ${definitionModule.getName};"
|
s" Type ${cons.name} defined in module ${definitionModule.getName};"
|
||||||
case BindingsMap.ResolvedModule(module) =>
|
case BindingsMap.ResolvedModule(module) =>
|
||||||
s" The module ${module.getName};"
|
s" The module ${module.getName};"
|
||||||
|
case BindingsMap.ResolvedPolyglotSymbol(_, symbol) =>
|
||||||
|
s" The imported polyglot symbol ${symbol.name};"
|
||||||
|
case BindingsMap.ResolvedMethod(module, symbol) =>
|
||||||
|
s" The method ${symbol.name} defined in module ${module.getName}"
|
||||||
}
|
}
|
||||||
(firstLine :: lines).mkString("\n")
|
(firstLine :: lines).mkString("\n")
|
||||||
case BindingsMap.ResolutionNotFound =>
|
case BindingsMap.ResolutionNotFound =>
|
||||||
|
@ -8,10 +8,14 @@ import org.enso.interpreter.runtime.Module
|
|||||||
* A utility structure for resolving symbols in a given module.
|
* A utility structure for resolving symbols in a given module.
|
||||||
*
|
*
|
||||||
* @param types the types defined in the current module
|
* @param types the types defined in the current module
|
||||||
|
* @param polyglotSymbols the polyglot symbols imported into the scope
|
||||||
|
* @param moduleMethods the methods defined with current module as `this`
|
||||||
* @param currentModule the module holding these bindings
|
* @param currentModule the module holding these bindings
|
||||||
*/
|
*/
|
||||||
case class BindingsMap(
|
case class BindingsMap(
|
||||||
types: List[BindingsMap.Cons],
|
types: List[BindingsMap.Cons],
|
||||||
|
polyglotSymbols: List[BindingsMap.PolyglotSymbol],
|
||||||
|
moduleMethods: List[BindingsMap.ModuleMethod],
|
||||||
currentModule: Module
|
currentModule: Module
|
||||||
) extends IRPass.Metadata {
|
) extends IRPass.Metadata {
|
||||||
import BindingsMap._
|
import BindingsMap._
|
||||||
@ -33,11 +37,28 @@ case class BindingsMap(
|
|||||||
.map(ResolvedConstructor(currentModule, _))
|
.map(ResolvedConstructor(currentModule, _))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def findPolyglotCandidates(
|
||||||
|
name: String
|
||||||
|
): List[ResolvedPolyglotSymbol] = {
|
||||||
|
polyglotSymbols
|
||||||
|
.filter(_.name == name)
|
||||||
|
.map(ResolvedPolyglotSymbol(currentModule, _))
|
||||||
|
}
|
||||||
|
|
||||||
|
private def findMethodCandidates(name: String): List[ResolvedName] = {
|
||||||
|
moduleMethods
|
||||||
|
.filter(_.name.toLowerCase == name.toLowerCase)
|
||||||
|
.map(ResolvedMethod(currentModule, _))
|
||||||
|
}
|
||||||
|
|
||||||
private def findLocalCandidates(name: String): List[ResolvedName] = {
|
private def findLocalCandidates(name: String): List[ResolvedName] = {
|
||||||
if (currentModule.getName.item == name) {
|
if (currentModule.getName.item == name) {
|
||||||
List(ResolvedModule(currentModule))
|
List(ResolvedModule(currentModule))
|
||||||
} else {
|
} else {
|
||||||
findConstructorCandidates(name)
|
val conses = findConstructorCandidates(name)
|
||||||
|
val polyglot = findPolyglotCandidates(name)
|
||||||
|
val methods = findMethodCandidates(name)
|
||||||
|
conses ++ polyglot ++ methods
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +78,7 @@ case class BindingsMap(
|
|||||||
"Wrong pass ordering. Running resolution on an unparsed module"
|
"Wrong pass ordering. Running resolution on an unparsed module"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.flatMap(_.findConstructorCandidates(name))
|
.flatMap(_.findExportedSymbolsFor(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
private def handleAmbiguity(
|
private def handleAmbiguity(
|
||||||
@ -70,6 +91,13 @@ case class BindingsMap(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def getBindingsFrom(module: Module): BindingsMap = {
|
||||||
|
module.getIr.unsafeGetMetadata(
|
||||||
|
BindingAnalysis,
|
||||||
|
"imported module has no binding map info"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves a name in the context of current module.
|
* Resolves a name in the context of current module.
|
||||||
*
|
*
|
||||||
@ -90,6 +118,52 @@ case class BindingsMap(
|
|||||||
}
|
}
|
||||||
handleAmbiguity(findExportedCandidatesInImports(name))
|
handleAmbiguity(findExportedCandidatesInImports(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves a qualified name to a symbol in the context of this module.
|
||||||
|
*
|
||||||
|
* @param name the name to resolve
|
||||||
|
* @return a resolution for `name`
|
||||||
|
*/
|
||||||
|
def resolveQualifiedName(
|
||||||
|
name: List[String]
|
||||||
|
): Either[ResolutionError, ResolvedName] =
|
||||||
|
name match {
|
||||||
|
case List() => Left(ResolutionNotFound)
|
||||||
|
case List(item) => resolveUppercaseName(item)
|
||||||
|
case List(module, cons) =>
|
||||||
|
resolveUppercaseName(module).flatMap {
|
||||||
|
case ResolvedModule(mod) =>
|
||||||
|
getBindingsFrom(mod).resolveExportedName(cons)
|
||||||
|
case _ => Left(ResolutionNotFound)
|
||||||
|
}
|
||||||
|
case _ =>
|
||||||
|
// TODO[MK] Implement when exports possible. Currently this has
|
||||||
|
// no viable interpretation.
|
||||||
|
Left(ResolutionNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
private def findExportedSymbolsFor(name: String): List[ResolvedName] = {
|
||||||
|
val matchingConses = types
|
||||||
|
.filter(_.name.toLowerCase == name.toLowerCase)
|
||||||
|
.map(ResolvedConstructor(currentModule, _))
|
||||||
|
val matchingMethods = moduleMethods
|
||||||
|
.filter(_.name.toLowerCase == name.toLowerCase)
|
||||||
|
.map(ResolvedMethod(currentModule, _))
|
||||||
|
matchingConses ++ matchingMethods
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves a name exported by this module.
|
||||||
|
*
|
||||||
|
* @param name the name to resolve
|
||||||
|
* @return the resolution for `name`
|
||||||
|
*/
|
||||||
|
def resolveExportedName(
|
||||||
|
name: String
|
||||||
|
): Either[ResolutionError, ResolvedName] = {
|
||||||
|
handleAmbiguity(findExportedSymbolsFor(name))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object BindingsMap {
|
object BindingsMap {
|
||||||
@ -102,6 +176,20 @@ object BindingsMap {
|
|||||||
*/
|
*/
|
||||||
case class Cons(name: String, arity: Int)
|
case class Cons(name: String, arity: Int)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A representation of an imported polyglot symbol.
|
||||||
|
*
|
||||||
|
* @param name the name of the symbol.
|
||||||
|
*/
|
||||||
|
case class PolyglotSymbol(name: String)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A representation of a method defined on the current module.
|
||||||
|
*
|
||||||
|
* @param name the name of the method.
|
||||||
|
*/
|
||||||
|
case class ModuleMethod(name: String)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A result of successful name resolution.
|
* A result of successful name resolution.
|
||||||
*/
|
*/
|
||||||
@ -123,6 +211,22 @@ object BindingsMap {
|
|||||||
*/
|
*/
|
||||||
case class ResolvedModule(module: Module) extends ResolvedName
|
case class ResolvedModule(module: Module) extends ResolvedName
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A representation of a name being resolved to a method call.
|
||||||
|
* @param module the module defining the method.
|
||||||
|
* @param method the method representation.
|
||||||
|
*/
|
||||||
|
case class ResolvedMethod(module: Module, method: ModuleMethod)
|
||||||
|
extends ResolvedName
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A representation of a name being resolved to a polyglot symbol.
|
||||||
|
*
|
||||||
|
* @param symbol the imported symbol name.
|
||||||
|
*/
|
||||||
|
case class ResolvedPolyglotSymbol(module: Module, symbol: PolyglotSymbol)
|
||||||
|
extends ResolvedName
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A representation of an error during name resolution.
|
* A representation of an error during name resolution.
|
||||||
*/
|
*/
|
||||||
@ -141,9 +245,8 @@ object BindingsMap {
|
|||||||
*/
|
*/
|
||||||
case object ResolutionNotFound extends ResolutionError
|
case object ResolutionNotFound extends ResolutionError
|
||||||
|
|
||||||
/** A metadata-friendly storage for resolutions */
|
/** A metadata-friendly storage for resolutions */
|
||||||
case class Resolution(target: ResolvedName)
|
case class Resolution(target: ResolvedName) extends IRPass.Metadata {
|
||||||
extends IRPass.Metadata {
|
|
||||||
|
|
||||||
/** The name of the metadata as a string. */
|
/** The name of the metadata as a string. */
|
||||||
override val metadataName: String = "Resolution"
|
override val metadataName: String = "Resolution"
|
||||||
|
@ -554,7 +554,7 @@ case object AliasAnalysis extends IRPass {
|
|||||||
): IR.Pattern = {
|
): IR.Pattern = {
|
||||||
pattern match {
|
pattern match {
|
||||||
case named @ Pattern.Name(name, _, _, _) =>
|
case named @ Pattern.Name(name, _, _, _) =>
|
||||||
if (name.isReferant) {
|
if (name.isReferent) {
|
||||||
throw new CompilerError(
|
throw new CompilerError(
|
||||||
"Nested patterns should be desugared by the point of alias " +
|
"Nested patterns should be desugared by the point of alias " +
|
||||||
"analysis."
|
"analysis."
|
||||||
@ -666,8 +666,9 @@ case object AliasAnalysis extends IRPass {
|
|||||||
*/
|
*/
|
||||||
def copy: Graph = {
|
def copy: Graph = {
|
||||||
val graph = new Graph
|
val graph = new Graph
|
||||||
graph.links = links
|
graph.links = links
|
||||||
graph.rootScope = rootScope.copy
|
graph.rootScope = rootScope.copy
|
||||||
|
graph.nextIdCounter = nextIdCounter
|
||||||
|
|
||||||
graph
|
graph
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package org.enso.compiler.pass.analyse
|
|||||||
|
|
||||||
import org.enso.compiler.context.{InlineContext, ModuleContext}
|
import org.enso.compiler.context.{InlineContext, ModuleContext}
|
||||||
import org.enso.compiler.core.IR
|
import org.enso.compiler.core.IR
|
||||||
|
import org.enso.compiler.core.IR.Module.Scope.Import.Polyglot
|
||||||
import org.enso.compiler.core.ir.MetadataStorage.ToPair
|
import org.enso.compiler.core.ir.MetadataStorage.ToPair
|
||||||
import org.enso.compiler.data.BindingsMap
|
import org.enso.compiler.data.BindingsMap
|
||||||
import org.enso.compiler.pass.IRPass
|
import org.enso.compiler.pass.IRPass
|
||||||
@ -48,9 +49,38 @@ case object BindingAnalysis extends IRPass {
|
|||||||
case cons: IR.Module.Scope.Definition.Atom =>
|
case cons: IR.Module.Scope.Definition.Atom =>
|
||||||
BindingsMap.Cons(cons.name.name, cons.arguments.length)
|
BindingsMap.Cons(cons.name.name, cons.arguments.length)
|
||||||
}
|
}
|
||||||
|
val importedPolyglot = ir.imports.collect {
|
||||||
|
case poly: IR.Module.Scope.Import.Polyglot =>
|
||||||
|
val sym = poly.entity match {
|
||||||
|
case Polyglot.Java(_, className) => className
|
||||||
|
}
|
||||||
|
BindingsMap.PolyglotSymbol(sym)
|
||||||
|
}
|
||||||
|
val moduleMethods = ir.bindings
|
||||||
|
.collect {
|
||||||
|
case method: IR.Module.Scope.Definition.Method.Explicit =>
|
||||||
|
val ref = method.methodReference
|
||||||
|
ref.typePointer match {
|
||||||
|
case IR.Name.Qualified(List(), _, _, _) => Some(ref.methodName.name)
|
||||||
|
case IR.Name.Qualified(List(n), _, _, _) =>
|
||||||
|
if (n.name == moduleContext.module.getName.item)
|
||||||
|
Some(ref.methodName.name)
|
||||||
|
else None
|
||||||
|
case IR.Name.Here(_, _, _) => Some(ref.methodName.name)
|
||||||
|
case IR.Name.Literal(n, _, _, _, _) =>
|
||||||
|
if (n == moduleContext.module.getName.item)
|
||||||
|
Some(ref.methodName.name)
|
||||||
|
else None
|
||||||
|
case _ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.flatten
|
||||||
|
.map(BindingsMap.ModuleMethod)
|
||||||
ir.updateMetadata(
|
ir.updateMetadata(
|
||||||
this -->> BindingsMap(
|
this -->> BindingsMap(
|
||||||
definedConstructors,
|
definedConstructors,
|
||||||
|
importedPolyglot,
|
||||||
|
moduleMethods,
|
||||||
moduleContext.module
|
moduleContext.module
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -133,7 +133,7 @@ case object ComplexType extends IRPass {
|
|||||||
val sig = lastSignature match {
|
val sig = lastSignature match {
|
||||||
case Some(IR.Type.Ascription(typed, _, _, _, _)) =>
|
case Some(IR.Type.Ascription(typed, _, _, _, _)) =>
|
||||||
typed match {
|
typed match {
|
||||||
case IR.Name.Literal(nameStr, _, _, _) =>
|
case IR.Name.Literal(nameStr, _, _, _, _) =>
|
||||||
if (name.name == nameStr) {
|
if (name.name == nameStr) {
|
||||||
lastSignature
|
lastSignature
|
||||||
} else {
|
} else {
|
||||||
|
@ -131,7 +131,7 @@ case object LambdaShorthandToLambda extends IRPass {
|
|||||||
IR.Function.Lambda(
|
IR.Function.Lambda(
|
||||||
List(
|
List(
|
||||||
IR.DefinitionArgument.Specified(
|
IR.DefinitionArgument.Specified(
|
||||||
IR.Name.Literal(newName.name, None),
|
IR.Name.Literal(newName.name, isReferent = false, None),
|
||||||
None,
|
None,
|
||||||
suspended = false,
|
suspended = false,
|
||||||
None
|
None
|
||||||
@ -207,7 +207,8 @@ case object LambdaShorthandToLambda extends IRPass {
|
|||||||
IR.Function.Lambda(
|
IR.Function.Lambda(
|
||||||
List(
|
List(
|
||||||
IR.DefinitionArgument.Specified(
|
IR.DefinitionArgument.Specified(
|
||||||
IR.Name.Literal(updatedName.get, fn.location),
|
IR.Name
|
||||||
|
.Literal(updatedName.get, isReferent = false, fn.location),
|
||||||
None,
|
None,
|
||||||
suspended = false,
|
suspended = false,
|
||||||
None
|
None
|
||||||
@ -320,7 +321,11 @@ case object LambdaShorthandToLambda extends IRPass {
|
|||||||
case IR.CallArgument.Specified(_, value, _, _, passData, diagnostics) =>
|
case IR.CallArgument.Specified(_, value, _, _, passData, diagnostics) =>
|
||||||
// Note [Safe Casting to IR.Name.Literal]
|
// Note [Safe Casting to IR.Name.Literal]
|
||||||
val defArgName =
|
val defArgName =
|
||||||
IR.Name.Literal(value.asInstanceOf[IR.Name.Literal].name, None)
|
IR.Name.Literal(
|
||||||
|
value.asInstanceOf[IR.Name.Literal].name,
|
||||||
|
isReferent = false,
|
||||||
|
None
|
||||||
|
)
|
||||||
|
|
||||||
Some(
|
Some(
|
||||||
IR.DefinitionArgument.Specified(
|
IR.DefinitionArgument.Specified(
|
||||||
|
@ -249,9 +249,9 @@ case object IgnoredBindings extends IRPass {
|
|||||||
*/
|
*/
|
||||||
def isIgnore(ir: IR.Name): Boolean = {
|
def isIgnore(ir: IR.Name): Boolean = {
|
||||||
ir match {
|
ir match {
|
||||||
case _: IR.Name.Blank => true
|
case _: IR.Name.Blank => true
|
||||||
case IR.Name.Literal(name, _, _, _) => name == "_"
|
case IR.Name.Literal(name, _, _, _, _) => name == "_"
|
||||||
case _ => false
|
case _ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,12 +55,33 @@ case object MethodDefinitions extends IRPass {
|
|||||||
BindingsMap.ResolvedModule(availableSymbolsMap.currentModule)
|
BindingsMap.ResolvedModule(availableSymbolsMap.currentModule)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
case tp @ IR.Name.Qualified(List(item), _, _, _) =>
|
case tp @ IR.Name.Qualified(names, _, _, _) =>
|
||||||
availableSymbolsMap.resolveUppercaseName(item.name) match {
|
val items = names.map(_.name)
|
||||||
|
availableSymbolsMap.resolveQualifiedName(items) match {
|
||||||
case Left(err) =>
|
case Left(err) =>
|
||||||
IR.Error.Resolution(tp, IR.Error.Resolution.Reason(err))
|
IR.Error.Resolution(tp, IR.Error.Resolution.ResolverError(err))
|
||||||
case Right(candidate) =>
|
case Right(value: BindingsMap.ResolvedConstructor) =>
|
||||||
tp.updateMetadata(this -->> BindingsMap.Resolution(candidate))
|
tp.updateMetadata(
|
||||||
|
this -->> BindingsMap.Resolution(value)
|
||||||
|
)
|
||||||
|
case Right(value: BindingsMap.ResolvedModule) =>
|
||||||
|
tp.updateMetadata(
|
||||||
|
this -->> BindingsMap.Resolution(value)
|
||||||
|
)
|
||||||
|
case Right(_: BindingsMap.ResolvedPolyglotSymbol) =>
|
||||||
|
IR.Error.Resolution(
|
||||||
|
tp,
|
||||||
|
IR.Error.Resolution.UnexpectedPolyglot(
|
||||||
|
"a method definition target"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
case Right(_: BindingsMap.ResolvedMethod) =>
|
||||||
|
IR.Error.Resolution(
|
||||||
|
tp,
|
||||||
|
IR.Error.Resolution.UnexpectedMethod(
|
||||||
|
"a method definition target"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
case tp: IR.Error.Resolution => tp
|
case tp: IR.Error.Resolution => tp
|
||||||
case _ =>
|
case _ =>
|
||||||
|
@ -4,6 +4,7 @@ import org.enso.compiler.context.{InlineContext, ModuleContext}
|
|||||||
import org.enso.compiler.core.IR
|
import org.enso.compiler.core.IR
|
||||||
import org.enso.compiler.core.ir.MetadataStorage.ToPair
|
import org.enso.compiler.core.ir.MetadataStorage.ToPair
|
||||||
import org.enso.compiler.data.BindingsMap
|
import org.enso.compiler.data.BindingsMap
|
||||||
|
import org.enso.compiler.exception.CompilerError
|
||||||
import org.enso.compiler.pass.IRPass
|
import org.enso.compiler.pass.IRPass
|
||||||
import org.enso.compiler.pass.analyse.{AliasAnalysis, BindingAnalysis}
|
import org.enso.compiler.pass.analyse.{AliasAnalysis, BindingAnalysis}
|
||||||
import org.enso.compiler.pass.desugar.{GenerateMethodBodies, NestedPatternMatch}
|
import org.enso.compiler.pass.desugar.{GenerateMethodBodies, NestedPatternMatch}
|
||||||
@ -69,27 +70,60 @@ object Patterns extends IRPass {
|
|||||||
val newBranches = caseExpr.branches.map { branch =>
|
val newBranches = caseExpr.branches.map { branch =>
|
||||||
val resolvedPattern = branch.pattern match {
|
val resolvedPattern = branch.pattern match {
|
||||||
case consPat: IR.Pattern.Constructor =>
|
case consPat: IR.Pattern.Constructor =>
|
||||||
val resolvedName = consPat.constructor match {
|
val consName = consPat.constructor
|
||||||
|
val resolution = consName match {
|
||||||
|
case qual: IR.Name.Qualified =>
|
||||||
|
val parts = qual.parts.map(_.name)
|
||||||
|
Some(bindings.resolveQualifiedName(parts))
|
||||||
case lit: IR.Name.Literal =>
|
case lit: IR.Name.Literal =>
|
||||||
val resolution = bindings.resolveUppercaseName(lit.name)
|
Some(bindings.resolveUppercaseName(lit.name))
|
||||||
resolution match {
|
case _ => None
|
||||||
case Left(err) =>
|
|
||||||
IR.Error.Resolution(
|
|
||||||
consPat.constructor,
|
|
||||||
IR.Error.Resolution.Reason(err)
|
|
||||||
)
|
|
||||||
case Right(value) =>
|
|
||||||
lit.updateMetadata(
|
|
||||||
this -->> BindingsMap.Resolution(value)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
case other => other
|
|
||||||
}
|
}
|
||||||
val resolution = resolvedName.getMetadata(this)
|
val resolvedName = resolution
|
||||||
val expectedArity = resolution.map { res =>
|
.map {
|
||||||
|
case Left(err) =>
|
||||||
|
IR.Error.Resolution(
|
||||||
|
consPat.constructor,
|
||||||
|
IR.Error.Resolution.ResolverError(err)
|
||||||
|
)
|
||||||
|
case Right(value: BindingsMap.ResolvedConstructor) =>
|
||||||
|
consName.updateMetadata(
|
||||||
|
this -->> BindingsMap.Resolution(value)
|
||||||
|
)
|
||||||
|
case Right(value: BindingsMap.ResolvedModule) =>
|
||||||
|
consName.updateMetadata(
|
||||||
|
this -->> BindingsMap.Resolution(value)
|
||||||
|
)
|
||||||
|
case Right(_: BindingsMap.ResolvedPolyglotSymbol) =>
|
||||||
|
IR.Error.Resolution(
|
||||||
|
consName,
|
||||||
|
IR.Error.Resolution.UnexpectedPolyglot(
|
||||||
|
"a pattern match"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
case Right(_: BindingsMap.ResolvedMethod) =>
|
||||||
|
IR.Error.Resolution(
|
||||||
|
consName,
|
||||||
|
IR.Error.Resolution.UnexpectedMethod(
|
||||||
|
"a pattern match"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.getOrElse(consName)
|
||||||
|
|
||||||
|
val actualResolution = resolvedName.getMetadata(this)
|
||||||
|
val expectedArity = actualResolution.map { res =>
|
||||||
res.target match {
|
res.target match {
|
||||||
case BindingsMap.ResolvedConstructor(_, cons) => cons.arity
|
case BindingsMap.ResolvedConstructor(_, cons) => cons.arity
|
||||||
case BindingsMap.ResolvedModule(_) => 0
|
case BindingsMap.ResolvedModule(_) => 0
|
||||||
|
case BindingsMap.ResolvedPolyglotSymbol(_, _) =>
|
||||||
|
throw new CompilerError(
|
||||||
|
"Impossible, should be transformed into an error before."
|
||||||
|
)
|
||||||
|
case BindingsMap.ResolvedMethod(_, _) =>
|
||||||
|
throw new CompilerError(
|
||||||
|
"Impossible, should be transformed into an error before."
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expectedArity match {
|
expectedArity match {
|
||||||
|
@ -189,7 +189,7 @@ case object SuspendedArguments extends IRPass {
|
|||||||
signature match {
|
signature match {
|
||||||
case IR.Application.Operator.Binary(
|
case IR.Application.Operator.Binary(
|
||||||
l,
|
l,
|
||||||
IR.Name.Literal("->", _, _, _),
|
IR.Name.Literal("->", _, _, _, _),
|
||||||
r,
|
r,
|
||||||
_,
|
_,
|
||||||
_,
|
_,
|
||||||
@ -210,8 +210,8 @@ case object SuspendedArguments extends IRPass {
|
|||||||
*/
|
*/
|
||||||
def representsSuspended(value: IR.Expression): Boolean = {
|
def representsSuspended(value: IR.Expression): Boolean = {
|
||||||
value match {
|
value match {
|
||||||
case IR.Name.Literal("Suspended", _, _, _) => true
|
case IR.Name.Literal("Suspended", _, _, _, _) => true
|
||||||
case _ => false
|
case _ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,280 @@
|
|||||||
|
package org.enso.compiler.pass.resolve
|
||||||
|
|
||||||
|
import org.enso.compiler.context.{FreshNameSupply, InlineContext, ModuleContext}
|
||||||
|
import org.enso.compiler.core.IR
|
||||||
|
import org.enso.compiler.core.ir.MetadataStorage.ToPair
|
||||||
|
import org.enso.compiler.data.BindingsMap
|
||||||
|
import org.enso.compiler.data.BindingsMap.{
|
||||||
|
Resolution,
|
||||||
|
ResolvedConstructor,
|
||||||
|
ResolvedMethod
|
||||||
|
}
|
||||||
|
import org.enso.compiler.exception.CompilerError
|
||||||
|
import org.enso.compiler.pass.IRPass
|
||||||
|
import org.enso.compiler.pass.analyse.{AliasAnalysis, BindingAnalysis}
|
||||||
|
import org.enso.interpreter.Constants
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves and desugars referent name occurences in non-pattern contexts.
|
||||||
|
*
|
||||||
|
* 1. Attaches resolution metadata to encountered constructors, modules,
|
||||||
|
* and polygot symbols.
|
||||||
|
* 2. Desugars encountered method references into proper applications.
|
||||||
|
* 3. Resolves qualified calls to constructors, i.e. a call of the form
|
||||||
|
* `KnownModule.consName a b c` is transformed into `KnownCons a b c`,
|
||||||
|
* if `consName` refers to a constructor and `KnownModule` was successfully
|
||||||
|
* resolved to a module.
|
||||||
|
*/
|
||||||
|
case object UppercaseNames extends IRPass {
|
||||||
|
|
||||||
|
/** The type of the metadata object that the pass writes to the IR. */
|
||||||
|
override type Metadata = BindingsMap.Resolution
|
||||||
|
|
||||||
|
/** The type of configuration for the pass. */
|
||||||
|
override type Config = IRPass.Configuration.Default
|
||||||
|
|
||||||
|
/** The passes that this pass depends _directly_ on to run. */
|
||||||
|
override val precursorPasses: Seq[IRPass] =
|
||||||
|
Seq(AliasAnalysis, BindingAnalysis)
|
||||||
|
|
||||||
|
/** The passes that are invalidated by running this pass. */
|
||||||
|
override val invalidatedPasses: Seq[IRPass] = Seq(AliasAnalysis)
|
||||||
|
|
||||||
|
/** Executes the pass on the provided `ir`, and returns a possibly transformed
|
||||||
|
* or annotated version of `ir`.
|
||||||
|
*
|
||||||
|
* @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 = {
|
||||||
|
val scopeMap = ir.unsafeGetMetadata(
|
||||||
|
BindingAnalysis,
|
||||||
|
"No binding analysis on the module"
|
||||||
|
)
|
||||||
|
val freshNameSupply = moduleContext.freshNameSupply.getOrElse(
|
||||||
|
throw new CompilerError(
|
||||||
|
"No fresh name supply passed to UppercaseNames resolver."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ir.mapExpressions(processExpression(_, scopeMap, freshNameSupply))
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Executes the pass on the provided `ir`, and returns a possibly transformed
|
||||||
|
* or annotated version of `ir` in an inline context.
|
||||||
|
*
|
||||||
|
* @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 = {
|
||||||
|
val scopeMap = inlineContext.module.getIr.unsafeGetMetadata(
|
||||||
|
BindingAnalysis,
|
||||||
|
"No binding analysis on the module"
|
||||||
|
)
|
||||||
|
val freshNameSupply = inlineContext.freshNameSupply.getOrElse(
|
||||||
|
throw new CompilerError(
|
||||||
|
"No fresh name supply passed to UppercaseNames resolver."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
processExpression(ir, scopeMap, freshNameSupply)
|
||||||
|
}
|
||||||
|
|
||||||
|
private def processExpression(
|
||||||
|
ir: IR.Expression,
|
||||||
|
bindings: BindingsMap,
|
||||||
|
freshNameSupply: FreshNameSupply,
|
||||||
|
isInsideApplication: Boolean = false
|
||||||
|
): IR.Expression =
|
||||||
|
ir.transformExpressions {
|
||||||
|
case lit: IR.Name.Literal =>
|
||||||
|
if (lit.isReferent && !isLocalVar(lit)) {
|
||||||
|
val resolution = bindings.resolveUppercaseName(lit.name)
|
||||||
|
resolution match {
|
||||||
|
case Left(error) =>
|
||||||
|
IR.Error.Resolution(
|
||||||
|
lit,
|
||||||
|
IR.Error.Resolution.ResolverError(error)
|
||||||
|
)
|
||||||
|
case Right(r @ BindingsMap.ResolvedMethod(mod, method)) =>
|
||||||
|
if (isInsideApplication) {
|
||||||
|
lit.updateMetadata(this -->> BindingsMap.Resolution(r))
|
||||||
|
|
||||||
|
} else {
|
||||||
|
val self = freshNameSupply
|
||||||
|
.newName(isReferent = true)
|
||||||
|
.updateMetadata(
|
||||||
|
this -->> BindingsMap.Resolution(
|
||||||
|
BindingsMap.ResolvedModule(mod)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val fun = lit.copy(name = method.name)
|
||||||
|
val app = IR.Application.Prefix(
|
||||||
|
fun,
|
||||||
|
List(IR.CallArgument.Specified(None, self, None)),
|
||||||
|
hasDefaultsSuspended = false,
|
||||||
|
None
|
||||||
|
)
|
||||||
|
app
|
||||||
|
}
|
||||||
|
case Right(value) =>
|
||||||
|
lit.updateMetadata(this -->> BindingsMap.Resolution(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { lit }
|
||||||
|
case app: IR.Application.Prefix =>
|
||||||
|
app.function match {
|
||||||
|
case n: IR.Name.Literal =>
|
||||||
|
if (n.isReferent)
|
||||||
|
resolveReferantApplication(app, bindings, freshNameSupply)
|
||||||
|
else resolveLocalApplication(app, bindings, freshNameSupply)
|
||||||
|
case _ =>
|
||||||
|
app.mapExpressions(processExpression(_, bindings, freshNameSupply))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private def resolveReferantApplication(
|
||||||
|
app: IR.Application.Prefix,
|
||||||
|
bindingsMap: BindingsMap,
|
||||||
|
freshNameSupply: FreshNameSupply
|
||||||
|
): IR.Expression = {
|
||||||
|
val processedFun = processExpression(
|
||||||
|
app.function,
|
||||||
|
bindingsMap,
|
||||||
|
freshNameSupply,
|
||||||
|
isInsideApplication = true
|
||||||
|
)
|
||||||
|
val processedArgs = app.arguments.map(
|
||||||
|
_.mapExpressions(processExpression(_, bindingsMap, freshNameSupply))
|
||||||
|
)
|
||||||
|
processedFun.getMetadata(this) match {
|
||||||
|
case Some(Resolution(ResolvedMethod(mod, method))) =>
|
||||||
|
val self = freshNameSupply
|
||||||
|
.newName(isReferent = true)
|
||||||
|
.updateMetadata(
|
||||||
|
this -->> BindingsMap.Resolution(
|
||||||
|
BindingsMap.ResolvedModule(mod)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val selfArg = IR.CallArgument.Specified(None, self, None)
|
||||||
|
processedFun.passData.remove(this)
|
||||||
|
val renamed = rename(processedFun, method.name)
|
||||||
|
app.copy(function = renamed, arguments = selfArg :: processedArgs)
|
||||||
|
case _ => app.copy(function = processedFun, arguments = processedArgs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def rename(name: IR.Expression, newName: String): IR.Expression =
|
||||||
|
name match {
|
||||||
|
case lit: IR.Name.Literal => lit.copy(name = newName)
|
||||||
|
case _ => name
|
||||||
|
}
|
||||||
|
|
||||||
|
private def resolveLocalApplication(
|
||||||
|
app: IR.Application.Prefix,
|
||||||
|
bindings: BindingsMap,
|
||||||
|
freshNameSupply: FreshNameSupply
|
||||||
|
): IR.Expression = {
|
||||||
|
val processedFun =
|
||||||
|
processExpression(app.function, bindings, freshNameSupply)
|
||||||
|
val processedArgs =
|
||||||
|
app.arguments.map(
|
||||||
|
_.mapExpressions(processExpression(_, bindings, freshNameSupply))
|
||||||
|
)
|
||||||
|
val newApp: Option[IR.Expression] = for {
|
||||||
|
thisArgPos <- findThisPosition(processedArgs)
|
||||||
|
thisArg = processedArgs(thisArgPos)
|
||||||
|
thisArgResolution <- thisArg.value.getMetadata(this)
|
||||||
|
funAsVar <- asGlobalVar(processedFun)
|
||||||
|
cons <- resolveToCons(thisArgResolution, funAsVar)
|
||||||
|
newFun =
|
||||||
|
buildSymbolFor(cons, freshNameSupply).setLocation(funAsVar.location)
|
||||||
|
newArgs = processedArgs.patch(thisArgPos, Nil, 1)
|
||||||
|
} yield buildConsApplication(app, cons.cons, newFun, newArgs)
|
||||||
|
newApp.getOrElse(
|
||||||
|
app.copy(function = processedFun, arguments = processedArgs)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private def buildConsApplication(
|
||||||
|
originalApp: IR.Application.Prefix,
|
||||||
|
calledCons: BindingsMap.Cons,
|
||||||
|
newFun: IR.Expression,
|
||||||
|
newArgs: List[IR.CallArgument]
|
||||||
|
): IR.Expression = {
|
||||||
|
if (
|
||||||
|
newArgs.isEmpty && (!originalApp.hasDefaultsSuspended || calledCons.arity == 0)
|
||||||
|
) {
|
||||||
|
newFun
|
||||||
|
} else {
|
||||||
|
originalApp.copy(function = newFun, arguments = newArgs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def buildSymbolFor(
|
||||||
|
cons: BindingsMap.ResolvedConstructor,
|
||||||
|
freshNameSupply: FreshNameSupply
|
||||||
|
): IR.Expression = {
|
||||||
|
freshNameSupply
|
||||||
|
.newName(isReferent = true)
|
||||||
|
.updateMetadata(this -->> BindingsMap.Resolution(cons))
|
||||||
|
}
|
||||||
|
|
||||||
|
private def resolveToCons(
|
||||||
|
thisResolution: BindingsMap.Resolution,
|
||||||
|
consName: IR.Name.Literal
|
||||||
|
): Option[BindingsMap.ResolvedConstructor] =
|
||||||
|
thisResolution.target match {
|
||||||
|
case BindingsMap.ResolvedModule(module) =>
|
||||||
|
val resolution = module.getIr
|
||||||
|
.unsafeGetMetadata(
|
||||||
|
BindingAnalysis,
|
||||||
|
"Imported module without bindings analysis results"
|
||||||
|
)
|
||||||
|
.resolveExportedName(consName.name)
|
||||||
|
resolution match {
|
||||||
|
case Right(cons @ ResolvedConstructor(_, _)) => Some(cons)
|
||||||
|
case _ => None
|
||||||
|
}
|
||||||
|
case _ => None
|
||||||
|
}
|
||||||
|
|
||||||
|
private def findThisPosition(args: List[IR.CallArgument]): Option[Int] = {
|
||||||
|
val ix = args.indexWhere(arg =>
|
||||||
|
arg.name.exists(
|
||||||
|
_.name == Constants.Names.THIS_ARGUMENT
|
||||||
|
) || arg.name.isEmpty
|
||||||
|
)
|
||||||
|
if (ix == -1) None else Some(ix)
|
||||||
|
}
|
||||||
|
|
||||||
|
private def asGlobalVar(ir: IR): Option[IR.Name.Literal] =
|
||||||
|
ir match {
|
||||||
|
case name: IR.Name.Literal =>
|
||||||
|
if (isLocalVar(name) || name.isReferent) None else Some(name)
|
||||||
|
case _ => None
|
||||||
|
}
|
||||||
|
|
||||||
|
private def isLocalVar(name: IR.Name.Literal): Boolean = {
|
||||||
|
val aliasInfo = name
|
||||||
|
.unsafeGetMetadata(
|
||||||
|
AliasAnalysis,
|
||||||
|
"no alias analysis info on a name"
|
||||||
|
)
|
||||||
|
.unsafeAs[AliasAnalysis.Info.Occurrence]
|
||||||
|
val defLink = aliasInfo.graph.defLinkFor(aliasInfo.id)
|
||||||
|
defLink.isDefined
|
||||||
|
}
|
||||||
|
}
|
@ -21,14 +21,29 @@ object StubIrBuilder {
|
|||||||
* @return the built stub IR.
|
* @return the built stub IR.
|
||||||
*/
|
*/
|
||||||
def build(module: Module): IR.Module = {
|
def build(module: Module): IR.Module = {
|
||||||
val ir = IR.Module(List(), List(), None)
|
val ir = IR.Module(List(), List(), None)
|
||||||
|
val scope = module.getScope
|
||||||
|
val conses = scope.getConstructors.asScala
|
||||||
|
val consNames = conses.keys.map(_.toLowerCase()).toSet
|
||||||
val definedConstructors: List[BindingsMap.Cons] =
|
val definedConstructors: List[BindingsMap.Cons] =
|
||||||
module.getScope.getConstructors.asScala.toList.map {
|
conses.toList.map {
|
||||||
case (name, cons) =>
|
case (name, cons) =>
|
||||||
BindingsMap.Cons(name, cons.getArity)
|
BindingsMap.Cons(name, cons.getArity)
|
||||||
}
|
}
|
||||||
|
val moduleMethods = Option(scope.getMethods.get(scope.getAssociatedType))
|
||||||
|
.map(methods =>
|
||||||
|
methods.asScala.keys
|
||||||
|
.filter(!consNames.contains(_))
|
||||||
|
.map(name => BindingsMap.ModuleMethod(name))
|
||||||
|
.toList
|
||||||
|
)
|
||||||
|
.getOrElse(List())
|
||||||
|
val polyglot = scope.getPolyglotSymbols.asScala.keys.toList
|
||||||
|
.map(BindingsMap.PolyglotSymbol)
|
||||||
val meta = BindingsMap(
|
val meta = BindingsMap(
|
||||||
definedConstructors,
|
definedConstructors,
|
||||||
|
polyglot,
|
||||||
|
moduleMethods,
|
||||||
module
|
module
|
||||||
)
|
)
|
||||||
ir.updateMetadata(BindingAnalysis -->> meta)
|
ir.updateMetadata(BindingAnalysis -->> meta)
|
||||||
|
@ -149,7 +149,7 @@ trait CompilerRunner {
|
|||||||
* @return an IR name representing the name `str`
|
* @return an IR name representing the name `str`
|
||||||
*/
|
*/
|
||||||
def nameFromString(str: String): IR.Name.Literal = {
|
def nameFromString(str: String): IR.Name.Literal = {
|
||||||
IR.Name.Literal(str, None)
|
IR.Name.Literal(str, isReferent = false, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
// === IR Testing Utils =====================================================
|
// === IR Testing Utils =====================================================
|
||||||
@ -167,8 +167,11 @@ trait CompilerRunner {
|
|||||||
def asMethod: IR.Module.Scope.Definition.Method = {
|
def asMethod: IR.Module.Scope.Definition.Method = {
|
||||||
IR.Module.Scope.Definition.Method.Explicit(
|
IR.Module.Scope.Definition.Method.Explicit(
|
||||||
IR.Name.MethodReference(
|
IR.Name.MethodReference(
|
||||||
IR.Name.Qualified(List(IR.Name.Literal("TestType", None)), None),
|
IR.Name.Qualified(
|
||||||
IR.Name.Literal("testMethod", None),
|
List(IR.Name.Literal("TestType", isReferent = true, None)),
|
||||||
|
None
|
||||||
|
),
|
||||||
|
IR.Name.Literal("testMethod", isReferent = false, None),
|
||||||
None
|
None
|
||||||
),
|
),
|
||||||
ir,
|
ir,
|
||||||
@ -182,11 +185,11 @@ trait CompilerRunner {
|
|||||||
*/
|
*/
|
||||||
def asAtomDefaultArg: IR.Module.Scope.Definition.Atom = {
|
def asAtomDefaultArg: IR.Module.Scope.Definition.Atom = {
|
||||||
IR.Module.Scope.Definition.Atom(
|
IR.Module.Scope.Definition.Atom(
|
||||||
IR.Name.Literal("TestAtom", None),
|
IR.Name.Literal("TestAtom", isReferent = true, None),
|
||||||
List(
|
List(
|
||||||
IR.DefinitionArgument
|
IR.DefinitionArgument
|
||||||
.Specified(
|
.Specified(
|
||||||
IR.Name.Literal("arg", None),
|
IR.Name.Literal("arg", isReferent = false, None),
|
||||||
Some(ir),
|
Some(ir),
|
||||||
suspended = false,
|
suspended = false,
|
||||||
None
|
None
|
||||||
|
@ -320,7 +320,11 @@ class AstToIrTest extends CompilerTest with Inside {
|
|||||||
ir shouldBe an[IR.Application.Prefix]
|
ir shouldBe an[IR.Application.Prefix]
|
||||||
|
|
||||||
val fn = ir.asInstanceOf[IR.Application.Prefix]
|
val fn = ir.asInstanceOf[IR.Application.Prefix]
|
||||||
fn.function shouldEqual IR.Name.Literal("negate", None)
|
fn.function shouldEqual IR.Name.Literal(
|
||||||
|
"negate",
|
||||||
|
isReferent = false,
|
||||||
|
None
|
||||||
|
)
|
||||||
|
|
||||||
val fooArg = fn.arguments.head.asInstanceOf[IR.CallArgument.Specified]
|
val fooArg = fn.arguments.head.asInstanceOf[IR.CallArgument.Specified]
|
||||||
fooArg.value shouldBe an[IR.Name.Literal]
|
fooArg.value shouldBe an[IR.Name.Literal]
|
||||||
|
@ -4,7 +4,7 @@ import org.enso.compiler.Passes
|
|||||||
import org.enso.compiler.context.{FreshNameSupply, ModuleContext}
|
import org.enso.compiler.context.{FreshNameSupply, ModuleContext}
|
||||||
import org.enso.compiler.core.IR
|
import org.enso.compiler.core.IR
|
||||||
import org.enso.compiler.data.BindingsMap
|
import org.enso.compiler.data.BindingsMap
|
||||||
import org.enso.compiler.data.BindingsMap.Cons
|
import org.enso.compiler.data.BindingsMap.{Cons, ModuleMethod, PolyglotSymbol}
|
||||||
import org.enso.compiler.pass.analyse.BindingAnalysis
|
import org.enso.compiler.pass.analyse.BindingAnalysis
|
||||||
import org.enso.compiler.pass.{PassConfiguration, PassGroup, PassManager}
|
import org.enso.compiler.pass.{PassConfiguration, PassGroup, PassManager}
|
||||||
import org.enso.compiler.test.CompilerTest
|
import org.enso.compiler.test.CompilerTest
|
||||||
@ -50,18 +50,24 @@ class BindingAnalysisTest extends CompilerTest {
|
|||||||
|
|
||||||
val ir =
|
val ir =
|
||||||
"""
|
"""
|
||||||
|
|polyglot java import foo.bar.baz.MyClass
|
||||||
|
|
|
||||||
|type Foo a b c
|
|type Foo a b c
|
||||||
|type Bar
|
|type Bar
|
||||||
|type Baz x y
|
|type Baz x y
|
||||||
|
|
|
|
||||||
|Baz.foo = 123
|
|Baz.foo = 123
|
||||||
|Bar.baz = Baz 1 2 . foo
|
|Bar.baz = Baz 1 2 . foo
|
||||||
|
|
|
||||||
|
|foo = 123
|
||||||
|""".stripMargin.preprocessModule.analyse
|
|""".stripMargin.preprocessModule.analyse
|
||||||
|
|
||||||
"discover all atoms in a module" in {
|
"discover all atoms, methods, and polyglot symbols in a module" in {
|
||||||
ir.getMetadata(BindingAnalysis) shouldEqual Some(
|
ir.getMetadata(BindingAnalysis) shouldEqual Some(
|
||||||
BindingsMap(
|
BindingsMap(
|
||||||
List(Cons("Foo", 3), Cons("Bar", 0), Cons("Baz", 2)),
|
List(Cons("Foo", 3), Cons("Bar", 0), Cons("Baz", 2)),
|
||||||
|
List(PolyglotSymbol("MyClass")),
|
||||||
|
List(ModuleMethod("foo")),
|
||||||
ctx.module
|
ctx.module
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -303,7 +303,7 @@ class DataflowAnalysisTest extends CompilerTest {
|
|||||||
val printlnFn = printlnExpr.function.asInstanceOf[IR.Name.Literal]
|
val printlnFn = printlnExpr.function.asInstanceOf[IR.Name.Literal]
|
||||||
val printlnArgIO =
|
val printlnArgIO =
|
||||||
printlnExpr.arguments.head.asInstanceOf[IR.CallArgument.Specified]
|
printlnExpr.arguments.head.asInstanceOf[IR.CallArgument.Specified]
|
||||||
val printlnArgIOExpr = printlnArgIO.value.asInstanceOf[IR.Name.Literal]
|
val printlnArgIOExpr = printlnArgIO.value.asInstanceOf[IR.Error.Resolution]
|
||||||
val printlnArgB =
|
val printlnArgB =
|
||||||
printlnExpr.arguments(1).asInstanceOf[IR.CallArgument.Specified]
|
printlnExpr.arguments(1).asInstanceOf[IR.CallArgument.Specified]
|
||||||
val printlnArgBExpr = printlnArgB.value.asInstanceOf[IR.Name.Literal]
|
val printlnArgBExpr = printlnArgB.value.asInstanceOf[IR.Name.Literal]
|
||||||
|
@ -16,7 +16,7 @@ class GatherDiagnosticsTest extends CompilerTest {
|
|||||||
AST.Invalid.Unrecognized("@@"),
|
AST.Invalid.Unrecognized("@@"),
|
||||||
IR.Error.Syntax.UnrecognizedToken
|
IR.Error.Syntax.UnrecognizedToken
|
||||||
)
|
)
|
||||||
val plusOp = IR.Name.Literal("+", None)
|
val plusOp = IR.Name.Literal("+", isReferent = false, None)
|
||||||
val plusApp = IR.Application.Prefix(
|
val plusApp = IR.Application.Prefix(
|
||||||
plusOp,
|
plusOp,
|
||||||
List(
|
List(
|
||||||
@ -29,7 +29,7 @@ class GatherDiagnosticsTest extends CompilerTest {
|
|||||||
List(
|
List(
|
||||||
IR.DefinitionArgument
|
IR.DefinitionArgument
|
||||||
.Specified(
|
.Specified(
|
||||||
IR.Name.Literal("bar", None),
|
IR.Name.Literal("bar", isReferent = false, None),
|
||||||
None,
|
None,
|
||||||
suspended = false,
|
suspended = false,
|
||||||
None
|
None
|
||||||
@ -59,10 +59,10 @@ class GatherDiagnosticsTest extends CompilerTest {
|
|||||||
IR.Error.Syntax.UnexpectedExpression
|
IR.Error.Syntax.UnexpectedExpression
|
||||||
)
|
)
|
||||||
|
|
||||||
val typeName = IR.Name.Literal("Foo", None)
|
val typeName = IR.Name.Literal("Foo", isReferent = false, None)
|
||||||
val method1Name = IR.Name.Literal("bar", None)
|
val method1Name = IR.Name.Literal("bar", isReferent = false, None)
|
||||||
val method2Name = IR.Name.Literal("baz", None)
|
val method2Name = IR.Name.Literal("baz", isReferent = false, None)
|
||||||
val fooName = IR.Name.Literal("foo", None)
|
val fooName = IR.Name.Literal("foo", isReferent = false, None)
|
||||||
|
|
||||||
val method1Ref =
|
val method1Ref =
|
||||||
IR.Name.MethodReference(
|
IR.Name.MethodReference(
|
||||||
|
@ -45,14 +45,14 @@ class OperatorToFunctionTest extends CompilerTest {
|
|||||||
// === The Tests ============================================================
|
// === The Tests ============================================================
|
||||||
|
|
||||||
"Operators" should {
|
"Operators" should {
|
||||||
val opName = IR.Name.Literal("=:=", None)
|
val opName = IR.Name.Literal("=:=", isReferent = false, None)
|
||||||
val left = IR.Empty(None)
|
val left = IR.Empty(None)
|
||||||
val right = IR.Empty(None)
|
val right = IR.Empty(None)
|
||||||
val rightArg = IR.CallArgument.Specified(None, IR.Empty(None), None)
|
val rightArg = IR.CallArgument.Specified(None, IR.Empty(None), None)
|
||||||
|
|
||||||
val (operator, operatorFn) = genOprAndFn(opName, left, right)
|
val (operator, operatorFn) = genOprAndFn(opName, left, right)
|
||||||
|
|
||||||
val oprArg = IR.CallArgument.Specified(None, operator, None)
|
val oprArg = IR.CallArgument.Specified(None, operator, None)
|
||||||
val oprFnArg = IR.CallArgument.Specified(None, operatorFn, None)
|
val oprFnArg = IR.CallArgument.Specified(None, operatorFn, None)
|
||||||
|
|
||||||
"be translated to functions" in {
|
"be translated to functions" in {
|
||||||
@ -76,7 +76,10 @@ class OperatorToFunctionTest extends CompilerTest {
|
|||||||
None
|
None
|
||||||
)
|
)
|
||||||
|
|
||||||
OperatorToFunction.runExpression(recursiveIR, ctx) shouldEqual recursiveIRResult
|
OperatorToFunction.runExpression(
|
||||||
|
recursiveIR,
|
||||||
|
ctx
|
||||||
|
) shouldEqual recursiveIRResult
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ class ApplicationSaturationTest extends CompilerTest {
|
|||||||
val name = if (positional) {
|
val name = if (positional) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(IR.Name.Literal("a", None))
|
Some(IR.Name.Literal("a", isReferent = false, None))
|
||||||
}
|
}
|
||||||
|
|
||||||
List.fill(n)(IR.CallArgument.Specified(name, IR.Empty(None), None))
|
List.fill(n)(IR.CallArgument.Specified(name, IR.Empty(None), None))
|
||||||
@ -83,7 +83,7 @@ class ApplicationSaturationTest extends CompilerTest {
|
|||||||
"Known applications" should {
|
"Known applications" should {
|
||||||
val plusFn = IR.Application
|
val plusFn = IR.Application
|
||||||
.Prefix(
|
.Prefix(
|
||||||
IR.Name.Literal("+", None),
|
IR.Name.Literal("+", isReferent = false, None),
|
||||||
genNArgs(2),
|
genNArgs(2),
|
||||||
hasDefaultsSuspended = false,
|
hasDefaultsSuspended = false,
|
||||||
None
|
None
|
||||||
@ -93,7 +93,7 @@ class ApplicationSaturationTest extends CompilerTest {
|
|||||||
|
|
||||||
val bazFn = IR.Application
|
val bazFn = IR.Application
|
||||||
.Prefix(
|
.Prefix(
|
||||||
IR.Name.Literal("baz", None),
|
IR.Name.Literal("baz", isReferent = false, None),
|
||||||
genNArgs(2),
|
genNArgs(2),
|
||||||
hasDefaultsSuspended = false,
|
hasDefaultsSuspended = false,
|
||||||
None
|
None
|
||||||
@ -103,7 +103,7 @@ class ApplicationSaturationTest extends CompilerTest {
|
|||||||
|
|
||||||
val fooFn = IR.Application
|
val fooFn = IR.Application
|
||||||
.Prefix(
|
.Prefix(
|
||||||
IR.Name.Literal("foo", None),
|
IR.Name.Literal("foo", isReferent = false, None),
|
||||||
genNArgs(5),
|
genNArgs(5),
|
||||||
hasDefaultsSuspended = false,
|
hasDefaultsSuspended = false,
|
||||||
None
|
None
|
||||||
@ -113,8 +113,8 @@ class ApplicationSaturationTest extends CompilerTest {
|
|||||||
|
|
||||||
val fooFnByName = IR.Application
|
val fooFnByName = IR.Application
|
||||||
.Prefix(
|
.Prefix(
|
||||||
IR.Name.Literal("foo", None),
|
IR.Name.Literal("foo", isReferent = false, None),
|
||||||
genNArgs(4, positional = false),
|
genNArgs(4, positional = false),
|
||||||
hasDefaultsSuspended = false,
|
hasDefaultsSuspended = false,
|
||||||
None
|
None
|
||||||
)
|
)
|
||||||
@ -159,7 +159,7 @@ class ApplicationSaturationTest extends CompilerTest {
|
|||||||
"Unknown applications" should {
|
"Unknown applications" should {
|
||||||
val unknownFn = IR.Application
|
val unknownFn = IR.Application
|
||||||
.Prefix(
|
.Prefix(
|
||||||
IR.Name.Literal("unknown", None),
|
IR.Name.Literal("unknown", isReferent = false, None),
|
||||||
genNArgs(10),
|
genNArgs(10),
|
||||||
hasDefaultsSuspended = false,
|
hasDefaultsSuspended = false,
|
||||||
None
|
None
|
||||||
@ -180,7 +180,7 @@ class ApplicationSaturationTest extends CompilerTest {
|
|||||||
val empty = IR.Empty(None)
|
val empty = IR.Empty(None)
|
||||||
val knownPlus = IR.Application
|
val knownPlus = IR.Application
|
||||||
.Prefix(
|
.Prefix(
|
||||||
IR.Name.Literal("+", None),
|
IR.Name.Literal("+", isReferent = false, None),
|
||||||
genNArgs(2),
|
genNArgs(2),
|
||||||
hasDefaultsSuspended = false,
|
hasDefaultsSuspended = false,
|
||||||
None
|
None
|
||||||
@ -190,7 +190,7 @@ class ApplicationSaturationTest extends CompilerTest {
|
|||||||
|
|
||||||
val undersaturatedPlus = IR.Application
|
val undersaturatedPlus = IR.Application
|
||||||
.Prefix(
|
.Prefix(
|
||||||
IR.Name.Literal("+", None),
|
IR.Name.Literal("+", isReferent = false, None),
|
||||||
genNArgs(1),
|
genNArgs(1),
|
||||||
hasDefaultsSuspended = false,
|
hasDefaultsSuspended = false,
|
||||||
None
|
None
|
||||||
@ -200,7 +200,7 @@ class ApplicationSaturationTest extends CompilerTest {
|
|||||||
|
|
||||||
val oversaturatedPlus = IR.Application
|
val oversaturatedPlus = IR.Application
|
||||||
.Prefix(
|
.Prefix(
|
||||||
IR.Name.Literal("+", None),
|
IR.Name.Literal("+", isReferent = false, None),
|
||||||
genNArgs(3),
|
genNArgs(3),
|
||||||
hasDefaultsSuspended = false,
|
hasDefaultsSuspended = false,
|
||||||
None
|
None
|
||||||
@ -222,7 +222,7 @@ class ApplicationSaturationTest extends CompilerTest {
|
|||||||
def outerPlus(argExpr: IR.Expression): IR.Application.Prefix = {
|
def outerPlus(argExpr: IR.Expression): IR.Application.Prefix = {
|
||||||
IR.Application
|
IR.Application
|
||||||
.Prefix(
|
.Prefix(
|
||||||
IR.Name.Literal("+", None),
|
IR.Name.Literal("+", isReferent = false, None),
|
||||||
List(
|
List(
|
||||||
IR.CallArgument.Specified(None, argExpr, None),
|
IR.CallArgument.Specified(None, argExpr, None),
|
||||||
IR.CallArgument.Specified(None, empty, None)
|
IR.CallArgument.Specified(None, empty, None)
|
||||||
|
@ -206,13 +206,13 @@ class LambdaConsolidateTest extends CompilerTest {
|
|||||||
List(
|
List(
|
||||||
IR.DefinitionArgument
|
IR.DefinitionArgument
|
||||||
.Specified(
|
.Specified(
|
||||||
IR.Name.Literal("a", None),
|
IR.Name.Literal("a", isReferent = false, None),
|
||||||
None,
|
None,
|
||||||
suspended = false,
|
suspended = false,
|
||||||
None
|
None
|
||||||
),
|
),
|
||||||
IR.DefinitionArgument.Specified(
|
IR.DefinitionArgument.Specified(
|
||||||
IR.Name.Literal("b", None),
|
IR.Name.Literal("b", isReferent = false, None),
|
||||||
None,
|
None,
|
||||||
suspended = false,
|
suspended = false,
|
||||||
None
|
None
|
||||||
@ -221,13 +221,13 @@ class LambdaConsolidateTest extends CompilerTest {
|
|||||||
IR.Function.Lambda(
|
IR.Function.Lambda(
|
||||||
List(
|
List(
|
||||||
IR.DefinitionArgument.Specified(
|
IR.DefinitionArgument.Specified(
|
||||||
IR.Name.Literal("c", None),
|
IR.Name.Literal("c", isReferent = false, None),
|
||||||
None,
|
None,
|
||||||
suspended = false,
|
suspended = false,
|
||||||
None
|
None
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
IR.Name.Literal("c", None),
|
IR.Name.Literal("c", isReferent = false, None),
|
||||||
None
|
None
|
||||||
),
|
),
|
||||||
None
|
None
|
||||||
|
@ -0,0 +1,131 @@
|
|||||||
|
package org.enso.compiler.test.pass.resolve
|
||||||
|
|
||||||
|
import org.enso.compiler.Passes
|
||||||
|
import org.enso.compiler.context.{FreshNameSupply, ModuleContext}
|
||||||
|
import org.enso.compiler.core.IR
|
||||||
|
import org.enso.compiler.data.BindingsMap.{
|
||||||
|
Cons,
|
||||||
|
Resolution,
|
||||||
|
ResolvedConstructor,
|
||||||
|
ResolvedModule
|
||||||
|
}
|
||||||
|
import org.enso.compiler.pass.resolve.UppercaseNames
|
||||||
|
import org.enso.compiler.pass.{PassConfiguration, PassGroup, PassManager}
|
||||||
|
import org.enso.compiler.test.CompilerTest
|
||||||
|
|
||||||
|
class UppercaseNamesTest extends CompilerTest {
|
||||||
|
|
||||||
|
// === Test Setup ===========================================================
|
||||||
|
|
||||||
|
def mkModuleContext: ModuleContext =
|
||||||
|
buildModuleContext(
|
||||||
|
freshNameSupply = Some(new FreshNameSupply)
|
||||||
|
)
|
||||||
|
|
||||||
|
val passes = new Passes
|
||||||
|
|
||||||
|
val precursorPasses: PassGroup =
|
||||||
|
passes.getPrecursors(UppercaseNames).get
|
||||||
|
|
||||||
|
val passConfiguration: PassConfiguration = PassConfiguration()
|
||||||
|
|
||||||
|
implicit val passManager: PassManager =
|
||||||
|
new PassManager(List(precursorPasses), passConfiguration)
|
||||||
|
|
||||||
|
/** Adds an extension method to analyse an Enso module.
|
||||||
|
*
|
||||||
|
* @param ir the ir to analyse
|
||||||
|
*/
|
||||||
|
implicit class AnalyseModule(ir: IR.Module) {
|
||||||
|
|
||||||
|
/** Performs tail call analysis on [[ir]].
|
||||||
|
*
|
||||||
|
* @param context the module context in which analysis takes place
|
||||||
|
* @return [[ir]], with tail call analysis metadata attached
|
||||||
|
*/
|
||||||
|
def analyse(implicit context: ModuleContext) = {
|
||||||
|
UppercaseNames.runModule(ir, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// === The Tests ============================================================
|
||||||
|
|
||||||
|
"Method definition resolution" should {
|
||||||
|
implicit val ctx: ModuleContext = mkModuleContext
|
||||||
|
|
||||||
|
val code = """
|
||||||
|
|main =
|
||||||
|
| x1 = My_Cons 1 2 3
|
||||||
|
| x2 = Constant
|
||||||
|
| x3 = Add_One 1
|
||||||
|
| x4 = Test_Module.My_Cons 1 2 3
|
||||||
|
| x5 = Does_Not_Exist 32
|
||||||
|
| 0
|
||||||
|
|
|
||||||
|
|type My_Cons a b c
|
||||||
|
|
|
||||||
|
|constant = 2
|
||||||
|
|
|
||||||
|
|add_one x = x + 1
|
||||||
|
|
|
||||||
|
|""".stripMargin
|
||||||
|
val preIr = code.preprocessModule
|
||||||
|
ctx.module.unsafeSetIr(preIr)
|
||||||
|
|
||||||
|
val ir = preIr.analyse
|
||||||
|
|
||||||
|
val bodyExprs = ir
|
||||||
|
.bindings(0)
|
||||||
|
.asInstanceOf[IR.Module.Scope.Definition.Method.Explicit]
|
||||||
|
.body
|
||||||
|
.asInstanceOf[IR.Function.Lambda]
|
||||||
|
.body
|
||||||
|
.asInstanceOf[IR.Expression.Block]
|
||||||
|
.expressions
|
||||||
|
.map(expr => expr.asInstanceOf[IR.Expression.Binding].expression)
|
||||||
|
|
||||||
|
"resolve visible constructors" in {
|
||||||
|
bodyExprs(0)
|
||||||
|
.asInstanceOf[IR.Application.Prefix]
|
||||||
|
.function
|
||||||
|
.getMetadata(UppercaseNames) shouldEqual Some(
|
||||||
|
Resolution(ResolvedConstructor(ctx.module, Cons("My_Cons", 3)))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
"resolve uppercase method names to applications" in {
|
||||||
|
val expr = bodyExprs(1)
|
||||||
|
expr shouldBe an[IR.Application.Prefix]
|
||||||
|
val app = expr.asInstanceOf[IR.Application.Prefix]
|
||||||
|
app.function.asInstanceOf[IR.Name.Literal].name shouldEqual "constant"
|
||||||
|
app.arguments.length shouldEqual 1
|
||||||
|
app.arguments(0).value.getMetadata(UppercaseNames) shouldEqual Some(
|
||||||
|
Resolution(ResolvedModule(ctx.module))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
"resolve uppercase method names in applications by adding the self argument" in {
|
||||||
|
val expr = bodyExprs(2)
|
||||||
|
expr shouldBe an[IR.Application.Prefix]
|
||||||
|
val app = expr.asInstanceOf[IR.Application.Prefix]
|
||||||
|
app.function.asInstanceOf[IR.Name.Literal].name shouldEqual "add_one"
|
||||||
|
app.arguments.length shouldEqual 2
|
||||||
|
app.arguments(0).value.getMetadata(UppercaseNames) shouldEqual Some(
|
||||||
|
Resolution(ResolvedModule(ctx.module))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
"resolve qualified uses of constructors into a simplified form when possible" in {
|
||||||
|
val app = bodyExprs(3).asInstanceOf[IR.Application.Prefix]
|
||||||
|
app.arguments.length shouldBe 3
|
||||||
|
app.function.getMetadata(UppercaseNames) shouldEqual Some(
|
||||||
|
Resolution(ResolvedConstructor(ctx.module, Cons("My_Cons", 3)))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
"indicate resolution failures" in {
|
||||||
|
val app = bodyExprs(4).asInstanceOf[IR.Application.Prefix]
|
||||||
|
app.function shouldBe an[IR.Error.Resolution]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -17,7 +17,7 @@ class ConstructorsTest extends InterpreterTest {
|
|||||||
val patternMatchingCode =
|
val patternMatchingCode =
|
||||||
"""
|
"""
|
||||||
|main =
|
|main =
|
||||||
| x = Cons 1 Nil
|
| x = Builtins.Cons 1 Nil
|
||||||
| case x of
|
| case x of
|
||||||
| Cons h t -> h
|
| Cons h t -> h
|
||||||
| Nil -> 0
|
| Nil -> 0
|
||||||
|
@ -19,10 +19,10 @@ class PatternMatchTest extends InterpreterTest {
|
|||||||
"""
|
"""
|
||||||
|main =
|
|main =
|
||||||
| f = case _ of
|
| f = case _ of
|
||||||
| Cons a _ -> a
|
| Builtins.Cons a _ -> a
|
||||||
| Nil -> -10
|
| Builtins.Nil -> -10
|
||||||
|
|
|
|
||||||
| (10.Cons Nil . f) - Nil.f
|
| (Builtins.Cons 10 Builtins.Nil . f) - Nil.f
|
||||||
|""".stripMargin
|
|""".stripMargin
|
||||||
|
|
||||||
eval(code) shouldEqual 20
|
eval(code) shouldEqual 20
|
||||||
@ -38,7 +38,7 @@ class PatternMatchTest extends InterpreterTest {
|
|||||||
| MyAtom a -> a
|
| MyAtom a -> a
|
||||||
| _ -> -100
|
| _ -> -100
|
||||||
|
|
|
|
||||||
| (50.MyAtom . f) + Nil.f
|
| (MyAtom 50 . f) + Nil.f
|
||||||
|""".stripMargin
|
|""".stripMargin
|
||||||
|
|
||||||
eval(code) shouldEqual -50
|
eval(code) shouldEqual -50
|
||||||
@ -54,7 +54,7 @@ class PatternMatchTest extends InterpreterTest {
|
|||||||
| MyAtom a -> a
|
| MyAtom a -> a
|
||||||
| a -> a + 5
|
| a -> a + 5
|
||||||
|
|
|
|
||||||
| (50.MyAtom . f) + 30.f
|
| (MyAtom 50 . f) + 30.f
|
||||||
|""".stripMargin
|
|""".stripMargin
|
||||||
|
|
||||||
eval(code) shouldEqual 85
|
eval(code) shouldEqual 85
|
||||||
|
@ -43,22 +43,26 @@ object WithDebugCommand {
|
|||||||
|
|
||||||
val printAssemblyOption = "--printAssembly"
|
val printAssemblyOption = "--printAssembly"
|
||||||
|
|
||||||
|
val debuggerOption = "--debugger"
|
||||||
|
|
||||||
val argSeparator = "--"
|
val argSeparator = "--"
|
||||||
|
|
||||||
val commandName = "withDebug"
|
val commandName = "withDebug"
|
||||||
|
|
||||||
val benchOnlyCommandName = "benchOnly"
|
val benchOnlyCommandName = "benchOnly"
|
||||||
val runCommandName = "run"
|
val runCommandName = "run"
|
||||||
|
val testOnlyCommandName = "testOnly"
|
||||||
|
|
||||||
/** The main logic for parsing and transforming the debug flags into JVM level flags */
|
/** The main logic for parsing and transforming the debug flags into JVM level flags */
|
||||||
def withDebug: Command = Command.args(commandName, "<arguments>") {
|
def withDebug: Command =
|
||||||
(state, args) =>
|
Command.args(commandName, "<arguments>") { (state, args) =>
|
||||||
val (debugFlags, prefixedRunArgs) = args.span(_ != argSeparator)
|
val (debugFlags, prefixedRunArgs) = args.span(_ != argSeparator)
|
||||||
val runArgs = " " + prefixedRunArgs.drop(1).mkString(" ")
|
val runArgs = " " + prefixedRunArgs.drop(1).mkString(" ")
|
||||||
|
|
||||||
val taskKey =
|
val taskKey =
|
||||||
if (debugFlags.contains(benchOnlyCommandName)) BenchTasks.benchOnly
|
if (debugFlags.contains(benchOnlyCommandName)) BenchTasks.benchOnly
|
||||||
else if (debugFlags.contains(runCommandName)) Compile / Keys.run
|
else if (debugFlags.contains(runCommandName)) Compile / Keys.run
|
||||||
|
else if (debugFlags.contains(testOnlyCommandName)) Test / Keys.testOnly
|
||||||
else throw new IllegalArgumentException("Invalid command name.")
|
else throw new IllegalArgumentException("Invalid command name.")
|
||||||
|
|
||||||
val dumpGraphsOpts =
|
val dumpGraphsOpts =
|
||||||
@ -72,11 +76,18 @@ object WithDebugCommand {
|
|||||||
if (debugFlags.contains(printAssemblyOption))
|
if (debugFlags.contains(printAssemblyOption))
|
||||||
trufflePrintAssemblyOptions
|
trufflePrintAssemblyOptions
|
||||||
else Seq()
|
else Seq()
|
||||||
|
val debuggerOpts =
|
||||||
|
if (debugFlags.contains(debuggerOption))
|
||||||
|
Seq(
|
||||||
|
"-agentlib:jdwp=transport=dt_socket,server=n,address=localhost:5005,suspend=y"
|
||||||
|
)
|
||||||
|
else Seq()
|
||||||
val javaOpts: Seq[String] = Seq(
|
val javaOpts: Seq[String] = Seq(
|
||||||
truffleNoBackgroundCompilationOptions,
|
truffleNoBackgroundCompilationOptions,
|
||||||
dumpGraphsOpts,
|
dumpGraphsOpts,
|
||||||
showCompilationsOpts,
|
showCompilationsOpts,
|
||||||
printAssemblyOpts
|
printAssemblyOpts,
|
||||||
|
debuggerOpts
|
||||||
).flatten
|
).flatten
|
||||||
|
|
||||||
val extracted = Project.extract(state)
|
val extracted = Project.extract(state)
|
||||||
@ -88,5 +99,5 @@ object WithDebugCommand {
|
|||||||
.extract(withJavaOpts)
|
.extract(withJavaOpts)
|
||||||
.runInputTask(taskKey, runArgs, withJavaOpts)
|
.runInputTask(taskKey, runArgs, withJavaOpts)
|
||||||
state
|
state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,10 @@ import Base.Test
|
|||||||
import Test.List_Spec
|
import Test.List_Spec
|
||||||
import Test.Number_Spec
|
import Test.Number_Spec
|
||||||
import Test.Import_Loop_Spec
|
import Test.Import_Loop_Spec
|
||||||
|
import Test.Names_Spec
|
||||||
|
|
||||||
main = Suite.runMain <|
|
main = Suite.runMain <|
|
||||||
List_Spec.spec
|
List_Spec.spec
|
||||||
Number_Spec.spec
|
Number_Spec.spec
|
||||||
Import_Loop_Spec.spec
|
Import_Loop_Spec.spec
|
||||||
|
Names_Spec.spec
|
||||||
|
6
test/Test/src/Names/Definitions.enso
Normal file
6
test/Test/src/Names/Definitions.enso
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
type Foo a b c
|
||||||
|
|
||||||
|
Foo.sum = case this of
|
||||||
|
Foo a b c -> a + b + c
|
||||||
|
|
||||||
|
another_constant = 10
|
39
test/Test/src/Names_Spec.enso
Normal file
39
test/Test/src/Names_Spec.enso
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import Test.Names.Definitions
|
||||||
|
import Base.Test
|
||||||
|
|
||||||
|
Definitions.Foo.my_method = case this of
|
||||||
|
Definitions.Foo x y z -> x * y * z
|
||||||
|
|
||||||
|
get_foo module = module.Foo
|
||||||
|
|
||||||
|
constant = 1
|
||||||
|
|
||||||
|
add_one (x = 0) = x + 1
|
||||||
|
|
||||||
|
spec =
|
||||||
|
describe "Qualified Names" <|
|
||||||
|
it "should allow to call constructors in a qualified manner" <|
|
||||||
|
Definitions.Foo 1 2 3 . sum . should_equal 6
|
||||||
|
Definitions . Foo 1 2 3 . sum . should_equal 6
|
||||||
|
it "should allow pattern matching in a qualified manner" <|
|
||||||
|
v = Foo 1 2 3
|
||||||
|
res = case v of
|
||||||
|
Definitions.Foo a b c -> a + b + c
|
||||||
|
res.should_equal 6
|
||||||
|
it "should allow defining methods on qualified names" <|
|
||||||
|
v = Definitions.Foo 2 3 5
|
||||||
|
v.my_method.should_equal 30
|
||||||
|
it "should allow using constructors from value-bound modules" <|
|
||||||
|
v = here.get_foo Definitions 1 2 3
|
||||||
|
v.sum.should_equal 6
|
||||||
|
describe "Uppercase Methods" <|
|
||||||
|
it "should allow calling methods without a target, through uppercase resolution" <|
|
||||||
|
v = Constant
|
||||||
|
v.should_equal 1
|
||||||
|
it "should allow calling methods that use defaulted arguments" <|
|
||||||
|
Add_One.should_equal 1
|
||||||
|
Add_One 100 . should_equal 101
|
||||||
|
it "should allow calling methods imported from another module" <|
|
||||||
|
## TODO
|
||||||
|
This should only work with `all` import.
|
||||||
|
Another_Constant.should_equal 10
|
Loading…
Reference in New Issue
Block a user