diff --git a/docs/language-server/protocol-language-server.md b/docs/language-server/protocol-language-server.md index 5d7b662b2718..cb7da109a70f 100644 --- a/docs/language-server/protocol-language-server.md +++ b/docs/language-server/protocol-language-server.md @@ -3191,14 +3191,6 @@ Current limitations of the method renaming are: ```rust Main.function1 x = x ``` -- Method calls where the self type is not specified will not be renamed, i.e. - - ```rust - function1 x = x - - main = - operator1 = function1 42 - ``` #### Parameters diff --git a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/desugar/SectionsToBinOp.java b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/desugar/SectionsToBinOp.java index 36cd49c72b1e..63a1980194b9 100644 --- a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/desugar/SectionsToBinOp.java +++ b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/desugar/SectionsToBinOp.java @@ -77,7 +77,8 @@ public Expression transformExpression(Expression ir) { var loc = sectionLeft.location().isDefined() ? sectionLeft.location().get() : null; var passData = sectionLeft.passData(); var rightArgName = freshNameSupply.newName(false, Option.empty()); - var rightCallArg = new CallArgument.Specified(Option.empty(), rightArgName, null, meta()); + var rightCallArg = + new CallArgument.Specified(Option.empty(), rightArgName, true, null, meta()); var rightDefArg = new DefinitionArgument.Specified( rightArgName.duplicate(true, true, true, false), @@ -89,7 +90,8 @@ public Expression transformExpression(Expression ir) { if (arg.value() instanceof Name.Blank) { var leftArgName = freshNameSupply.newName(false, Option.empty()); - var leftCallArg = new CallArgument.Specified(Option.empty(), leftArgName, null, meta()); + var leftCallArg = + new CallArgument.Specified(Option.empty(), leftArgName, true, null, meta()); var leftDefArg = new DefinitionArgument.Specified( leftArgName.duplicate(true, true, true, false), @@ -122,7 +124,8 @@ public Expression transformExpression(Expression ir) { var loc = sectionSides.location().isDefined() ? sectionSides.location().get() : null; var passData = sectionSides.passData(); var leftArgName = freshNameSupply.newName(false, Option.empty()); - var leftCallArg = new CallArgument.Specified(Option.empty(), leftArgName, null, meta()); + var leftCallArg = + new CallArgument.Specified(Option.empty(), leftArgName, true, null, meta()); var leftDefArg = new DefinitionArgument.Specified( leftArgName.duplicate(true, true, true, false), @@ -133,7 +136,8 @@ public Expression transformExpression(Expression ir) { meta()); var rightArgName = freshNameSupply.newName(false, Option.empty()); - var rightCallArg = new CallArgument.Specified(Option.empty(), rightArgName, null, meta()); + var rightCallArg = + new CallArgument.Specified(Option.empty(), rightArgName, true, null, meta()); var rightDefArg = new DefinitionArgument.Specified( rightArgName.duplicate(true, true, true, false), @@ -183,7 +187,8 @@ public Expression transformExpression(Expression ir) { var loc = sectionRight.location().isDefined() ? sectionRight.location().get() : null; var passData = sectionRight.passData(); var leftArgName = freshNameSupply.newName(false, Option.empty()); - var leftCallArg = new CallArgument.Specified(Option.empty(), leftArgName, null, meta()); + var leftCallArg = + new CallArgument.Specified(Option.empty(), leftArgName, true, null, meta()); var leftDefArg = new DefinitionArgument.Specified( leftArgName.duplicate(true, true, true, false), @@ -197,7 +202,7 @@ public Expression transformExpression(Expression ir) { // Note [Blanks in Sections] var rightArgName = freshNameSupply.newName(false, Option.empty()); var rightCallArg = - new CallArgument.Specified(Option.empty(), rightArgName, null, meta()); + new CallArgument.Specified(Option.empty(), rightArgName, true, null, meta()); var rightDefArg = new DefinitionArgument.Specified( rightArgName.duplicate(true, true, true, false), diff --git a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/AliasAnalysis.scala b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/AliasAnalysis.scala index b94800b5b2d3..5e517e95ec78 100644 --- a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/AliasAnalysis.scala +++ b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/AliasAnalysis.scala @@ -653,7 +653,7 @@ case object AliasAnalysis extends IRPass { args: List[CallArgument], builder: GraphBuilder ): List[CallArgument] = { - args.map { case arg @ CallArgument.Specified(_, expr, _, _) => + args.map { case arg @ CallArgument.Specified(_, expr, _, _, _) => val currentScope = expr match { case _: Literal => builder case _ => builder.addChild() diff --git a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/AutomaticParallelism.scala b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/AutomaticParallelism.scala index f0a121aa8f52..e25927cbfc6e 100644 --- a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/AutomaticParallelism.scala +++ b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/AutomaticParallelism.scala @@ -323,8 +323,8 @@ object AutomaticParallelism extends IRPass { Name.Special(Name.Special.WriteRef, null), List( CallArgument - .Specified(None, refVars(bind.name).duplicate(), null), - CallArgument.Specified(None, bind.name.duplicate(), null) + .Specified(None, refVars(bind.name).duplicate(), true, null), + CallArgument.Specified(None, bind.name.duplicate(), true, null) ), false, null @@ -338,6 +338,7 @@ object AutomaticParallelism extends IRPass { CallArgument.Specified( None, Expression.Block(blockBody.init, blockBody.last, null), + true, null ) ), @@ -354,7 +355,7 @@ object AutomaticParallelism extends IRPass { val threadJoins = threadSpawns.map { bind => Application.Prefix( Name.Special(Name.Special.JoinThread, null), - List(CallArgument.Specified(None, bind.name.duplicate(), null)), + List(CallArgument.Specified(None, bind.name.duplicate(), true, null)), false, null ) @@ -366,7 +367,7 @@ object AutomaticParallelism extends IRPass { name.duplicate(), Application.Prefix( Name.Special(Name.Special.ReadRef, null), - List(CallArgument.Specified(None, ref.duplicate(), null)), + List(CallArgument.Specified(None, ref.duplicate(), true, null)), false, null ), diff --git a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/DataflowAnalysis.scala b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/DataflowAnalysis.scala index 2147865f8c94..66ddb466a835 100644 --- a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/DataflowAnalysis.scala +++ b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/DataflowAnalysis.scala @@ -745,7 +745,7 @@ case object DataflowAnalysis extends IRPass { info: DependencyInfo ): CallArgument = { argument match { - case spec @ CallArgument.Specified(name, value, _, _) => + case spec @ CallArgument.Specified(name, value, _, _, _) => val specDep = asStatic(spec) val valueDep = asStatic(value) info.dependents.updateAt(valueDep, Set(specDep)) diff --git a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/DemandAnalysis.scala b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/DemandAnalysis.scala index e59033695589..7d7f9d0ec854 100644 --- a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/DemandAnalysis.scala +++ b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/DemandAnalysis.scala @@ -265,10 +265,10 @@ case object DemandAnalysis extends IRPass { */ def analyseCallArgument(arg: CallArgument): CallArgument = { arg match { - case spec @ CallArgument.Specified(_, expr, _, _) => - spec.copy( + case arg: CallArgument.Specified => + arg.copy( value = analyseExpression( - expr, + arg.value, isInsideCallArgument = true ) ) diff --git a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/FramePointerAnalysis.scala b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/FramePointerAnalysis.scala index 71a1e00b1b03..34a62b2f56af 100644 --- a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/FramePointerAnalysis.scala +++ b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/FramePointerAnalysis.scala @@ -242,12 +242,13 @@ case object FramePointerAnalysis extends IRPass { arguments: List[CallArgument], graph: Graph ): Unit = { - arguments.foreach { case arg @ CallArgument.Specified(name, value, _, _) => - maybeAttachFramePointer(arg, graph) - name.foreach(maybeAttachFramePointer(_, graph)) - processExpression(value, graph, false) - maybAttachFrameVariableNames(value) - maybAttachFrameVariableNames(arg) + arguments.foreach { + case arg @ CallArgument.Specified(name, value, _, _, _) => + maybeAttachFramePointer(arg, graph) + name.foreach(maybeAttachFramePointer(_, graph)) + processExpression(value, graph, false) + maybAttachFrameVariableNames(value) + maybAttachFrameVariableNames(arg) } } diff --git a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/desugar/LambdaShorthandToLambdaMini.scala b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/desugar/LambdaShorthandToLambdaMini.scala index 9243a9988424..a3f3b9f4e1ac 100644 --- a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/desugar/LambdaShorthandToLambdaMini.scala +++ b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/desugar/LambdaShorthandToLambdaMini.scala @@ -34,8 +34,8 @@ class LambdaShorthandToLambdaMini( parent match { case Application.Prefix(fn, args, _, _, _) => val hasBlankArg = args.exists { - case CallArgument.Specified(_, _: Name.Blank, _, _) => true - case _ => false + case CallArgument.Specified(_, _: Name.Blank, _, _, _) => true + case _ => false } val hasBlankFn = fn.isInstanceOf[Name.Blank] hasBlankArg || hasBlankFn @@ -222,8 +222,8 @@ class LambdaShorthandToLambdaMini( private def determineLambdaShorthand( args: List[CallArgument] ): List[Boolean] = { - args.map { case CallArgument.Specified(_, value, _, _) => - value match { + args.map { arg => + arg.value match { case _: Name.Blank => true case _ => false } @@ -245,14 +245,14 @@ class LambdaShorthandToLambdaMini( val isShorthand = argAndIsShorthand._2 arg match { - case s @ CallArgument.Specified(_, value, _, _) => + case s: CallArgument.Specified => if (isShorthand) { val newName = freshNameSupply .newName() .copy( - location = value.location, - passData = value.passData, - diagnostics = value.diagnostics + location = s.value.location, + passData = s.value.passData, + diagnostics = s.value.diagnostics ) s.copy(value = newName) @@ -274,11 +274,11 @@ class LambdaShorthandToLambdaMini( ): Option[DefinitionArgument] = { if (isShorthand) { arg match { - case specified @ CallArgument.Specified(_, value, _, passData) => + case specified: CallArgument.Specified => // Note [Safe Casting to Name.Literal] val defArgName = Name.Literal( - value.asInstanceOf[Name.Literal].name, + specified.value.asInstanceOf[Name.Literal].name, isMethod = false, null ) @@ -290,7 +290,7 @@ class LambdaShorthandToLambdaMini( None, suspended = false, null, - passData.duplicate, + specified.passData.duplicate, specified.diagnosticsCopy ) ) diff --git a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/resolve/GlobalNames.scala b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/resolve/GlobalNames.scala index 23dd5b605f86..706709209c4d 100644 --- a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/resolve/GlobalNames.scala +++ b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/resolve/GlobalNames.scala @@ -221,8 +221,12 @@ case object GlobalNames extends IRPass { val app = Application.Prefix( fun, List( - CallArgument - .Specified(None, self, identifiedLocation = null) + CallArgument.Specified( + None, + self, + true, + identifiedLocation = null + ) ), hasDefaultsSuspended = false, lit.identifiedLocation @@ -345,7 +349,7 @@ case object GlobalNames extends IRPass { ) ) val selfArg = - CallArgument.Specified(None, self, identifiedLocation = null) + CallArgument.Specified(None, self, true, identifiedLocation = null) processedFun.passData.remove(this) // Necessary for IrToTruffle app.copy(function = processedFun, arguments = selfArg :: processedArgs) case _ => diff --git a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/resolve/TypeFunctions.scala b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/resolve/TypeFunctions.scala index 1d1ed8837636..a1c47cec7f6e 100644 --- a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/resolve/TypeFunctions.scala +++ b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/resolve/TypeFunctions.scala @@ -219,9 +219,9 @@ case object TypeFunctions extends IRPass { */ private def resolveCallArgument(arg: CallArgument): CallArgument = { arg match { - case spec @ CallArgument.Specified(_, value, _, _) => + case spec: CallArgument.Specified => spec.copy( - value = resolveExpression(value) + value = resolveExpression(spec.value) ) } } @@ -241,8 +241,8 @@ case object TypeFunctions extends IRPass { */ private def isValidCallArg(arg: CallArgument): Boolean = { arg match { - case CallArgument.Specified(name, _, _, _) => - name.isEmpty + case specified: CallArgument.Specified => + specified.name.isEmpty } } } diff --git a/engine/runtime-compiler/src/main/scala/org/enso/compiler/refactoring/IRUtils.scala b/engine/runtime-compiler/src/main/scala/org/enso/compiler/refactoring/IRUtils.scala index fdb69606d443..d2112a03aecd 100644 --- a/engine/runtime-compiler/src/main/scala/org/enso/compiler/refactoring/IRUtils.scala +++ b/engine/runtime-compiler/src/main/scala/org/enso/compiler/refactoring/IRUtils.scala @@ -3,6 +3,7 @@ package org.enso.compiler.refactoring import org.enso.compiler.core.Implicits.AsMetadata import org.enso.compiler.core.{ExternalID, IR, Identifier} import org.enso.compiler.core.ir.Name +import org.enso.compiler.core.ir.expression.Application import org.enso.compiler.data.BindingsMap import org.enso.compiler.pass.analyse.DataflowAnalysis import org.enso.compiler.pass.resolve.MethodCalls @@ -64,23 +65,27 @@ trait IRUtils { for { usages <- findDynamicUsages(ir, node) } yield { - usages - .collect { - case usage: Name.Literal - if usage.isMethod && usage.name == node.name => - usage - } - .flatMap { symbol => - symbol.getMetadata(MethodCalls).flatMap { resolution => - resolution.target match { - case BindingsMap.ResolvedModuleMethod(module, _) - if module.getName == moduleName => - Some(symbol) - case _ => - None - } + usages.collect { + case Application.Prefix(function: Name.Literal, args, _, _, _) + if function.name == node.name => + function.getMetadata(MethodCalls) match { + case Some(resolution) => + resolution.target match { + case BindingsMap.ResolvedModuleMethod(module, _) + if module.getName == moduleName => + Some(function) + case _ => + None + } + case None => + args.headOption match { + case Some(arg) if arg.isSynthetic => + Some(function) + case _ => + None + } } - } + }.flatten } /** Find usages of a static dependency in the [[DataflowAnalysis]] metadata. diff --git a/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/pass/analyse/GatherDiagnosticsTest.scala b/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/pass/analyse/GatherDiagnosticsTest.scala index b2785b3aa9be..3b9329977afa 100644 --- a/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/pass/analyse/GatherDiagnosticsTest.scala +++ b/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/pass/analyse/GatherDiagnosticsTest.scala @@ -26,7 +26,7 @@ class GatherDiagnosticsTest extends CompilerTest { val plusApp = Application.Prefix( plusOp, List( - CallArgument.Specified(None, error1, identifiedLocation = null) + CallArgument.Specified(None, error1, false, identifiedLocation = null) ), hasDefaultsSuspended = false, identifiedLocation = null @@ -121,11 +121,11 @@ class GatherDiagnosticsTest extends CompilerTest { ) val result = GatherDiagnostics.runModule(module, buildModuleContext()) - val gatheredErrros = result + val gatheredErros = result .unsafeGetMetadata(GatherDiagnostics, "Impossible") .diagnostics - gatheredErrros.toSet shouldEqual Set(error1, error2, error3) + gatheredErros.toSet shouldEqual Set(error1, error2, error3) } "work with annotations" in { diff --git a/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/pass/analyse/TailCallMegaPass.scala b/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/pass/analyse/TailCallMegaPass.scala index 8ba7958c00c2..7758bda458a5 100644 --- a/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/pass/analyse/TailCallMegaPass.scala +++ b/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/pass/analyse/TailCallMegaPass.scala @@ -300,11 +300,11 @@ case object TailCallMegaPass extends IRPass { */ private def analyseCallArg(argument: CallArgument): CallArgument = { argument match { - case arg @ CallArgument.Specified(_, expr, _, _) => + case arg: CallArgument.Specified => arg .copy( // Note [Call Argument Tail Position] - value = analyseExpression(expr, isInTailPosition = true) + value = analyseExpression(arg.value, isInTailPosition = true) ) .updateMetadata(TAIL_META) } diff --git a/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/pass/desugar/LambdaShorthandToLambdaMegaPass.scala b/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/pass/desugar/LambdaShorthandToLambdaMegaPass.scala index 8d0d81347322..64e43809e7f6 100644 --- a/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/pass/desugar/LambdaShorthandToLambdaMegaPass.scala +++ b/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/pass/desugar/LambdaShorthandToLambdaMegaPass.scala @@ -189,8 +189,8 @@ case object LambdaShorthandToLambdaMegaPass extends IRPass { args .zip(argIsUnderscore) .map(updateShorthandArg(_, freshNameSupply)) - .map { case s @ CallArgument.Specified(_, value, _, _) => - s.copy(value = desugarExpression(value, freshNameSupply)) + .map { case s: CallArgument.Specified => + s.copy(value = desugarExpression(s.value, freshNameSupply)) } // Generate a definition arg instance for each shorthand arg @@ -306,8 +306,8 @@ case object LambdaShorthandToLambdaMegaPass extends IRPass { private def determineLambdaShorthand( args: List[CallArgument] ): List[Boolean] = { - args.map { case CallArgument.Specified(_, value, _, _) => - value match { + args.map { arg => + arg.value match { case _: Name.Blank => true case _ => false } @@ -330,14 +330,14 @@ case object LambdaShorthandToLambdaMegaPass extends IRPass { val isShorthand = argAndIsShorthand._2 arg match { - case s @ CallArgument.Specified(_, value, _, _) => + case s: CallArgument.Specified => if (isShorthand) { val newName = freshNameSupply .newName() .copy( - location = value.location, - passData = value.passData, - diagnostics = value.diagnostics + location = s.value.location, + passData = s.value.passData, + diagnostics = s.value.diagnostics ) s.copy(value = newName) @@ -359,11 +359,11 @@ case object LambdaShorthandToLambdaMegaPass extends IRPass { ): Option[DefinitionArgument] = { if (isShorthand) { arg match { - case specified @ CallArgument.Specified(_, value, _, passData) => + case specified: CallArgument.Specified => // Note [Safe Casting to Name.Literal] val defArgName = Name.Literal( - value.asInstanceOf[Name.Literal].name, + specified.value.asInstanceOf[Name.Literal].name, isMethod = false, null ) @@ -375,7 +375,7 @@ case object LambdaShorthandToLambdaMegaPass extends IRPass { None, suspended = false, null, - passData.duplicate, + specified.passData.duplicate, specified.diagnosticsCopy ) ) diff --git a/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/pass/desugar/OperatorToFunctionTest.scala b/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/pass/desugar/OperatorToFunctionTest.scala index 780145c77ea5..e387e7908f44 100644 --- a/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/pass/desugar/OperatorToFunctionTest.scala +++ b/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/pass/desugar/OperatorToFunctionTest.scala @@ -64,9 +64,10 @@ class OperatorToFunctionTest extends MiniPassTest { ): (Operator.Binary, Application.Prefix) = { val loc = new IdentifiedLocation(new Location(1, 33)) - val leftArg = CallArgument.Specified(None, left, left.identifiedLocation()) + val leftArg = + CallArgument.Specified(None, left, false, left.identifiedLocation()) val rightArg = - CallArgument.Specified(None, right, right.identifiedLocation()) + CallArgument.Specified(None, right, false, right.identifiedLocation()) val binOp = Operator.Binary(leftArg, name, rightArg, loc) @@ -85,12 +86,12 @@ class OperatorToFunctionTest extends MiniPassTest { Name.Literal("=:=", isMethod = true, null) val left = Empty(null) val right = Empty(null) - val rightArg = CallArgument.Specified(None, Empty(null), null) + val rightArg = CallArgument.Specified(None, Empty(null), false, null) val (operator, operatorFn) = genOprAndFn(opName, left, right) - val oprArg = CallArgument.Specified(None, operator, null) - val oprFnArg = CallArgument.Specified(None, operatorFn, null) + val oprArg = CallArgument.Specified(None, operator, false, null) + val oprFnArg = CallArgument.Specified(None, operatorFn, false, null) "Operators" should { val opName = @@ -100,15 +101,16 @@ class OperatorToFunctionTest extends MiniPassTest { val rightArg = CallArgument.Specified( None, Empty(identifiedLocation = null), + false, identifiedLocation = null ) val (operator, operatorFn) = genOprAndFn(opName, left, right) val oprArg = - CallArgument.Specified(None, operator, identifiedLocation = null) + CallArgument.Specified(None, operator, false, identifiedLocation = null) val oprFnArg = - CallArgument.Specified(None, operatorFn, identifiedLocation = null) + CallArgument.Specified(None, operatorFn, false, identifiedLocation = null) "be translated to functions" in { OperatorToFunctionTestPass.runExpression( diff --git a/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/pass/desugar/SectionsToBinOpMegaPass.scala b/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/pass/desugar/SectionsToBinOpMegaPass.scala index 5434577d8faa..f1a9fe441410 100644 --- a/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/pass/desugar/SectionsToBinOpMegaPass.scala +++ b/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/pass/desugar/SectionsToBinOpMegaPass.scala @@ -105,7 +105,12 @@ case object SectionsToBinOpMegaPass extends IRPass { case sectionLeft @ Section.Left(arg, op, loc, passData) => val rightArgName = freshNameSupply.newName() val rightCallArg = - CallArgument.Specified(None, rightArgName, identifiedLocation = null) + CallArgument.Specified( + None, + rightArgName, + true, + identifiedLocation = null + ) val rightDefArg = DefinitionArgument.Specified( rightArgName.duplicate(), None, @@ -117,7 +122,12 @@ case object SectionsToBinOpMegaPass extends IRPass { if (arg.value.isInstanceOf[Name.Blank]) { val leftArgName = freshNameSupply.newName() val leftCallArg = - CallArgument.Specified(None, leftArgName, identifiedLocation = null) + CallArgument.Specified( + None, + leftArgName, + true, + identifiedLocation = null + ) val leftDefArg = DefinitionArgument.Specified( leftArgName.duplicate(), None, @@ -161,7 +171,12 @@ case object SectionsToBinOpMegaPass extends IRPass { case sectionSides @ Section.Sides(op, loc, passData) => val leftArgName = freshNameSupply.newName() val leftCallArg = - CallArgument.Specified(None, leftArgName, identifiedLocation = null) + CallArgument.Specified( + None, + leftArgName, + true, + identifiedLocation = null + ) val leftDefArg = DefinitionArgument.Specified( leftArgName.duplicate(), None, @@ -172,7 +187,12 @@ case object SectionsToBinOpMegaPass extends IRPass { val rightArgName = freshNameSupply.newName() val rightCallArg = - CallArgument.Specified(None, rightArgName, identifiedLocation = null) + CallArgument.Specified( + None, + rightArgName, + true, + identifiedLocation = null + ) val rightDefArg = DefinitionArgument.Specified( rightArgName.duplicate(), None, @@ -224,7 +244,12 @@ case object SectionsToBinOpMegaPass extends IRPass { case sectionRight @ Section.Right(op, arg, loc, passData) => val leftArgName = freshNameSupply.newName() val leftCallArg = - CallArgument.Specified(None, leftArgName, identifiedLocation = null) + CallArgument.Specified( + None, + leftArgName, + true, + identifiedLocation = null + ) val leftDefArg = DefinitionArgument.Specified( leftArgName.duplicate(), @@ -241,6 +266,7 @@ case object SectionsToBinOpMegaPass extends IRPass { CallArgument.Specified( None, rightArgName, + true, identifiedLocation = null ) val rightDefArg = DefinitionArgument.Specified( diff --git a/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/refactoring/IRUtilsTest.scala b/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/refactoring/IRUtilsTest.scala index 4bdbf9c01c91..d7b17bd08854 100644 --- a/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/refactoring/IRUtilsTest.scala +++ b/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/refactoring/IRUtilsTest.scala @@ -170,7 +170,34 @@ class IRUtilsTest extends AnyWordSpecLike with Matchers with OptionValues { } } - "find usages of a static call in lambda" in { + "find usages of unqualified method call in main body" in { + val uuid1 = new UUID(0, 1) + val code = + s"""function1 = "" + | + |main = + | operator1 = Test.function1 + | operator2 = function1 + | operator3 = operator2.function1 + | + | + |#### METADATA #### + |[[{"index": {"value": 0}, "size": {"value": 9}}, "$uuid1"]] + |[] + |""".stripMargin + + val module = code.preprocessModule() + val function1 = IRUtils.findByExternalId(module, uuid1).get + val usages = findUsagesOfModuleMethod(moduleName, module, function1) + + usages.value.size shouldEqual 2 + usages.value.foreach { + case _: Name.Literal => succeed + case ir => fail(s"Not a literal: $ir") + } + } + + "find usages of a qualified static call in lambda" in { val uuid1 = new UUID(0, 1) val code = s"""function1 x = x @@ -197,6 +224,32 @@ class IRUtilsTest extends AnyWordSpecLike with Matchers with OptionValues { } } + "find usages of unqualified static call in lambda" in { + val uuid1 = new UUID(0, 1) + val code = + s"""function1 x = x + | + |main = + | operator2 = function1 (x -> function1 x) + | operator2 + | + | + |#### METADATA #### + |[[{"index": {"value": 0}, "size": {"value": 9}}, "$uuid1"]] + |[] + |""".stripMargin + + val module = code.preprocessModule() + val function1 = IRUtils.findByExternalId(module, uuid1).get + val usages = findUsagesOfModuleMethod(moduleName, module, function1) + + usages.value.size shouldEqual 2 + usages.value.foreach { + case _: Name.Literal => succeed + case ir => fail(s"Not a literal: $ir") + } + } + "find usages of a static method call in presence of an instance method" in { val uuid1 = new UUID(0, 1) val code = @@ -235,7 +288,8 @@ class IRUtilsTest extends AnyWordSpecLike with Matchers with OptionValues { |main = | operator1 = 41 | operator2 = Test.function1 operator1 - | operator3 = A.function1 + | operator3 = function1 operator1 + | operator4 = A.function1 | | |#### METADATA #### @@ -247,7 +301,7 @@ class IRUtilsTest extends AnyWordSpecLike with Matchers with OptionValues { val operator1 = IRUtils.findByExternalId(module, uuid1).get val usages = findUsagesOfModuleMethod(moduleName, module, operator1) - usages.value.size shouldEqual 1 + usages.value.size shouldEqual 2 usages.value.foreach { case _: Name.Literal => succeed case ir => fail(s"Not a literal: $ir") diff --git a/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeRefactoringTest.scala b/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeRefactoringTest.scala index 94a914851ff5..c82dde5108ec 100644 --- a/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeRefactoringTest.scala +++ b/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeRefactoringTest.scala @@ -430,7 +430,7 @@ class RuntimeRefactoringTest context.consumeOut shouldEqual List("43") } - it should "rename module method in main body" in { + it should "rename qualified module method in main body" in { val contextId = UUID.randomUUID() val requestId = UUID.randomUUID() val moduleName = "Enso_Test.Test.Main" @@ -508,7 +508,7 @@ class RuntimeRefactoringTest context.send( Api.Request(requestId, Api.RenameSymbol(moduleName, idFunction1, newName)) ) - context.receiveNIgnoreStdLib(4, 5) should contain theSameElementsAs Seq( + context.receiveNIgnoreStdLib(4) should contain theSameElementsAs Seq( Api.Response(requestId, Api.SymbolRenamed(newName)), Api.Response(None, expectedFileEdit), TestMessages.pending(contextId, idFunction1), @@ -517,7 +517,7 @@ class RuntimeRefactoringTest context.consumeOut shouldEqual List("42") } - it should "rename module method in lambda expression" in { + it should "rename qualified module method in lambda expression" in { val contextId = UUID.randomUUID() val requestId = UUID.randomUUID() val moduleName = "Enso_Test.Test.Main" @@ -595,7 +595,180 @@ class RuntimeRefactoringTest context.send( Api.Request(requestId, Api.RenameSymbol(moduleName, idFunction1, newName)) ) - context.receiveNIgnoreStdLib(4, 5) should contain theSameElementsAs Seq( + context.receiveNIgnoreStdLib(4) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.SymbolRenamed(newName)), + Api.Response(None, expectedFileEdit), + TestMessages.pending(contextId, idFunction1), + context.executionComplete(contextId) + ) + context.consumeOut shouldEqual List("42") + } + + it should "rename unqualified module method in main body" in { + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val moduleName = "Enso_Test.Test.Main" + + val metadata = new Metadata + val idFunction1 = metadata.addItem(31, 9) + val code = + """from Standard.Base import all + | + |function1 x = x + 1 + | + |main = + | operator1 = function1 41 + | IO.println operator1 + |""".stripMargin.linesIterator.mkString("\n") + val contents = metadata.appendToCode(code) + val mainFile = context.writeMain(contents) + + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) + + // open file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // push main + context.send( + Api.Request( + requestId, + Api.PushContextRequest( + contextId, + Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, moduleName, "main"), + None, + Vector() + ) + ) + ) + ) + + context.receiveNIgnoreStdLib(2) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + context.executionComplete(contextId) + ) + context.consumeOut shouldEqual List("42") + + // rename operator1 + val newName = "function2" + val expectedEdits = Vector( + TextEdit( + model.Range(model.Position(2, 0), model.Position(2, 9)), + newName + ), + TextEdit( + model.Range(model.Position(5, 16), model.Position(5, 25)), + newName + ) + ) + val expectedFileEdit = Api.FileEdit( + context.pkg.mainFile, + expectedEdits, + versionCalculator.evalVersion(contents).toHexString, + versionCalculator + .evalVersion(contents.replaceAll("function1", newName)) + .toHexString + ) + context.send( + Api.Request(requestId, Api.RenameSymbol(moduleName, idFunction1, newName)) + ) + context.receiveNIgnoreStdLib(4) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.SymbolRenamed(newName)), + Api.Response(None, expectedFileEdit), + TestMessages.pending(contextId, idFunction1), + context.executionComplete(contextId) + ) + context.consumeOut shouldEqual List("42") + } + + it should "rename unqualified module method in lambda expression" in { + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val moduleName = "Enso_Test.Test.Main" + + val metadata = new Metadata + val idFunction1 = metadata.addItem(31, 9) + val code = + """from Standard.Base import all + | + |function1 x = x + 1 + | + |main = + | operator1 = 41 + | operator2 = x -> function1 x + | IO.println (operator2 operator1) + |""".stripMargin.linesIterator.mkString("\n") + val contents = metadata.appendToCode(code) + val mainFile = context.writeMain(contents) + + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) + + // open file + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // push main + context.send( + Api.Request( + requestId, + Api.PushContextRequest( + contextId, + Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, moduleName, "main"), + None, + Vector() + ) + ) + ) + ) + + context.receiveNIgnoreStdLib(2) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + context.executionComplete(contextId) + ) + context.consumeOut shouldEqual List("42") + + // rename operator1 + val newName = "function2" + val expectedEdits = Vector( + TextEdit( + model.Range(model.Position(2, 0), model.Position(2, 9)), + newName + ), + TextEdit( + model.Range(model.Position(6, 21), model.Position(6, 30)), + newName + ) + ) + val expectedFileEdit = Api.FileEdit( + context.pkg.mainFile, + expectedEdits, + versionCalculator.evalVersion(contents).toHexString, + versionCalculator + .evalVersion(contents.replaceAll("function1", newName)) + .toHexString + ) + context.send( + Api.Request(requestId, Api.RenameSymbol(moduleName, idFunction1, newName)) + ) + context.receiveNIgnoreStdLib(4) should contain theSameElementsAs Seq( Api.Response(requestId, Api.SymbolRenamed(newName)), Api.Response(None, expectedFileEdit), TestMessages.pending(contextId, idFunction1), diff --git a/engine/runtime-parser/src/main/java/org/enso/compiler/core/TreeToIr.java b/engine/runtime-parser/src/main/java/org/enso/compiler/core/TreeToIr.java index 6e791b94e1ef..14e2fd759503 100644 --- a/engine/runtime-parser/src/main/java/org/enso/compiler/core/TreeToIr.java +++ b/engine/runtime-parser/src/main/java/org/enso/compiler/core/TreeToIr.java @@ -445,7 +445,7 @@ private Application translateTypeApplication(Tree.App app) throws SyntaxExceptio } else { arg = new Name.Qualified(tail, loc, meta()); } - var ca = new CallArgument.Specified(Option.empty(), arg, loc, meta()); + var ca = new CallArgument.Specified(Option.empty(), arg, false, loc, meta()); args = join(ca, args); yield name; } @@ -453,7 +453,7 @@ private Application translateTypeApplication(Tree.App app) throws SyntaxExceptio if (in == null) { return new Application.Prefix(type, args, false, getIdentifiedLocation(app), meta()); } else { - var fn = new CallArgument.Specified(Option.empty(), type, getIdentifiedLocation(app), meta()); + var fn = new CallArgument.Specified(Option.empty(), type, false, getIdentifiedLocation(app), meta()); return new Operator.Binary(fn, in, args.head(), getIdentifiedLocation(app), meta()); } } @@ -652,14 +652,14 @@ private Expression translateCall(Tree ast, boolean isMethod) throws SyntaxExcept case Tree.App app -> { var expr = translateExpression(app.getArg(), false); var loc = getIdentifiedLocation(app.getArg()); - args.add(new CallArgument.Specified(Option.empty(), expr, loc, meta())); + args.add(new CallArgument.Specified(Option.empty(), expr, false, loc, meta())); tree = app.getFunc(); } case Tree.NamedApp app -> { var expr = translateExpression(app.getArg(), false); var loc = getIdentifiedLocation(app.getArg()); var id = buildName(app, app.getName()); - args.add(new CallArgument.Specified(Option.apply(id), expr, loc, meta())); + args.add(new CallArgument.Specified(Option.apply(id), expr, false, loc, meta())); tree = app.getFunc(); } case Tree.OperatorBlockApplication app -> { @@ -675,16 +675,16 @@ private Expression translateCall(Tree ast, boolean isMethod) throws SyntaxExcept } var expr = switch (translateExpression(l.getExpression().getExpression(), true)) { case Application.Prefix pref -> { - var arg = new CallArgument.Specified(Option.empty(), self, self.identifiedLocation(), meta()); + var arg = new CallArgument.Specified(Option.empty(), self, false, self.identifiedLocation(), meta()); yield new Application.Prefix(pref.function(), join(arg, pref.arguments()), false, pref.identifiedLocation(), meta()); } case Expression any -> { - var arg = new CallArgument.Specified(Option.empty(), self, self.identifiedLocation(), meta()); + var arg = new CallArgument.Specified(Option.empty(), self, false, self.identifiedLocation(), meta()); yield new Application.Prefix(any, join(arg, nil()), false, any.identifiedLocation(), meta()); } }; var loc = getIdentifiedLocation(l.getExpression().getExpression()); - args.add(at, new CallArgument.Specified(Option.empty(), expr, loc, meta())); + args.add(at, new CallArgument.Specified(Option.empty(), expr, false, loc, meta())); self = expr; } return self; @@ -701,7 +701,7 @@ && isDotOperator(oprApp.getOpr().getRight()) if (oprApp.getLhs() != null) { var self = translateExpression(oprApp.getLhs(), isMethod); var loc = getIdentifiedLocation(oprApp.getLhs()); - args.add(new CallArgument.Specified(Option.empty(), self, loc, meta())); + args.add(new CallArgument.Specified(Option.empty(), self, false, loc, meta())); } } else if (args.isEmpty()) { return null; @@ -878,7 +878,7 @@ yield translateSyntaxError(l.getExpression().getExpression(), var loc = getIdentifiedLocation(app); var both = applyOperator(op, lhs, rhs, loc); expr = both; - lhs = new CallArgument.Specified(Option.empty(), expr, loc, meta()); + lhs = new CallArgument.Specified(Option.empty(), expr, false, loc, meta()); } yield expr; } @@ -1033,7 +1033,7 @@ yield switch (translateExpression(group.getBody(), false)) { ); case Expression expr -> { var negate = new Name.Literal("negate", true, null, Option.empty(), meta()); - var arg = new CallArgument.Specified(Option.empty(), expr, expr.identifiedLocation(), meta()); + var arg = new CallArgument.Specified(Option.empty(), expr, false, expr.identifiedLocation(), meta()); yield new Application.Prefix(negate, join(arg, nil()), false, getIdentifiedLocation(un), meta()); } case null -> @@ -1080,6 +1080,7 @@ private Expression translateTypeSignatureToOprApp(TypeSignature sig) { var methodReference = new CallArgument.Specified( Option.empty(), methodName, + false, methodName.identifiedLocation(), meta() ); @@ -1394,7 +1395,7 @@ private Expression patchPrefixWithBlock(Application.Prefix pref, Expression.Bloc args = (List) args.tail(); } List allArgs = (List) pref.arguments().appendedAll(args.reverse()); - final CallArgument.Specified blockArg = new CallArgument.Specified(Option.empty(), block, block.identifiedLocation(), meta()); + final CallArgument.Specified blockArg = new CallArgument.Specified(Option.empty(), block, false, block.identifiedLocation(), meta()); List withBlockArgs = (List) allArgs.appended(blockArg); if (!checkArgs(withBlockArgs)) { return translateSyntaxError(pref.location().get(), Syntax.UnexpectedExpression$.MODULE$); @@ -1534,12 +1535,12 @@ CallArgument.Specified translateCallArgument(Tree arg) { case Tree.NamedApp app -> { var expr = translateExpression(app.getArg(), false); var id = sanitizeName(buildName(app, app.getName())); - yield new CallArgument.Specified(Option.apply(id), expr, loc, meta()); + yield new CallArgument.Specified(Option.apply(id), expr, false, loc, meta()); } case null -> null; default -> { var expr = translateExpression(arg, false); - yield new CallArgument.Specified(Option.empty(), expr, loc, meta()); + yield new CallArgument.Specified(Option.empty(), expr, false, loc, meta()); } }; } @@ -1547,7 +1548,7 @@ CallArgument.Specified translateCallArgument(Tree arg) { CallArgument.Specified translateTypeCallArgument(Tree arg) { var loc = getIdentifiedLocation(arg); var expr = translateType(arg); - return new CallArgument.Specified(Option.empty(), expr, loc, meta()); + return new CallArgument.Specified(Option.empty(), expr, false, loc, meta()); } CallArgument.Specified unnamedCallArgument(Tree arg) { @@ -1556,7 +1557,7 @@ CallArgument.Specified unnamedCallArgument(Tree arg) { } var loc = getIdentifiedLocation(arg); var expr = translateExpression(arg); - return new CallArgument.Specified(Option.empty(), expr, loc, meta()); + return new CallArgument.Specified(Option.empty(), expr, false, loc, meta()); } /** diff --git a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/CallArgument.scala b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/CallArgument.scala index 9d8f14601a0b..b16249bf3dc8 100644 --- a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/CallArgument.scala +++ b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/CallArgument.scala @@ -9,10 +9,13 @@ import java.util.UUID sealed trait CallArgument extends IR { /** The name of the argument, if present. */ - val name: Option[Name] + def name: Option[Name] /** The expression of the argument, if present. */ - val value: Expression + def value: Expression + + /** Flag indicating that the argument was generated by compiler. */ + def isSynthetic: Boolean /** @inheritdoc */ override def mapExpressions( @@ -37,12 +40,14 @@ object CallArgument { * * @param name the name of the argument being called, if present * @param value the expression being passed as the argument's value + * @param isSynthetic the flag indicating that the argument was generated by compiler * @param identifiedLocation the source location that the node corresponds to * @param passData the pass metadata associated with this node */ sealed case class Specified( override val name: Option[Name], override val value: Expression, + override val isSynthetic: Boolean, identifiedLocation: IdentifiedLocation, passData: MetadataStorage = new MetadataStorage() ) extends CallArgument @@ -52,17 +57,19 @@ object CallArgument { /** Creates a copy of `this`. * - * @param name the name of the argument being called, if present - * @param value the expression being passed as the argument's value - * @param location the source location that the node corresponds to - * @param passData the pass metadata associated with this node - * @param diagnostics compiler diagnostics for this node - * @param id the identifier for the new node + * @param name the name of the argument being called, if present + * @param value the expression being passed as the argument's value + * @param isSynthetic the flag indicating that the argument was generated by compiler + * @param location the source location that the node corresponds to + * @param passData the pass metadata associated with this node + * @param diagnostics compiler diagnostics for this node + * @param id the identifier for the new node * @return a copy of `this`, updated with the specified values */ def copy( name: Option[Name] = name, value: Expression = value, + isSynthetic: Boolean = isSynthetic, location: Option[IdentifiedLocation] = location, passData: MetadataStorage = passData, diagnostics: DiagnosticStorage = diagnostics, @@ -76,7 +83,7 @@ object CallArgument { || diagnostics != this.diagnostics || id != this.id ) { - val res = Specified(name, value, location.orNull, passData) + val res = Specified(name, value, isSynthetic, location.orNull, passData) res.diagnostics = diagnostics res.id = id res diff --git a/engine/runtime/src/main/scala/org/enso/interpreter/runtime/IrToTruffle.scala b/engine/runtime/src/main/scala/org/enso/interpreter/runtime/IrToTruffle.scala index f2d24d34da3d..d92326eee8bf 100644 --- a/engine/runtime/src/main/scala/org/enso/interpreter/runtime/IrToTruffle.scala +++ b/engine/runtime/src/main/scala/org/enso/interpreter/runtime/IrToTruffle.scala @@ -2472,7 +2472,7 @@ class IrToTruffle( subjectToInstrumentation: Boolean ): callable.argument.CallArgument = arg match { - case CallArgument.Specified(name, value, _, _) => + case CallArgument.Specified(name, value, _, _, _) => val scopeInfo = childScopeInfo("call argument", arg) def valueHasSomeTypeCheck() =