From 58abfc038723b3bb7015a2104a5dd92cb47e7e45 Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Tue, 30 Jul 2024 18:19:31 +0200 Subject: [PATCH 1/3] Optimizing IR copying Testing hypothesis that we are doing way more copying than necessary. Benchmarks locally are not conclusive so throwing it at CI. --- .../analyse/PrivateConstructorAnalysis.java | 18 +++--- .../pass/analyse/PrivateModuleAnalysis.java | 18 +++--- .../pass/analyse/PrivateSymbolsAnalysis.java | 57 ++++++++++--------- .../enso/compiler/core/ir/CallArgument.scala | 6 +- .../compiler/core/ir/DefinitionArgument.scala | 15 +++-- .../enso/compiler/core/ir/Expression.scala | 20 +++++-- .../org/enso/compiler/core/ir/Function.scala | 26 ++++++--- .../org/enso/compiler/core/ir/Module.scala | 15 +++-- .../org/enso/compiler/core/ir/Name.scala | 23 +++++--- .../org/enso/compiler/core/ir/Pattern.scala | 28 ++++++--- .../org/enso/compiler/core/ir/Type.scala | 28 +++++++-- .../core/ir/expression/Application.scala | 32 +++++++++-- .../compiler/core/ir/expression/Case.scala | 23 ++++++-- .../core/ir/expression/Operator.scala | 5 +- .../compiler/core/ir/expression/Section.scala | 35 ++++++++---- .../core/ir/expression/errors/Pattern.scala | 9 ++- .../core/ir/module/scope/Definition.scala | 38 +++++++++---- .../ir/module/scope/definition/Method.scala | 46 +++++++++++---- 18 files changed, 310 insertions(+), 132 deletions(-) diff --git a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/PrivateConstructorAnalysis.java b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/PrivateConstructorAnalysis.java index f58d47ea8f4b..ddc66d0cf82e 100644 --- a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/PrivateConstructorAnalysis.java +++ b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/PrivateConstructorAnalysis.java @@ -70,14 +70,16 @@ public Module runModule(Module ir, ModuleContext moduleContext) { } return binding; }); - return ir.copy( - ir.imports(), - ir.exports(), - newBindings, - ir.location(), - ir.passData(), - ir.diagnostics(), - ir.id()); + if (newBindings != ir.bindings()) + return ir.copy( + ir.imports(), + ir.exports(), + newBindings, + ir.location(), + ir.passData(), + ir.diagnostics(), + ir.id()); + else return ir; } /** Not supported on a single expression. */ diff --git a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/PrivateModuleAnalysis.java b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/PrivateModuleAnalysis.java index 644b05cde572..ef42b6a2c1f5 100644 --- a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/PrivateModuleAnalysis.java +++ b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/PrivateModuleAnalysis.java @@ -131,14 +131,16 @@ public Module runModule(Module moduleIr, ModuleContext moduleContext) { ? moduleIr.exports() : CollectionConverters.asScala(exportErrors).toList(); - return moduleIr.copy( - convertedImports, - convertedExports, - moduleIr.bindings(), - moduleIr.location(), - moduleIr.passData(), - moduleIr.diagnostics(), - moduleIr.id()); + if (convertedImports != moduleIr.imports() || convertedExports != moduleIr.exports()) + return moduleIr.copy( + convertedImports, + convertedExports, + moduleIr.bindings(), + moduleIr.location(), + moduleIr.passData(), + moduleIr.diagnostics(), + moduleIr.id()); + else return moduleIr; } @Override diff --git a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/PrivateSymbolsAnalysis.java b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/PrivateSymbolsAnalysis.java index df86dfcd7476..ea072252f49f 100644 --- a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/PrivateSymbolsAnalysis.java +++ b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/PrivateSymbolsAnalysis.java @@ -71,14 +71,16 @@ public Module runModule(Module ir, ModuleContext moduleContext) { var newBindings = ir.bindings() .map(binding -> binding.mapExpressions(expr -> processExpression(expr, bindingsMap))); - return ir.copy( - ir.imports(), - ir.exports(), - newBindings, - ir.location(), - ir.passData(), - ir.diagnostics(), - ir.id()); + if (newBindings != ir.bindings()) + return ir.copy( + ir.imports(), + ir.exports(), + newBindings, + ir.location(), + ir.passData(), + ir.diagnostics(), + ir.id()); + else return ir; } /** Not supported for expressions. */ @@ -94,14 +96,16 @@ private Expression processExpression(Expression expr, BindingsMap bindingsMap) { var newBranches = caseExpr.branches().map(branch -> processCaseBranch(branch, bindingsMap)).toSeq(); var newScrutinee = processExpression(caseExpr.scrutinee(), bindingsMap); - yield caseExpr.copy( - newScrutinee, - newBranches, - caseExpr.isNested(), - caseExpr.location(), - caseExpr.passData(), - caseExpr.diagnostics(), - caseExpr.id()); + if (newBranches != caseExpr.branches() || newScrutinee != caseExpr.scrutinee()) + yield caseExpr.copy( + newScrutinee, + newBranches, + caseExpr.isNested(), + caseExpr.location(), + caseExpr.passData(), + caseExpr.diagnostics(), + caseExpr.id()); + else yield expr; } case Name name -> processName(name, bindingsMap); default -> expr.mapExpressions(e -> processExpression(e, bindingsMap)); @@ -109,17 +113,18 @@ private Expression processExpression(Expression expr, BindingsMap bindingsMap) { } private Branch processCaseBranch(Branch branch, BindingsMap bindingsMap) { - var pat = branch.pattern(); - var newPat = processCasePattern(pat, bindingsMap); + var newPat = processCasePattern(branch.pattern(), bindingsMap); var newExpr = processExpression(branch.expression(), bindingsMap); - return branch.copy( - newPat, - newExpr, - branch.terminalBranch(), - branch.location(), - branch.passData(), - branch.diagnostics(), - branch.id()); + if (newPat != branch.pattern() || newExpr != branch.expression()) + return branch.copy( + newPat, + newExpr, + branch.terminalBranch(), + branch.location(), + branch.passData(), + branch.diagnostics(), + branch.id()); + else return branch; } private Pattern processCasePattern(Pattern pattern, BindingsMap bindingsMap) { 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 56282daf46fa..f2c4deb30b74 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 @@ -121,7 +121,11 @@ object CallArgument { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Specified = { - copy(name = name.map(n => n.mapExpressions(fn)), value = fn(value)) + val name1 = name.map(n => n.mapExpressions(fn)) + val value1 = fn(value) + if (name1 != name || value1 != value) + copy(name = name1, value = value1) + else this } /** String representation. */ diff --git a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/DefinitionArgument.scala b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/DefinitionArgument.scala index 4c83865c9376..7e2480de005d 100644 --- a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/DefinitionArgument.scala +++ b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/DefinitionArgument.scala @@ -151,11 +151,18 @@ object DefinitionArgument { def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Specified = { - copy( - name = name.mapExpressions(fn), - ascribedType = ascribedType.map(fn.asScala), - defaultValue = defaultValue.map(fn.asScala) + val name1 = name.mapExpressions(fn) + val ascribedType1 = ascribedType.map(fn.asScala) + val defaultValue1 = defaultValue.map(fn.asScala) + if ( + name1 != name || ascribedType1 != ascribedType || defaultValue1 != defaultValue ) + copy( + name = name1, + ascribedType = ascribedType1, + defaultValue = defaultValue1 + ) + else this } /** String representation. */ diff --git a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Expression.scala b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Expression.scala index 0c01efe1615b..ebf78fcc9059 100644 --- a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Expression.scala +++ b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Expression.scala @@ -136,10 +136,14 @@ object Expression { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Block = { - copy( - expressions = expressions.map(fn.asScala), - returnValue = fn(returnValue) - ) + val expressions1 = expressions.map(fn.asScala) + val returnValue1 = fn(returnValue) + if (expressions1 != expressions || returnValue1 != returnValue) { + copy( + expressions = expressions1, + returnValue = returnValue1 + ) + } else this } /** String representation. */ @@ -251,7 +255,13 @@ object Expression { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Binding = { - copy(name = name.mapExpressions(fn), expression = fn(expression)) + val name1 = name.mapExpressions(fn) + val expression1 = fn(expression) + if (name1 != name || expression1 != expression) { + copy(name = name1, expression = expression1) + } else { + this + } } /** String representation. */ diff --git a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Function.scala b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Function.scala index 1f83839a8a13..548dfdd54a53 100644 --- a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Function.scala +++ b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Function.scala @@ -151,7 +151,13 @@ object Function { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Lambda = { - copy(arguments = arguments.map(_.mapExpressions(fn)), body = fn(body)) + val arguments1 = arguments.map(_.mapExpressions(fn)) + val body1 = fn(body) + if (arguments1 != arguments || body1 != body) { + copy(arguments = arguments1, body = body1) + } else { + this + } } /** String representation. */ @@ -313,12 +319,18 @@ object Function { /** @inheritdoc */ override def mapExpressions( fn: java.util.function.Function[Expression, Expression] - ): Binding = - copy( - name = name.mapExpressions(fn), - arguments = arguments.map(_.mapExpressions(fn)), - body = fn(body) - ) + ): Binding = { + val name1 = name.mapExpressions(fn) + val arguments1 = arguments.map(_.mapExpressions(fn)) + val body1 = fn(body) + if (name1 != name || arguments1 != arguments || body1 != body) { + copy( + name = name1, + arguments = arguments1, + body = body1 + ) + } else this + } /** String representation. */ override def toString: String = diff --git a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Module.scala b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Module.scala index 1740fdfd1877..5e69d603d8bb 100644 --- a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Module.scala +++ b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Module.scala @@ -105,11 +105,16 @@ final case class Module( override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Module = { - copy( - imports = imports.map(_.mapExpressions(fn)), - exports = exports.map(_.mapExpressions(fn)), - bindings = bindings.map(_.mapExpressions(fn)) - ) + val imports1 = imports.map(_.mapExpressions(fn)) + val exports1 = exports.map(_.mapExpressions(fn)) + val bindings1 = bindings.map(_.mapExpressions(fn)) + if (imports1 != imports || exports1 != exports || bindings1 != bindings) + copy( + imports = imports1, + exports = exports1, + bindings = bindings1 + ) + else this } /** @inheritdoc */ diff --git a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Name.scala b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Name.scala index 815ccca1ce6d..afed7947dda3 100644 --- a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Name.scala +++ b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Name.scala @@ -118,11 +118,16 @@ object Name { /** @inheritdoc */ override def mapExpressions( fn: java.util.function.Function[Expression, Expression] - ): MethodReference = - copy( - typePointer = typePointer.map(_.mapExpressions(fn)), - methodName = methodName.mapExpressions(fn) - ) + ): MethodReference = { + val typePointer1 = typePointer.map(_.mapExpressions(fn)) + val methodName1 = methodName.mapExpressions(fn) + if (typePointer1 != typePointer || methodName1 != methodName) + copy( + typePointer = typePointer1, + methodName = methodName1 + ) + else this + } /** @inheritdoc */ override def setLocation( @@ -702,8 +707,12 @@ object Name { /** @inheritdoc */ override def mapExpressions( fn: java.util.function.Function[Expression, Expression] - ): GenericAnnotation = - copy(expression = fn(expression)) + ): GenericAnnotation = { + val expression1 = fn(expression) + if (expression1 != expression) + copy(expression = expression1) + else this + } /** String representation. */ override def toString: String = diff --git a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Pattern.scala b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Pattern.scala index 3e58a44c0775..401c4cc705f5 100644 --- a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Pattern.scala +++ b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Pattern.scala @@ -95,7 +95,8 @@ object Pattern { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Name = { - copy(name = name.mapExpressions(fn)) + val name1 = name.mapExpressions(fn) + if (name1 != name) copy(name = name1) else this } /** String representation. */ @@ -239,11 +240,17 @@ object Pattern { /** @inheritdoc */ override def mapExpressions( fn: java.util.function.Function[Expression, Expression] - ): Constructor = - copy( - constructor = constructor.mapExpressions(fn), - fields = fields.map(_.mapExpressions(fn)) - ) + ): Constructor = { + val constructor1 = constructor.mapExpressions(fn) + val fields1 = fields.map(_.mapExpressions(fn)) + + if (constructor1 != constructor || fields1 != fields) + copy( + constructor = constructor1, + fields = fields1 + ) + else this + } /** String representation. */ override def toString: String = @@ -339,7 +346,8 @@ object Pattern { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Literal = { - copy(literal = literal.mapExpressions(fn)) + val literal1 = literal.mapExpressions(fn) + if (literal1 != literal) copy(literal = literal1) else this } /** String representation. */ @@ -442,7 +450,11 @@ object Pattern { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Type = { - copy(name = name.mapExpressions(fn), tpe = tpe.mapExpressions(fn)) + val name1 = name.mapExpressions(fn) + val tpe1 = tpe.mapExpressions(fn) + if (name1 != name || tpe1 != tpe) + copy(name = name1, tpe = tpe1) + else this } /** String representation. */ diff --git a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Type.scala b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Type.scala index 57ddba922382..3413233c3510 100644 --- a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Type.scala +++ b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/Type.scala @@ -94,7 +94,11 @@ object Type { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Function = { - copy(args = args.map(fn.asScala), result = fn(result)) + val args1 = args.map(fn.asScala) + val result1 = fn(result) + if (args1 != args || result1 != result) + copy(args = args1, result = result1) + else this } /** String representation. */ @@ -201,7 +205,11 @@ object Type { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Ascription = { - copy(typed = fn(typed), signature = fn(signature)) + val typed1 = fn(typed) + val signature1 = fn(signature) + if (typed1 != typed || signature1 != signature) + copy(typed = typed1, signature = signature1) + else this } /** String representation. */ @@ -307,7 +315,11 @@ object Type { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Context = { - copy(typed = fn(typed), context = fn(context)) + val typed1 = fn(typed) + val context1 = fn(context) + if (typed1 != typed || context1 != context) + copy(typed = typed1, context = context1) + else this } /** String representation. */ @@ -410,8 +422,14 @@ object Type { /** @inheritdoc */ override def mapExpressions( fn: java.util.function.Function[Expression, Expression] - ): Error = - copy(typed = fn(typed), error = fn(error)) + ): Error = { + val typed1 = fn(typed) + val error1 = fn(error) + if (typed1 != typed || error1 != error) + copy(typed = typed1, error = error1) + else + this + } /** String representation. */ override def toString: String = diff --git a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/expression/Application.scala b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/expression/Application.scala index c76e7a882299..ff0d33a46379 100644 --- a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/expression/Application.scala +++ b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/expression/Application.scala @@ -105,7 +105,13 @@ object Application { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Prefix = { - copy(function = fn(function), arguments.map(_.mapExpressions(fn))) + val function1 = fn(function) + val arguments1 = arguments.map(_.mapExpressions(fn)) + if (function1 != function || arguments1 != arguments) { + copy(function = function1, arguments = arguments1) + } else { + this + } } /** String representation. */ @@ -200,7 +206,11 @@ object Application { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Force = { - copy(target = fn(target)) + val target1 = fn(target) + if (target1 != target) + copy(target = target1) + else + this } /** String representation. */ @@ -263,8 +273,13 @@ object Application { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] - ): Typeset = - copy(expression = expression.map(fn.asScala)) + ): Typeset = { + val expression1 = expression.map(fn.asScala) + if (expression1 != expression) + copy(expression = expression1) + else + this + } /** Creates a copy of `this`. * @@ -359,8 +374,13 @@ object Application { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] - ): Sequence = - copy(items = items.map(fn.asScala)) + ): Sequence = { + val items1 = items.map(fn.asScala) + if (items1 != items) + copy(items = items1) + else + this + } /** Creates a copy of `this`. * diff --git a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/expression/Case.scala b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/expression/Case.scala index 3015c653ac35..df1d6926b9ab 100644 --- a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/expression/Case.scala +++ b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/expression/Case.scala @@ -124,10 +124,17 @@ object Case { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Expr = { - copy( - scrutinee = fn(scrutinee), - branches.map(_.mapExpressions(fn)) - ) + val scrutinee1 = fn(scrutinee) + val branches1 = branches.map(_.mapExpressions(fn)) + + if (scrutinee1 != scrutinee || branches1 != branches) { + copy( + scrutinee = scrutinee1, + branches = branches1 + ) + } else { + this + } } /** String representation. */ @@ -280,7 +287,13 @@ object Case { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Branch = { - copy(pattern = pattern.mapExpressions(fn), expression = fn(expression)) + val pattern1 = pattern.mapExpressions(fn) + val expression1 = fn(expression) + if (pattern1 != pattern || expression1 != expression) { + copy(pattern = pattern1, expression = expression1) + } else { + this + } } /** String representation. */ diff --git a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/expression/Operator.scala b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/expression/Operator.scala index 7fc4487b22e5..b6b8c8afb252 100644 --- a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/expression/Operator.scala +++ b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/expression/Operator.scala @@ -116,7 +116,10 @@ object Operator { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Binary = { - copy(left = left.mapExpressions(fn), right = right.mapExpressions(fn)) + val left1 = left.mapExpressions(fn) + val right1 = right.mapExpressions(fn) + if (left1 != left || right1 != right) copy(left = left1, right = right1) + else this } /** String representation. */ diff --git a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/expression/Section.scala b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/expression/Section.scala index c127b07ce991..d7012f691c19 100644 --- a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/expression/Section.scala +++ b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/expression/Section.scala @@ -105,11 +105,17 @@ object Section { /** @inheritdoc */ override def mapExpressions( fn: java.util.function.Function[Expression, Expression] - ): Section = - copy( - arg = arg.mapExpressions(fn), - operator = operator.mapExpressions(fn) - ) + ): Section = { + val arg1 = arg.mapExpressions(fn) + val operator1 = operator.mapExpressions(fn) + + if (arg1 != arg || operator1 != operator) + copy( + arg = arg1, + operator = operator1 + ) + else this + } /** String representation. */ override def toString: String = @@ -200,8 +206,10 @@ object Section { /** @inheritdoc */ override def mapExpressions( fn: java.util.function.Function[Expression, Expression] - ): Section = - copy(operator = operator.mapExpressions(fn)) + ): Section = { + val operator1 = operator.mapExpressions(fn) + if (operator1 != operator) copy(operator = operator1) else this + } /** String representation. */ override def toString: String = @@ -302,10 +310,15 @@ object Section { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Section = { - copy( - operator = operator.mapExpressions(fn), - arg = arg.mapExpressions(fn) - ) + val operator1 = operator.mapExpressions(fn) + val arg1 = arg.mapExpressions(fn) + + if (operator1 != operator || arg1 != arg) + copy( + operator = operator1, + arg = arg1 + ) + else this } /** String representation. */ diff --git a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/expression/errors/Pattern.scala b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/expression/errors/Pattern.scala index bced8e4cfae8..de1512c36f32 100644 --- a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/expression/errors/Pattern.scala +++ b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/expression/errors/Pattern.scala @@ -25,8 +25,13 @@ sealed case class Pattern( with LazyId { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] - ): Pattern = - copy(originalPattern = originalPattern.mapExpressions(fn)) + ): Pattern = { + val originalPattern1 = originalPattern.mapExpressions(fn) + if (originalPattern1 != originalPattern) + copy(originalPattern = originalPattern1) + else + this + } override def setLocation(location: Option[IdentifiedLocation]): Pattern = copy(originalPattern = originalPattern.setLocation(location)) diff --git a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/module/scope/Definition.scala b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/module/scope/Definition.scala index 30d5be4745aa..b1636df27f81 100644 --- a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/module/scope/Definition.scala +++ b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/module/scope/Definition.scala @@ -118,11 +118,17 @@ object Definition { /** @inheritdoc */ override def mapExpressions( fn: java.util.function.Function[Expression, Expression] - ): Type = - copy( - params = params.map(_.mapExpressions(fn)), - members = members.map(_.mapExpressions(fn)) - ) + ): Type = { + val params1 = params.map(_.mapExpressions(fn)) + val members1 = members.map(_.mapExpressions(fn)) + + if (params1 != params || members1 != members) + copy( + params = params1, + members = members1 + ) + else this + } /** String representation. */ override def toString: String = @@ -242,11 +248,19 @@ object Definition { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Data = { - copy( - name = name.mapExpressions(fn), - arguments = arguments.map(_.mapExpressions(fn)), - annotations = annotations.map(_.mapExpressions(fn)) + val name1 = name.mapExpressions(fn) + val arguments1 = arguments.map(_.mapExpressions(fn)) + val annotations1 = annotations.map(_.mapExpressions(fn)) + + if ( + name1 != name || arguments1 != arguments || annotations1 != annotations ) + copy( + name = name1, + arguments = arguments1, + annotations = annotations1 + ) + else this } /** String representation. */ @@ -368,8 +382,10 @@ object Definition { /** @inheritdoc */ override def mapExpressions( fn: java.util.function.Function[Expression, Expression] - ): SugaredType = - copy(body = body.map(_.mapExpressions(fn))) + ): SugaredType = { + val body1 = body.map(_.mapExpressions(fn)) + if (body1 != body) copy(body = body1) else this + } /** @inheritdoc */ override def setLocation( diff --git a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/module/scope/definition/Method.scala b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/module/scope/definition/Method.scala index 657b2b85092a..d3b535658d9d 100644 --- a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/module/scope/definition/Method.scala +++ b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/module/scope/definition/Method.scala @@ -157,10 +157,15 @@ object Method { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Explicit = { - copy( - methodReference = methodReference.mapExpressions(fn), - body = fn(body) - ) + val methodReference1 = methodReference.mapExpressions(fn) + val body1 = fn(body) + + if (methodReference1 != methodReference || body1 != body) + copy( + methodReference = methodReference1, + body = body1 + ) + else this } /** String representation. */ @@ -335,11 +340,19 @@ object Method { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Binding = { - copy( - methodReference = methodReference.mapExpressions(fn), - arguments = arguments.map(_.mapExpressions(fn)), - body = fn(body) + val methodReference1 = methodReference.mapExpressions(fn) + val arguments1 = arguments.map(_.mapExpressions(fn)) + val body1 = fn(body) + + if ( + methodReference1 != methodReference || arguments1 != arguments || body1 != body ) + copy( + methodReference = methodReference1, + arguments = arguments1, + body = body1 + ) + else this } /** String representation. */ @@ -478,11 +491,20 @@ object Method { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Conversion = { - copy( - methodReference = methodReference.mapExpressions(fn), - sourceTypeName = sourceTypeName.mapExpressions(fn), - body = fn(body) + val methodReference1 = methodReference.mapExpressions(fn) + val sourceTypeName1 = sourceTypeName.mapExpressions(fn) + val body1 = fn(body) + + if ( + methodReference1 != methodReference || sourceTypeName1 != sourceTypeName || body1 != body ) + copy( + methodReference = methodReference1, + sourceTypeName = sourceTypeName1, + body = body1 + ) + else + this } /** String representation. */ From 0e3172d00badb4d53221b58412291a9bb89999e2 Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Wed, 31 Jul 2024 17:02:30 +0200 Subject: [PATCH 2/3] Optimize AliasAnalysis and TailCall One profiling data showed 10% improvement in AliasAnalysis which is encouraging. Overall it seems to be a bit hard to reliably quantify the potential improvement from lack of copying. --- .../compiler/pass/analyse/AliasAnalysis.scala | 378 ++++++++++-------- .../enso/compiler/pass/analyse/TailCall.scala | 223 ++++++----- .../pass/optimise/LambdaConsolidate.scala | 4 +- .../org/enso/compiler/core/ir/type/Set.scala | 46 ++- 4 files changed, 370 insertions(+), 281 deletions(-) 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 d64e56fef86b..b2d550c6d2e6 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 @@ -95,7 +95,11 @@ case object AliasAnalysis extends IRPass { ir: Module, moduleContext: ModuleContext ): Module = { - ir.copy(bindings = ir.bindings.map(analyseModuleDefinition)) + val bindings1 = ir.bindings.map(analyseModuleDefinition) + if (bindings1 != ir.bindings) + ir.copy(bindings = bindings1) + else + ir } /** Performs alias analysis on an inline expression, starting from the @@ -234,14 +238,13 @@ case object AliasAnalysis extends IRPass { case m: definition.Method.Conversion => m.body match { case _: Function => - m.copy( - body = analyseExpression( - m.body, - topLevelGraph, - topLevelGraph.rootScope, - lambdaReuseScope = true - ) - ).updateMetadata( + val body1 = analyseExpression( + m.body, + topLevelGraph, + topLevelGraph.rootScope, + lambdaReuseScope = true + ) + (if (body1 != m.body) m.copy(body = body1) else m).updateMetadata( new MetadataPair( this, alias.Info.Scope.Root(topLevelGraph) @@ -255,14 +258,13 @@ case object AliasAnalysis extends IRPass { case m @ definition.Method.Explicit(_, body, _, _, _) => body match { case _: Function => - m.copy( - body = analyseExpression( - body, - topLevelGraph, - topLevelGraph.rootScope, - lambdaReuseScope = true - ) - ).updateMetadata( + val body1 = analyseExpression( + body, + topLevelGraph, + topLevelGraph.rootScope, + lambdaReuseScope = true + ) + (if (body1 != m.body) m.copy(body = body1) else m).updateMetadata( new MetadataPair( this, alias.Info.Scope.Root(topLevelGraph) @@ -278,41 +280,46 @@ case object AliasAnalysis extends IRPass { "Method definition sugar should not occur during alias analysis." ) case t: Definition.Type => - t.copy( - params = analyseArgumentDefs( - t.params, - topLevelGraph, - topLevelGraph.rootScope - ), - members = t.members.map(d => { - val graph = new alias.Graph - d.copy( - arguments = analyseArgumentDefs( - d.arguments, - graph, - graph.rootScope - ), - annotations = d.annotations.map { ann => - ann - .copy( - expression = analyseExpression( - ann.expression, - topLevelGraph, - topLevelGraph.rootScope - ) - ) - .updateMetadata( - new MetadataPair( - this, - alias.Info.Scope.Root(topLevelGraph) - ) - ) - } - ).updateMetadata( - new MetadataPair(this, alias.Info.Scope.Root(graph)) + val params1 = analyseArgumentDefs( + t.params, + topLevelGraph, + topLevelGraph.rootScope + ) + val members1 = t.members.map(d => { + val graph = new alias.Graph + val arguments1 = analyseArgumentDefs( + d.arguments, + graph, + graph.rootScope + ) + val annotations1 = d.annotations.map { ann => + val expression1 = analyseExpression( + ann.expression, + topLevelGraph, + topLevelGraph.rootScope ) - }) - ).updateMetadata( + (if (expression1 != ann.expression) + ann.copy(expression = expression1) + else ann) + .updateMetadata( + new MetadataPair( + this, + alias.Info.Scope.Root(topLevelGraph) + ) + ) + } + (if (arguments1 != d.arguments || annotations1 != d.annotations) + d.copy(arguments = arguments1, annotations = annotations1) + else d).updateMetadata( + new MetadataPair(this, alias.Info.Scope.Root(graph)) + ) + }) + (if (params1 != t.params || members1 != t.members) + t.copy( + params = params1, + members = members1 + ) + else t).updateMetadata( new MetadataPair(this, alias.Info.Scope.Root(topLevelGraph)) ) case _: Definition.SugaredType => @@ -335,17 +342,15 @@ case object AliasAnalysis extends IRPass { "analysis." ) case ann: Name.GenericAnnotation => - ann - .copy(expression = - analyseExpression( - ann.expression, - topLevelGraph, - topLevelGraph.rootScope - ) - ) - .updateMetadata( - new MetadataPair(this, alias.Info.Scope.Root(topLevelGraph)) - ) + val expression1 = analyseExpression( + ann.expression, + topLevelGraph, + topLevelGraph.rootScope + ) + (if (expression1 != ann.expression) ann.copy(expression = expression1) + else ann).updateMetadata( + new MetadataPair(this, alias.Info.Scope.Root(topLevelGraph)) + ) case err: Error => err } } @@ -394,21 +399,26 @@ case object AliasAnalysis extends IRPass { val currentScope = if (!isSuspended) parentScope else parentScope.addChild() - block - .copy( - expressions = expressions.map((expression: Expression) => - analyseExpression( - expression, - graph, - currentScope - ) - ), - returnValue = analyseExpression( - retVal, - graph, - currentScope - ) + val expressions1 = expressions.map((expression: Expression) => + analyseExpression( + expression, + graph, + currentScope ) + ) + val returnValue1 = analyseExpression( + retVal, + graph, + currentScope + ) + + (if (expressions1 != expression || returnValue1 != retVal) + block + .copy( + expressions = expressions1, + returnValue = returnValue1 + ) + else block) .updateMetadata( new MetadataPair( this, @@ -434,14 +444,13 @@ case object AliasAnalysis extends IRPass { parentScope.add(occurrence) parentScope.addDefinition(occurrence) - binding - .copy( - expression = analyseExpression( - expression, - graph, - parentScope - ) - ) + val expression1 = analyseExpression( + expression, + graph, + parentScope + ) + (if (expression1 != expression) binding.copy(expression = expression1) + else binding) .updateMetadata( new MetadataPair( this, @@ -495,11 +504,16 @@ case object AliasAnalysis extends IRPass { parentScope.add(definition) parentScope.addDefinition(definition) - member - .copy( - memberType = analyseExpression(memberType, graph, memberTypeScope), - value = analyseExpression(value, graph, valueScope) - ) + val memberType1 = analyseExpression(memberType, graph, memberTypeScope) + val value1 = analyseExpression(value, graph, valueScope) + + (if (memberType1 != memberType || value1 != value) + member + .copy( + memberType = memberType1, + value = value1 + ) + else member) .updateMetadata( new MetadataPair(this, alias.Info.Occurrence(graph, labelId)) ) @@ -549,17 +563,17 @@ case object AliasAnalysis extends IRPass { arg.getExternalId ) scope.addDefinition(definition) - arg + val ascribedType1 = + arg.ascribedType.map(analyseExpression(_, graph, scope)) + (if (ascribedType1 != arg.ascribedType) + arg.copy(ascribedType = ascribedType1) + else arg) .updateMetadata( new MetadataPair( this, alias.Info.Occurrence(graph, occurrenceId) ) ) - .copy( - ascribedType = - arg.ascribedType.map(analyseExpression(_, graph, scope)) - ) case arg @ DefinitionArgument.Specified( name, @@ -592,12 +606,15 @@ case object AliasAnalysis extends IRPass { scope.add(definition) scope.addDefinition(definition) - arg - .copy( - defaultValue = newDefault, - ascribedType = - arg.ascribedType.map(analyseExpression(_, graph, scope)) - ) + val ascribedType1 = + arg.ascribedType.map(analyseExpression(_, graph, scope)) + (if (newDefault != value || ascribedType1 != arg.ascribedType) + arg + .copy( + defaultValue = newDefault, + ascribedType = ascribedType1 + ) + else arg) .updateMetadata( new MetadataPair( this, @@ -609,9 +626,7 @@ case object AliasAnalysis extends IRPass { case x if x.symbol == name.name => x } arg - .copy( - ascribedType = Some(Redefined.Arg(name, arg.location)) - ) + .copy(ascribedType = Some(Redefined.Arg(name, arg.location))) .updateMetadata( new MetadataPair( this, @@ -636,18 +651,24 @@ case object AliasAnalysis extends IRPass { ): Application = { application match { case app @ Application.Prefix(fun, arguments, _, _, _, _) => - app.copy( - function = analyseExpression(fun, graph, scope), - arguments = analyseCallArguments(arguments, graph, scope) - ) + val function1 = analyseExpression(fun, graph, scope) + val arguments1 = analyseCallArguments(arguments, graph, scope) + if (function1 != fun || arguments1 != arguments) + app.copy( + function = function1, + arguments = arguments1 + ) + else app case app @ Application.Force(expr, _, _, _) => - app.copy(target = analyseExpression(expr, graph, scope)) + val target1 = analyseExpression(expr, graph, scope) + if (target1 != expr) app.copy(target = target1) else app case app @ Application.Sequence(items, _, _, _) => - app.copy(items = items.map(analyseExpression(_, graph, scope))) + val items1 = items.map(analyseExpression(_, graph, scope)) + if (items1 != items) app.copy(items = items1) else app case tSet @ Application.Typeset(expr, _, _, _) => - val newScope = scope.addChild() - tSet - .copy(expression = expr.map(analyseExpression(_, graph, newScope))) + val newScope = scope.addChild() + val expression1 = expr.map(analyseExpression(_, graph, newScope)) + (if (expression1 != expr) tSet.copy(expression = expression1) else tSet) .updateMetadata( new MetadataPair( this, @@ -682,8 +703,8 @@ case object AliasAnalysis extends IRPass { case _: Literal => parentScope case _ => parentScope.addChild() } - arg - .copy(value = analyseExpression(expr, graph, currentScope)) + val value1 = analyseExpression(expr, graph, currentScope) + (if (value1 != expr) arg.copy(value = value1) else arg) .updateMetadata( new MetadataPair( this, @@ -713,15 +734,16 @@ case object AliasAnalysis extends IRPass { function match { case lambda @ Function.Lambda(arguments, body, _, _, _, _) => - lambda - .copy( - arguments = analyseArgumentDefs(arguments, graph, currentScope), - body = analyseExpression( - body, - graph, - currentScope - ) - ) + val arguments1 = analyseArgumentDefs(arguments, graph, currentScope) + val body1 = analyseExpression( + body, + graph, + currentScope + ) + + (if (arguments1 != arguments || body1 != body) + lambda.copy(arguments = arguments1, body = body1) + else lambda) .updateMetadata( new MetadataPair( this, @@ -789,11 +811,15 @@ case object AliasAnalysis extends IRPass { ): Case = { ir match { case caseExpr @ Case.Expr(scrutinee, branches, _, _, _, _) => - caseExpr - .copy( - scrutinee = analyseExpression(scrutinee, graph, parentScope), - branches = branches.map(analyseCaseBranch(_, graph, parentScope)) - ) + val scrutinee1 = analyseExpression(scrutinee, graph, parentScope) + val branches1 = branches.map(analyseCaseBranch(_, graph, parentScope)) + if (scrutinee1 != scrutinee || branches1 != branches) + caseExpr + .copy( + scrutinee = scrutinee1, + branches = branches1 + ) + else caseExpr case _: Case.Branch => throw new CompilerError("Case branch in `analyseCase`.") } @@ -812,16 +838,19 @@ case object AliasAnalysis extends IRPass { parentScope: Scope ): Case.Branch = { val currentScope = parentScope.addChild() - - branch - .copy( - pattern = analysePattern(branch.pattern, graph, currentScope), - expression = analyseExpression( - branch.expression, - graph, - currentScope - ) - ) + val pattern1 = analysePattern(branch.pattern, graph, currentScope) + val expression1 = analyseExpression( + branch.expression, + graph, + currentScope + ) + (if (pattern1 != branch.pattern || expression1 != branch.expression) + branch + .copy( + pattern = pattern1, + expression = expression1 + ) + else branch) .updateMetadata( new MetadataPair( this, @@ -844,15 +873,14 @@ case object AliasAnalysis extends IRPass { ): Pattern = { pattern match { case named @ Pattern.Name(name, _, _, _) => - named.copy( - name = analyseName( - name, - isInPatternContext = true, - isConstructorNameInPatternContext = false, - graph, - parentScope - ) + val name1 = analyseName( + name, + isInPatternContext = true, + isConstructorNameInPatternContext = false, + graph, + parentScope ) + if (name1 != name) named.copy(name = name1) else named case cons @ Pattern.Constructor(constructor, fields, _, _, _) => if (!cons.isDesugared) { throw new CompilerError( @@ -860,36 +888,44 @@ case object AliasAnalysis extends IRPass { "analysis." ) } - - cons.copy( - constructor = analyseName( - constructor, - isInPatternContext = true, - isConstructorNameInPatternContext = true, - graph, - parentScope - ), - fields = fields.map(analysePattern(_, graph, parentScope)) + val constructor1 = analyseName( + constructor, + isInPatternContext = true, + isConstructorNameInPatternContext = true, + graph, + parentScope ) + val fields1 = fields.map(analysePattern(_, graph, parentScope)) + + if (constructor1 != constructor || fields1 != fields) + cons.copy( + constructor = constructor1, + fields = fields1 + ) + else cons case literalPattern: Pattern.Literal => literalPattern case typePattern @ Pattern.Type(name, tpe, _, _, _) => - typePattern.copy( - name = analyseName( - name, - isInPatternContext = true, - isConstructorNameInPatternContext = false, - graph, - parentScope - ), - tpe = analyseName( - tpe, - isInPatternContext = false, - isConstructorNameInPatternContext = false, - graph, - parentScope - ) + val name1 = analyseName( + name, + isInPatternContext = true, + isConstructorNameInPatternContext = false, + graph, + parentScope ) + val tpe1 = analyseName( + tpe, + isInPatternContext = false, + isConstructorNameInPatternContext = false, + graph, + parentScope + ) + if (name1 != name || tpe1 != tpe) + typePattern.copy( + name = name1, + tpe = tpe1 + ) + else typePattern case _: Pattern.Documentation => throw new CompilerError( "Branch documentation should be desugared at an earlier stage." diff --git a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/TailCall.scala b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/TailCall.scala index ca5c0a608a2b..3666347b1879 100644 --- a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/TailCall.scala +++ b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/analyse/TailCall.scala @@ -73,7 +73,10 @@ case object TailCall extends IRPass { ir: Module, moduleContext: ModuleContext ): Module = { - ir.copy(bindings = ir.bindings.map(analyseModuleBinding)) + val bindings1 = ir.bindings.map(analyseModuleBinding) + if (bindings1 != ir.bindings) + ir.copy(bindings = bindings1) + else ir } /** Analyses tail call state for an arbitrary expression. @@ -108,17 +111,13 @@ case object TailCall extends IRPass { ): Definition = { moduleDefinition match { case method: definition.Method.Conversion => - method - .copy( - body = analyseExpression(method.body, isInTailPosition = true) - ) + val body1 = analyseExpression(method.body, isInTailPosition = true) + (if (body1 != method.body) method.copy(body = body1) else method) .updateMetadata(new MetadataPair(this, TailPosition.Tail)) case method @ definition.Method .Explicit(_, body, _, _, _) => - method - .copy( - body = analyseExpression(body, isInTailPosition = true) - ) + val body1 = analyseExpression(body, isInTailPosition = true) + (if (body1 != body) method.copy(body = body1) else method) .updateMetadata(new MetadataPair(this, TailPosition.Tail)) case _: definition.Method.Binding => throw new CompilerError( @@ -149,10 +148,10 @@ case object TailCall extends IRPass { "tail call analysis." ) case ann: Name.GenericAnnotation => + val expression1 = + analyseExpression(ann.expression, isInTailPosition = true) ann - .copy(expression = - analyseExpression(ann.expression, isInTailPosition = true) - ) + .copy(expression = expression1) .updateMetadata(new MetadataPair(this, TailPosition.Tail)) case err: Error => err } @@ -197,21 +196,28 @@ case object TailCall extends IRPass { _, _ ) => - block - .copy( - expressions = expressions.map( - analyseExpression(_, isInTailPosition = false) - ), - returnValue = analyseExpression(returnValue, isInTailPosition) - ) + val expression1 = + expressions.map(analyseExpression(_, isInTailPosition = false)) + val returnValue1 = analyseExpression(returnValue, isInTailPosition) + (if (expression1 != expression || returnValue1 != returnValue) + block + .copy( + expressions = expression1, + returnValue = returnValue1 + ) + else block) .updateMetadata( new MetadataPair(this, TailPosition.fromBool(isInTailPosition)) ) case binding @ Expression.Binding(_, expression, _, _, _) => - binding - .copy( - expression = analyseExpression(expression, isInTailPosition = false) - ) + val expression1 = + analyseExpression(expression, isInTailPosition = false) + (if (expression1 != expression) + binding + .copy( + expression = expression1 + ) + else binding) .updateMetadata( new MetadataPair(this, TailPosition.fromBool(isInTailPosition)) ) @@ -261,43 +267,40 @@ case object TailCall extends IRPass { application: Application, isInTailPosition: Boolean ): Application = { - application match { + val application1 = application match { case app @ Application.Prefix(fn, args, _, _, _, _) => - app - .copy( - function = analyseExpression(fn, isInTailPosition = false), - arguments = args.map(analyseCallArg) - ) - .updateMetadata( - new MetadataPair(this, TailPosition.fromBool(isInTailPosition)) - ) + val function1 = analyseExpression(fn, isInTailPosition = false) + val arguments1 = args.map(analyseCallArg) + if (function1 != fn || arguments1 != args) + app + .copy( + function = function1, + arguments = arguments1 + ) + else app case force @ Application.Force(target, _, _, _) => - force - .copy( - target = analyseExpression(target, isInTailPosition) - ) - .updateMetadata( - new MetadataPair(this, TailPosition.fromBool(isInTailPosition)) - ) + val target1 = analyseExpression(target, isInTailPosition) + if (target1 != target) + force + .copy( + target = target1 + ) + else force case vector @ Application.Sequence(items, _, _, _) => - vector - .copy(items = - items.map(analyseExpression(_, isInTailPosition = false)) - ) - .updateMetadata( - new MetadataPair(this, TailPosition.fromBool(isInTailPosition)) - ) + val items1 = items.map(analyseExpression(_, isInTailPosition = false)) + if (items1 != items) vector.copy(items = items1) else vector case tSet @ Application.Typeset(expr, _, _, _) => - tSet - .copy(expression = - expr.map(analyseExpression(_, isInTailPosition = false)) - ) - .updateMetadata( - new MetadataPair(this, TailPosition.fromBool(isInTailPosition)) - ) + val expression1 = + expr.map(analyseExpression(_, isInTailPosition = false)) + if (expression1 != expr) + tSet.copy(expression = expression1) + else tSet case _: Operator => throw new CompilerError("Unexpected binary operator.") } + application1.updateMetadata( + new MetadataPair(this, TailPosition.fromBool(isInTailPosition)) + ) } /** Performs tail call analysis on a call site argument. @@ -307,12 +310,10 @@ case object TailCall extends IRPass { */ def analyseCallArg(argument: CallArgument): CallArgument = { argument match { - case arg @ CallArgument.Specified(_, expr, _, _, _) => - arg - .copy( - // Note [Call Argument Tail Position] - value = analyseExpression(expr, isInTailPosition = true) - ) + case arg @ CallArgument.Specified(_, value, _, _, _) => + // Note [Call Argument Tail Position] + val value1 = analyseExpression(value, isInTailPosition = true) + (if (value1 != value) arg.copy(value = value1) else arg) .updateMetadata(new MetadataPair(this, TailPosition.Tail)) } } @@ -365,12 +366,18 @@ case object TailCall extends IRPass { def analyseCase(caseExpr: Case, isInTailPosition: Boolean): Case = { caseExpr match { case caseExpr @ Case.Expr(scrutinee, branches, _, _, _, _) => - caseExpr - .copy( - scrutinee = analyseExpression(scrutinee, isInTailPosition = false), - // Note [Analysing Branches in Case Expressions] - branches = branches.map(analyseCaseBranch(_, isInTailPosition)) - ) + val scrutinee1 = analyseExpression(scrutinee, isInTailPosition = false) + // Note [Analysing Branches in Case Expressions] + val branches1 = branches.map(analyseCaseBranch(_, isInTailPosition)) + + (if (scrutinee1 != scrutinee || branches1 != branches) + caseExpr + .copy( + scrutinee = scrutinee1, + // Note [Analysing Branches in Case Expressions] + branches = branches1 + ) + else caseExpr) .updateMetadata( new MetadataPair(this, TailPosition.fromBool(isInTailPosition)) ) @@ -401,14 +408,19 @@ case object TailCall extends IRPass { branch: Case.Branch, isInTailPosition: Boolean ): Case.Branch = { - branch - .copy( - pattern = analysePattern(branch.pattern), - expression = analyseExpression( - branch.expression, - isInTailPosition - ) - ) + val pattern1 = analysePattern(branch.pattern) + val expression1 = analyseExpression( + branch.expression, + isInTailPosition + ) + + (if (pattern1 != branch.pattern || expression1 != branch.expression) + branch + .copy( + pattern = pattern1, + expression = expression1 + ) + else branch) .updateMetadata( new MetadataPair(this, TailPosition.fromBool(isInTailPosition)) ) @@ -424,27 +436,38 @@ case object TailCall extends IRPass { ): Pattern = { pattern match { case namePat @ Pattern.Name(name, _, _, _) => - namePat - .copy( - name = analyseName(name, isInTailPosition = false) - ) + val name1 = analyseName(name, isInTailPosition = false) + (if (name1 != name) + namePat + .copy( + name = name1 + ) + else namePat) .updateMetadata(new MetadataPair(this, TailPosition.NotTail)) case cons @ Pattern.Constructor(constructor, fields, _, _, _) => - cons - .copy( - constructor = analyseName(constructor, isInTailPosition = false), - fields = fields.map(analysePattern) - ) + val constructor1 = analyseName(constructor, isInTailPosition = false) + val fields1 = fields.map(analysePattern) + (if (constructor1 != constructor || fields1 != fields) + cons + .copy( + constructor = constructor1, + fields = fields1 + ) + else cons) .updateMetadata(new MetadataPair(this, TailPosition.NotTail)) case literal: Pattern.Literal => literal .updateMetadata(new MetadataPair(this, TailPosition.NotTail)) case tpePattern @ Pattern.Type(name, tpe, _, _, _) => - tpePattern - .copy( - name = analyseName(name, isInTailPosition = false), - tpe = analyseName(tpe, isInTailPosition = false) - ) + val name1 = analyseName(name, isInTailPosition = false) + val tpe1 = analyseName(tpe, isInTailPosition = false) + if (name1 != name || tpe1 != tpe) + tpePattern + .copy( + name = name1, + tpe = tpe1 + ) + else tpePattern case err: errors.Pattern => err.updateMetadata(new MetadataPair(this, TailPosition.NotTail)) case _: Pattern.Documentation => @@ -470,10 +493,14 @@ case object TailCall extends IRPass { val resultFunction = function match { case lambda @ Function.Lambda(args, body, _, _, _, _) => - lambda.copy( - arguments = args.map(analyseDefArgument), - body = analyseExpression(body, isInTailPosition = markAsTail) - ) + val arguments1 = args.map(analyseDefArgument) + val body1 = analyseExpression(body, isInTailPosition = markAsTail) + if (arguments1 != args || body1 != body) + lambda.copy( + arguments = arguments1, + body = body1 + ) + else lambda case _: Function.Binding => throw new CompilerError( "Function sugar should not be present during tail call analysis." @@ -493,13 +520,13 @@ case object TailCall extends IRPass { def analyseDefArgument(arg: DefinitionArgument): DefinitionArgument = { arg match { case arg @ DefinitionArgument.Specified(_, _, default, _, _, _, _) => - arg - .copy( - defaultValue = default.map(x => - analyseExpression(x, isInTailPosition = false) - .updateMetadata(new MetadataPair(this, TailPosition.NotTail)) - ) - ) + val defaultValue1 = default.map(x => + analyseExpression(x, isInTailPosition = false) + .updateMetadata(new MetadataPair(this, TailPosition.NotTail)) + ) + (if (defaultValue1 != default) + arg.copy(defaultValue = defaultValue1) + else arg) .updateMetadata(new MetadataPair(this, TailPosition.NotTail)) } } diff --git a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/optimise/LambdaConsolidate.scala b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/optimise/LambdaConsolidate.scala index f80c55eea5bc..63a8f280173c 100644 --- a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/optimise/LambdaConsolidate.scala +++ b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/optimise/LambdaConsolidate.scala @@ -351,7 +351,7 @@ case object LambdaConsolidate extends IRPass { args: List[DefinitionArgument] ): Set[AliasGraph.Id] = { args - .map { case spec: DefinitionArgument.Specified => + .flatMap { case spec: DefinitionArgument.Specified => val aliasInfo = spec .unsafeGetMetadata( @@ -364,8 +364,8 @@ case object LambdaConsolidate extends IRPass { .flatMap(occ => Some(aliasInfo.graph.knownShadowedDefinitions(occ))) .getOrElse(Set()) } - .foldLeft(Set[AliasGraph.Occurrence]())(_ ++ _) .map(_.id) + .toSet } /** Computes the identifiers of expression that use a shadowed argument. diff --git a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/type/Set.scala b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/type/Set.scala index c7af7e98a230..9822a45e1336 100644 --- a/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/type/Set.scala +++ b/engine/runtime-parser/src/main/scala/org/enso/compiler/core/ir/type/Set.scala @@ -119,11 +119,17 @@ object Set { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Member = { - copy( - label = label.mapExpressions(fn), - memberType = fn(memberType), - value = fn(value) - ) + val label1 = label.mapExpressions(fn) + val memberType1 = fn(memberType) + val value1 = fn(value) + + if (label1 != label || memberType1 != memberType || value1 != value) + copy( + label = label1, + memberType = memberType1, + value = value1 + ) + else this } /** String representation. */ @@ -233,7 +239,11 @@ object Set { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Subsumption = { - copy(left = fn(left), right = fn(right)) + val left1 = fn(left) + val right1 = fn(right) + if (left1 != left || right1 != right) + copy(left = left1, right = right1) + else this } /** String representation. */ @@ -338,7 +348,11 @@ object Set { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Equality = { - copy(left = fn(left), right = fn(right)) + val left1 = fn(left) + val right1 = fn(right) + if (left1 != left || right1 != right) + copy(left = left1, right = right1) + else this } /** String representation. */ @@ -442,7 +456,11 @@ object Set { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Concat = { - copy(left = fn(left), right = fn(right)) + val left1 = fn(left) + val right1 = fn(right) + if (left1 != left || right1 != right) + copy(left = left1, right = right1) + else this } /** String representation. */ @@ -539,7 +557,11 @@ object Set { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Union = { - copy(operands = operands.map(fn.asScala)) + val operands1 = operands.map(fn.asScala) + if (operands1 != operands) + copy(operands = operands1) + else + this } /** String representation. */ @@ -643,7 +665,11 @@ object Set { override def mapExpressions( fn: java.util.function.Function[Expression, Expression] ): Intersection = { - copy(left = fn(left), right = fn(right)) + val left1 = fn(left) + val right1 = fn(right) + if (left1 != left || right1 != right) + copy(left = left1, right = right1) + else this } /** String representation. */ From 8fc5aabccd4343737aa12cea52238d63a4e670ad Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Thu, 1 Aug 2024 11:12:28 +0200 Subject: [PATCH 3/3] two more candidates --- .../pass/analyse/DataflowAnalysis.scala | 328 ++++++++++-------- .../pass/resolve/IgnoredBindings.scala | 78 +++-- 2 files changed, 240 insertions(+), 166 deletions(-) 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 ceb99906adf9..7f481fb66caa 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 @@ -73,9 +73,9 @@ case object DataflowAnalysis extends IRPass { moduleContext: ModuleContext ): Module = { val dependencyInfo = new DependencyInfo - ir.copy( - bindings = ir.bindings.map(analyseModuleDefinition(_, dependencyInfo)) - ).updateMetadata(new MetadataPair(this, dependencyInfo)) + val bindings1 = ir.bindings.map(analyseModuleDefinition(_, dependencyInfo)) + (if (bindings1 != ir.bindings) ir.copy(bindings = bindings1) else ir) + .updateMetadata(new MetadataPair(this, dependencyInfo)) } /** Performs dataflow analysis on an inline expression. @@ -150,11 +150,15 @@ case object DataflowAnalysis extends IRPass { info.dependents.updateAt(bodyDep, Set(methodDep)) info.dependencies.updateAt(methodDep, Set(bodyDep, sourceTypeDep)) - m.copy( - body = analyseExpression(m.body, info), - sourceTypeName = - m.sourceTypeName.updateMetadata(new MetadataPair(this, info)) - ).updateMetadata(new MetadataPair(this, info)) + val body1 = analyseExpression(m.body, info) + val sourceTypeName1 = + m.sourceTypeName.updateMetadata(new MetadataPair(this, info)) + (if (body1 != m.body || sourceTypeName1 != m.sourceTypeName) + m.copy( + body = body1, + sourceTypeName = sourceTypeName1 + ) + else m).updateMetadata(new MetadataPair(this, info)) case method @ definition.Method .Explicit(_, body, _, _, _) => val bodyDep = asStatic(body) @@ -162,8 +166,9 @@ case object DataflowAnalysis extends IRPass { info.dependents.updateAt(bodyDep, Set(methodDep)) info.dependencies.update(methodDep, Set(bodyDep)) + val body1 = analyseExpression(body, info) method - .copy(body = analyseExpression(body, info)) + .copy(body = body1) .updateMetadata(new MetadataPair(this, info)) case tp @ Definition.Type(_, params, members, _, _, _) => val tpDep = asStatic(tp) @@ -183,13 +188,18 @@ case object DataflowAnalysis extends IRPass { info.dependencies.updateAt(dataDep, Set(argDep)) }) - data - .copy( - arguments = data.arguments.map(analyseDefinitionArgument(_, info)) - ) + val arguments1 = + data.arguments.map(analyseDefinitionArgument(_, info)) + (if (arguments1 != data.arguments) + data + .copy(arguments = arguments1) + else data) .updateMetadata(new MetadataPair(this, info)) + } - tp.copy(params = newParams, members = newMembers) + (if (newParams != params || newMembers != members) + tp.copy(params = newParams, members = newMembers) + else tp) .updateMetadata(new MetadataPair(this, info)) case _: definition.Method.Binding => throw new CompilerError( @@ -216,8 +226,11 @@ case object DataflowAnalysis extends IRPass { "dataflow analysis." ) case ann: Name.GenericAnnotation => - ann - .copy(expression = analyseExpression(ann.expression, info)) + val expression1 = analyseExpression(ann.expression, info) + (if (expression1 != ann.expression) + ann + .copy(expression = expression1) + else ann) .updateMetadata(new MetadataPair(this, info)) case err: Error => err } @@ -254,11 +267,15 @@ case object DataflowAnalysis extends IRPass { info.dependents.updateAt(retValDep, Set(blockDep)) info.dependencies.updateAt(blockDep, Set(retValDep)) - block - .copy( - expressions = expressions.map(analyseExpression(_, info)), - returnValue = analyseExpression(returnValue, info) - ) + val expressions1 = expressions.map(analyseExpression(_, info)) + val returnValue1 = analyseExpression(returnValue, info) + (if (expressions1 != expressions || returnValue1 != returnValue) + block + .copy( + expressions = expressions1, + returnValue = returnValue1 + ) + else block) .updateMetadata(new MetadataPair(this, info)) case binding @ Expression.Binding(name, expression, _, _, _) => val expressionDep = asStatic(expression) @@ -268,11 +285,14 @@ case object DataflowAnalysis extends IRPass { info.dependents.updateAt(nameDep, Set(bindingDep)) info.dependencies.updateAt(bindingDep, Set(expressionDep, nameDep)) - binding - .copy( - name = name.updateMetadata(new MetadataPair(this, info)), - expression = analyseExpression(expression, info) - ) + val expression1 = analyseExpression(expression, info) + name.updateMetadata(new MetadataPair(this, info)) + (if (expression1 != expression) + binding + .copy( + expression = analyseExpression(expression, info) + ) + else binding) .updateMetadata(new MetadataPair(this, info)) case error: Error => error @@ -303,11 +323,15 @@ case object DataflowAnalysis extends IRPass { info.dependents.updateAt(bodyDep, Set(lamDep)) info.dependencies.updateAt(lamDep, Set(bodyDep)) - lam - .copy( - arguments = arguments.map(analyseDefinitionArgument(_, info)), - body = analyseExpression(body, info) - ) + val arguments1 = arguments.map(analyseDefinitionArgument(_, info)) + val body1 = analyseExpression(body, info) + (if (arguments1 != arguments || body1 != body) + lam + .copy( + arguments = arguments1, + body = body1 + ) + else lam) .updateMetadata(new MetadataPair(this, info)) case _: Function.Binding => throw new CompilerError( @@ -335,17 +359,21 @@ case object DataflowAnalysis extends IRPass { val prefixDep = asStatic(prefix) info.dependents.updateAt(fnDep, Set(prefixDep)) info.dependencies.updateAt(prefixDep, Set(fnDep)) - args.foreach(arg => { + args.foreach { arg => val argDep = asStatic(arg) info.dependents.updateAt(argDep, Set(prefixDep)) info.dependencies.updateAt(prefixDep, Set(argDep)) - }) + } - prefix - .copy( - function = analyseExpression(fn, info), - arguments = args.map(analyseCallArgument(_, info)) - ) + val function1 = analyseExpression(fn, info) + val arguments1 = args.map(analyseCallArgument(_, info)) + (if (function1 != fn || arguments1 != args) + prefix + .copy( + function = function1, + arguments = arguments1 + ) + else prefix) .updateMetadata(new MetadataPair(this, info)) case force @ Application.Force(target, _, _, _) => val targetDep = asStatic(target) @@ -353,8 +381,11 @@ case object DataflowAnalysis extends IRPass { info.dependents.updateAt(targetDep, Set(forceDep)) info.dependencies.updateAt(forceDep, Set(targetDep)) - force - .copy(target = analyseExpression(target, info)) + val target1 = analyseExpression(target, info) + (if (target1 != target) + force + .copy(target = target1) + else force) .updateMetadata(new MetadataPair(this, info)) case vector @ Application.Sequence(items, _, _, _) => val vectorDep = asStatic(vector) @@ -364,8 +395,11 @@ case object DataflowAnalysis extends IRPass { info.dependencies.updateAt(vectorDep, Set(itemDep)) }) - vector - .copy(items = items.map(analyseExpression(_, info))) + val items1 = items.map(analyseExpression(_, info)) + (if (items1 != items) + vector + .copy(items = items1) + else vector) .updateMetadata(new MetadataPair(this, info)) case tSet @ Application.Typeset(expr, _, _, _) => val tSetDep = asStatic(tSet) @@ -375,8 +409,11 @@ case object DataflowAnalysis extends IRPass { info.dependencies.updateAt(tSetDep, Set(exprDep)) }) - tSet - .copy(expression = expr.map(analyseExpression(_, info))) + val expression1 = expr.map(analyseExpression(_, info)) + (if (expression1 != expr) + tSet + .copy(expression = expression1) + else tSet) .updateMetadata(new MetadataPair(this, info)) case _: Operator => throw new CompilerError("Unexpected operator during Dataflow Analysis.") @@ -401,11 +438,16 @@ case object DataflowAnalysis extends IRPass { info.dependents.updateAt(sigDep, Set(ascrDep)) info.dependencies.updateAt(ascrDep, Set(typedDep, sigDep)) - asc - .copy( - typed = analyseExpression(typed, info), - signature = analyseExpression(signature, info) - ) + val typed1 = analyseExpression(typed, info) + val signature1 = analyseExpression(signature, info) + + (if (typed1 != typed || signature1 != signature) + asc + .copy( + typed = typed1, + signature = signature1 + ) + else asc) .updateMetadata(new MetadataPair(this, info)) case fun @ Type.Function(args, result, _, _, _) => @@ -416,11 +458,11 @@ case object DataflowAnalysis extends IRPass { info.dependents.updateAt(resDep, Set(funDep)) info.dependencies.updateAt(funDep, Set(resDep :: argDeps: _*)) - fun - .copy( - args = args.map(analyseExpression(_, info)), - result = analyseExpression(result, info) - ) + val args1 = args.map(analyseExpression(_, info)) + val result1 = analyseExpression(result, info) + (if (args1 != args || result1 != result) + fun.copy(args = args1, result = result1) + else fun) .updateMetadata(new MetadataPair(this, info)) case ctx @ Type.Context(typed, context, _, _, _) => val ctxDep = asStatic(ctx) @@ -430,10 +472,12 @@ case object DataflowAnalysis extends IRPass { info.dependents.updateAt(contextDep, Set(ctxDep)) info.dependencies.updateAt(ctxDep, Set(typedDep, contextDep)) + val typed1 = analyseExpression(typed, info) + val context1 = analyseExpression(context, info) ctx .copy( - typed = analyseExpression(typed, info), - context = analyseExpression(context, info) + typed = typed1, + context = context1 ) .updateMetadata(new MetadataPair(this, info)) case err @ Type.Error(typed, error, _, _, _) => @@ -444,11 +488,15 @@ case object DataflowAnalysis extends IRPass { info.dependents.updateAt(errorDep, Set(errDep)) info.dependencies.updateAt(errDep, Set(typedDep, errorDep)) - err - .copy( - typed = analyseExpression(typed, info), - error = analyseExpression(error, info) - ) + val typed1 = analyseExpression(typed, info) + val error1 = analyseExpression(error, info) + (if (typed1 != typed || error1 != error) + err + .copy( + typed = typed1, + error = error1 + ) + else err) .updateMetadata(new MetadataPair(this, info)) case member @ `type`.Set.Member(_, memberType, value, _, _, _) => val memberDep = asStatic(member) @@ -458,11 +506,15 @@ case object DataflowAnalysis extends IRPass { info.dependents.updateAt(valueDep, Set(memberDep)) info.dependencies.updateAt(memberDep, Set(memberTypeDep, valueDep)) - member - .copy( - memberType = analyseExpression(memberType, info), - value = analyseExpression(value, info) - ) + val memberType1 = analyseExpression(memberType, info) + val value1 = analyseExpression(value, info) + (if (memberType1 != memberType || value1 != value) + member + .copy( + memberType = memberType1, + value = value1 + ) + else member) .updateMetadata(new MetadataPair(this, info)) case concat @ `type`.Set.Concat(left, right, _, _, _) => val concatDep = asStatic(concat) @@ -472,11 +524,15 @@ case object DataflowAnalysis extends IRPass { info.dependents.updateAt(rightDep, Set(concatDep)) info.dependencies.updateAt(concatDep, Set(rightDep, leftDep)) - concat - .copy( - left = analyseExpression(left, info), - right = analyseExpression(right, info) - ) + val left1 = analyseExpression(left, info) + val right1 = analyseExpression(right, info) + (if (left1 != left || right1 != right) + concat + .copy( + left = left1, + right = right1 + ) + else concat) .updateMetadata(new MetadataPair(this, info)) case eq @ `type`.Set.Equality(left, right, _, _, _) => val eqDep = asStatic(eq) @@ -486,10 +542,11 @@ case object DataflowAnalysis extends IRPass { info.dependents.updateAt(rightDep, Set(eqDep)) info.dependencies.updateAt(eqDep, Set(leftDep, rightDep)) - eq.copy( - left = analyseExpression(left, info), - right = analyseExpression(right, info) - ).updateMetadata(new MetadataPair(this, info)) + val left1 = analyseExpression(left, info) + val right1 = analyseExpression(right, info) + (if (left1 != left || right1 != right) + eq.copy(left = left1, right = right1) + else eq).updateMetadata(new MetadataPair(this, info)) case intersect @ `type`.Set.Intersection(left, right, _, _, _) => val intersectDep = asStatic(intersect) val leftDep = asStatic(left) @@ -498,19 +555,22 @@ case object DataflowAnalysis extends IRPass { info.dependents.updateAt(rightDep, Set(intersectDep)) info.dependencies.updateAt(intersectDep, Set(leftDep, rightDep)) - intersect - .copy( - left = analyseExpression(left, info), - right = analyseExpression(right, info) - ) - .updateMetadata(new MetadataPair(this, info)) + val left1 = analyseExpression(left, info) + val right1 = analyseExpression(right, info) + (if (left1 != left || right1 != right) + intersect.copy(left = left1, right = right1) + else intersect).updateMetadata(new MetadataPair(this, info)) case union @ `type`.Set.Union(operands, _, _, _) => val unionDep = asStatic(union) val opDeps = operands.map(asStatic) opDeps.foreach(info.dependents.updateAt(_, Set(unionDep))) info.dependencies.updateAt(unionDep, opDeps.toSet) - union - .copy(operands = operands.map(analyseExpression(_, info))) + + val operands1 = operands.map(analyseExpression(_, info)) + (if (operands1 != operands) + union + .copy(operands = operands1) + else union) .updateMetadata(new MetadataPair(this, info)) case subsumption @ `type`.Set.Subsumption(left, right, _, _, _) => val subDep = asStatic(subsumption) @@ -520,12 +580,11 @@ case object DataflowAnalysis extends IRPass { info.dependents.updateAt(rightDep, Set(subDep)) info.dependencies.updateAt(subDep, Set(leftDep, rightDep)) - subsumption - .copy( - left = analyseExpression(left, info), - right = analyseExpression(right, info) - ) - .updateMetadata(new MetadataPair(this, info)) + val left1 = analyseExpression(left, info) + val right1 = analyseExpression(right, info) + (if (left1 != left || right1 != right) + subsumption.copy(left = left1, right = right1) + else subsumption).updateMetadata(new MetadataPair(this, info)) } } @@ -601,11 +660,16 @@ case object DataflowAnalysis extends IRPass { info.dependencies.updateAt(exprDep, Set(branchDep)) }) - expr - .copy( - scrutinee = analyseExpression(expr.scrutinee, info), - branches = expr.branches.map(analyseCaseBranch(_, info)) - ) + val scrutinee1 = analyseExpression(expr.scrutinee, info) + val branches1 = expr.branches.map(analyseCaseBranch(_, info)) + + (if (scrutinee1 != expr.scrutinee || branches1 != expr.branches) + expr + .copy( + scrutinee = scrutinee1, + branches = branches1 + ) + else expr) .updateMetadata(new MetadataPair(this, info)) case _: Case.Branch => throw new CompilerError("Unexpected case branch.") @@ -635,11 +699,16 @@ case object DataflowAnalysis extends IRPass { info.dependents.updateAt(exprDep, Set(branchDep)) info.dependencies.updateAt(branchDep, Set(patternDep, exprDep)) - branch - .copy( - pattern = analysePattern(pattern, info), - expression = analyseExpression(expression, info) - ) + val pattern1 = analysePattern(pattern, info) + val expression1 = analyseExpression(expression, info) + + (if (pattern1 != pattern || expression1 != expression) + branch + .copy( + pattern = pattern1, + expression = expression1 + ) + else branch) .updateMetadata(new MetadataPair(this, info)) } @@ -673,11 +742,16 @@ case object DataflowAnalysis extends IRPass { info.dependencies.updateAt(patternDep, Set(fieldDep)) }) - cons - .copy( - constructor = analyseName(constructor, info), - fields = fields.map(analysePattern(_, info)) - ) + val constructor1 = analyseName(constructor, info) + val fields1 = fields.map(analysePattern(_, info)) + + (if (constructor1 != constructor || fields1 != fields) + cons + .copy( + constructor = constructor1, + fields = fields1 + ) + else cons) .updateMetadata(new MetadataPair(this, info)) case literal: Pattern.Literal => literal.updateMetadata(new MetadataPair(this, info)) @@ -721,10 +795,13 @@ case object DataflowAnalysis extends IRPass { info.dependencies.updateAt(specDep, Set(exprDep)) }) - spec - .copy( - defaultValue = defValue.map(analyseExpression(_, info)) - ) + val defaultValue1 = defValue.map(analyseExpression(_, info)) + (if (defaultValue1 != defValue) + spec + .copy( + defaultValue = defaultValue1 + ) + else spec) .updateMetadata(new MetadataPair(this, info)) } } @@ -754,10 +831,13 @@ case object DataflowAnalysis extends IRPass { info.dependencies.updateAt(specDep, Set(nameDep)) }) - spec - .copy( - value = analyseExpression(value, info) - ) + val value1 = analyseExpression(value, info) + (if (value1 != value) + spec + .copy( + value = analyseExpression(value, info) + ) + else spec) .updateMetadata(new MetadataPair(this, info)) } } @@ -921,18 +1001,6 @@ case object DataflowAnalysis extends IRPass { } } - /** Updates the associations for the provided keys, or creates them if they - * do not already exist. - * - * @param keys the keys to add or update assocuations for - * @param dependents the new associations information for each `key` in - * `keys` - */ - def updateAt( - keys: List[DependencyInfo.Type], - dependents: Set[DependencyInfo.Type] - ): Unit = keys.foreach(key => updateAt(key, dependents)) - /** Combines two dependency information containers. * * @param that the other container to combine with `this` @@ -972,18 +1040,6 @@ case object DataflowAnalysis extends IRPass { ) extends IRPass.IRMetadata { override val metadataName: String = "DataflowAnalysis.DependencyInfo" - /** Combines two dependency information containers. - * - * @param that the other container to combine with `this` - * @return the result of combining `this` and `that` - */ - def ++(that: DependencyInfo): DependencyInfo = { - DependencyInfo( - dependents = this.dependents ++ that.dependents, - dependencies = that.dependencies ++ that.dependencies - ) - } - override def duplicate(): Option[IRPass.IRMetadata] = None /** @inheritdoc */ diff --git a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/resolve/IgnoredBindings.scala b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/resolve/IgnoredBindings.scala index 5acff5c265e4..ab74b049c761 100644 --- a/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/resolve/IgnoredBindings.scala +++ b/engine/runtime-compiler/src/main/scala/org/enso/compiler/pass/resolve/IgnoredBindings.scala @@ -181,10 +181,13 @@ case object IgnoredBindings extends IRPass { genNewArg(arg, isIgnore, supply) } - lam.copy( - arguments = newArgs, - body = resolveExpression(body, supply) - ) + val newBody = resolveExpression(body, supply) + if (newArgs != args || newBody != body) + lam.copy( + arguments = newArgs, + body = newBody + ) + else lam case _: Function.Binding => throw new CompilerError( "Function sugar should not be present during ignored " + @@ -219,10 +222,12 @@ case object IgnoredBindings extends IRPass { _ ) => // Note [Ignored `this` Argument] - spec - .copy(defaultValue = - spec.defaultValue.map(resolveExpression(_, freshNameSupply)) - ) + val defaultValue1 = + spec.defaultValue.map(resolveExpression(_, freshNameSupply)) + (if (defaultValue1 != spec.defaultValue) + spec + .copy(defaultValue = defaultValue1) + else spec) .updateMetadata(new MetadataPair(this, State.Ignored)) case spec: DefinitionArgument.Specified => if (isIgnored) { @@ -242,12 +247,15 @@ case object IgnoredBindings extends IRPass { ) .updateMetadata(new MetadataPair(this, State.Ignored)) } else { + val defaultValue1 = + spec.defaultValue.map(resolveExpression(_, freshNameSupply)) setNotIgnored( - spec - .copy( - defaultValue = - spec.defaultValue.map(resolveExpression(_, freshNameSupply)) - ) + if (defaultValue1 != spec.defaultValue) + spec + .copy( + defaultValue = defaultValue1 + ) + else spec ) } } @@ -287,10 +295,15 @@ case object IgnoredBindings extends IRPass { def resolveCase(cse: Case, supply: FreshNameSupply): Case = { cse match { case expr @ Case.Expr(scrutinee, branches, _, _, _, _) => - expr.copy( - scrutinee = resolveExpression(scrutinee, supply), - branches = branches.map(resolveCaseBranch(_, supply)) - ) + val scrutinee1 = resolveExpression(scrutinee, supply) + val branches1 = branches.map(resolveCaseBranch(_, supply)) + + if (scrutinee1 != scrutinee || branches1 != branches) + expr.copy( + scrutinee = scrutinee1, + branches = branches1 + ) + else expr case _: Case.Branch => throw new CompilerError( "Unexpected case branch while desugaring ignores for case." @@ -308,10 +321,14 @@ case object IgnoredBindings extends IRPass { branch: Case.Branch, supply: FreshNameSupply ): Case.Branch = { - branch.copy( - pattern = resolvePattern(branch.pattern, supply), - expression = resolveExpression(branch.expression, supply) - ) + val pattern1 = resolvePattern(branch.pattern, supply) + val expression1 = resolveExpression(branch.expression, supply) + if (pattern1 != branch.pattern || expression1 != branch.expression) + branch.copy( + pattern = resolvePattern(branch.pattern, supply), + expression = resolveExpression(branch.expression, supply) + ) + else branch } /** Resolves ignored bindings in a pattern. @@ -340,14 +357,16 @@ case object IgnoredBindings extends IRPass { name = newName ) } else { - named.copy( - name = setNotIgnored(name) - ) + setNotIgnored(named.name) + named } case cons @ Pattern.Constructor(_, fields, _, _, _) => - cons.copy( - fields = fields.map(resolvePattern(_, supply)) - ) + val fields1 = fields.map(resolvePattern(_, supply)) + if (fields1 != fields) + cons.copy( + fields = fields.map(resolvePattern(_, supply)) + ) + else cons case literal: Pattern.Literal => literal case typed @ Pattern.Type(name, _, _, _, _) => if (isIgnore(name)) { @@ -364,9 +383,8 @@ case object IgnoredBindings extends IRPass { name = newName ) } else { - typed.copy( - name = setNotIgnored(name) - ) + setNotIgnored(typed.name) + typed } case err: errors.Pattern => err case _: Pattern.Documentation =>