Referencing self from static method raises compiler error (#7131)

Add a new `NoStaticInSelf` compiler pass that ensures that `self` keyword is used only from instance methods.
This commit is contained in:
Pavel Marek 2023-06-28 19:04:32 +02:00 committed by GitHub
parent b4d0a40c7d
commit 60ef7e0ba3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 266 additions and 305 deletions

View File

@ -1117,7 +1117,7 @@ type Number_Parse_Error
## PRIVATE ## PRIVATE
Pretty print the syntax error. Pretty print the syntax error.
to_display_text : Text to_display_text : Text
to_display_text = to_display_text self =
"Could not parse " + self.text.to_text + " as a double." "Could not parse " + self.text.to_text + " as a double."
## PRIVATE ## PRIVATE

View File

@ -7868,6 +7868,11 @@ object IR {
override def explanation: String = "Ambiguous expression" override def explanation: String = "Ambiguous expression"
} }
case object InvalidSelfArgUsage extends Reason {
override def explanation: String =
"Self argument cannot be used in static methods"
}
case object UnrecognizedToken extends Reason { case object UnrecognizedToken extends Reason {
override def explanation: String = "Unrecognized token" override def explanation: String = "Unrecognized token"
} }

View File

@ -1,5 +1,6 @@
package org.enso.interpreter.bench.benchmarks.semantic; package org.enso.interpreter.bench.benchmarks.semantic;
import org.enso.polyglot.MethodNames.Module;
import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value; import org.graalvm.polyglot.Value;
import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.annotations.*;
@ -22,7 +23,6 @@ public class TypePatternBenchmarks {
private Value patternMatch; private Value patternMatch;
private Value avg; private Value avg;
private Value vec; private Value vec;
private Value self;
@Setup @Setup
public void initializeBenchmark(BenchmarkParams params) throws Exception { public void initializeBenchmark(BenchmarkParams params) throws Exception {
@ -43,8 +43,8 @@ public class TypePatternBenchmarks {
@Tail_Call sum (acc + arr.at i) i+1 @Tail_Call sum (acc + arr.at i) i+1
(sum 0 0) / arr.length (sum 0 0) / arr.length
avg_pattern self arr pattern = avg_pattern arr pattern =
avg (arr.map (pattern self)) avg (arr.map (pattern _))
gen_vec size value = gen_vec size value =
b = Vector.new_builder size b = Vector.new_builder size
@ -65,20 +65,14 @@ public class TypePatternBenchmarks {
var src = SrcUtil.source(benchmarkName, code); var src = SrcUtil.source(benchmarkName, code);
var module = ctx.eval(src); var module = ctx.eval(src);
this.self = module.invokeMember("get_associated_type"); Function<String,Value> getMethod = (name) -> module.invokeMember(Module.EVAL_EXPRESSION, name);
Function<String,Value> getMethod = (name) -> module.invokeMember("get_method", self, name);
var length = 100; var length = 100;
this.vec = getMethod.apply("gen_vec").execute(self, length, 1.1); this.vec = getMethod.apply("gen_vec").execute(length, 1.1);
switch (SrcUtil.findName(params)) { switch (SrcUtil.findName(params)) {
case "matchOverAny": case "matchOverAny" -> this.patternMatch = getMethod.apply("match_any");
this.patternMatch = getMethod.apply("match_any"); case "matchOverDecimal" -> this.patternMatch = getMethod.apply("match_dec");
break; default -> throw new IllegalStateException("Unexpected benchmark: " + params.getBenchmark());
case "matchOverDecimal":
this.patternMatch = getMethod.apply("match_dec");
break;
default:
throw new IllegalStateException("Unexpected benchmark: " + params.getBenchmark());
} }
this.avg = getMethod.apply("avg_pattern"); this.avg = getMethod.apply("avg_pattern");
} }
@ -98,7 +92,7 @@ public class TypePatternBenchmarks {
} }
private void performBenchmark(Blackhole matter) throws AssertionError { private void performBenchmark(Blackhole matter) throws AssertionError {
var average = avg.execute(self, this.vec, this.patternMatch); var average = avg.execute(this.vec, this.patternMatch);
if (!average.fitsInDouble()) { if (!average.fitsInDouble()) {
throw new AssertionError("Shall be a double: " + average); throw new AssertionError("Shall be a double: " + average);
} }

View File

@ -33,7 +33,7 @@ public final class Function implements TruffleObject {
private final RootCallTarget callTarget; private final RootCallTarget callTarget;
private final MaterializedFrame scope; private final MaterializedFrame scope;
private final FunctionSchema schema; private final FunctionSchema schema;
private final @CompilerDirectives.CompilationFinal(dimensions = 1) Object[] preAppliedArguments; private final @CompilationFinal(dimensions = 1) Object[] preAppliedArguments;
private final @CompilationFinal(dimensions = 1) Object[] oversaturatedArguments; private final @CompilationFinal(dimensions = 1) Object[] oversaturatedArguments;
/** /**

View File

@ -6,6 +6,7 @@ import org.enso.compiler.pass.analyse._
import org.enso.compiler.pass.desugar._ import org.enso.compiler.pass.desugar._
import org.enso.compiler.pass.lint.{ import org.enso.compiler.pass.lint.{
ModuleNameConflicts, ModuleNameConflicts,
NoSelfInStatic,
ShadowedPatternFields, ShadowedPatternFields,
UnusedBindings UnusedBindings
} }
@ -87,6 +88,7 @@ class Passes(
DataflowAnalysis, DataflowAnalysis,
CachePreferenceAnalysis, CachePreferenceAnalysis,
UnusedBindings, UnusedBindings,
NoSelfInStatic,
GenericAnnotations GenericAnnotations
) )
) )

View File

@ -77,7 +77,8 @@ trait IRPass extends ProcessingPass {
* @return the result of updating metadata in `copyOfIr` globally using * @return the result of updating metadata in `copyOfIr` globally using
* information from `sourceIr` * information from `sourceIr`
*/ */
def updateMetadataInDuplicate[T <: IR](sourceIr: T, copyOfIr: T): T def updateMetadataInDuplicate[T <: IR](@unused sourceIr: T, copyOfIr: T): T =
copyOfIr
} }
object IRPass { object IRPass {

View File

@ -50,11 +50,6 @@ case object AmbiguousImportsAnalysis extends IRPass {
inlineContext: InlineContext inlineContext: InlineContext
): IR.Expression = ir ): IR.Expression = ir
/** @inheritdoc
*/
override def updateMetadataInDuplicate[T <: IR](sourceIr: T, copyOfIr: T): T =
copyOfIr
/** @inheritdoc /** @inheritdoc
*/ */
override def runModule( override def runModule(

View File

@ -41,9 +41,6 @@ object AutomaticParallelism extends IRPass {
DataflowAnalysis DataflowAnalysis
) )
override def updateMetadataInDuplicate[T <: IR](sourceIr: T, copyOfIr: T): T =
copyOfIr
/** An assignment of a line to a given thread. /** An assignment of a line to a given thread.
*/ */
sealed private trait BlockAssignment sealed private trait BlockAssignment

View File

@ -17,8 +17,6 @@ import org.enso.compiler.pass.resolve.{
Patterns Patterns
} }
import scala.annotation.unused
/** Recognizes all defined bindings in the current module and constructs /** Recognizes all defined bindings in the current module and constructs
* a mapping data structure that can later be used for symbol resolution. * a mapping data structure that can later be used for symbol resolution.
*/ */
@ -114,10 +112,4 @@ case object BindingAnalysis extends IRPass {
ir: IR.Expression, ir: IR.Expression,
inlineContext: InlineContext inlineContext: InlineContext
): IR.Expression = ir ): IR.Expression = ir
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
} }

View File

@ -9,7 +9,6 @@ import org.enso.compiler.pass.IRPass
import org.enso.compiler.pass.desugar._ import org.enso.compiler.pass.desugar._
import java.util import java.util
import scala.annotation.unused
import scala.collection.mutable import scala.collection.mutable
import scala.jdk.CollectionConverters._ import scala.jdk.CollectionConverters._
@ -67,12 +66,6 @@ case object CachePreferenceAnalysis extends IRPass {
): IR.Expression = ): IR.Expression =
analyseExpression(ir, WeightInfo()) analyseExpression(ir, WeightInfo())
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
// === Pass Internals ======================================================= // === Pass Internals =======================================================
/** Performas preference analysis on a module definition. /** Performas preference analysis on a module definition.

View File

@ -7,8 +7,6 @@ import org.enso.compiler.pass.IRPass
import org.enso.compiler.pass.optimise.LambdaConsolidate import org.enso.compiler.pass.optimise.LambdaConsolidate
import org.enso.compiler.pass.resolve.OverloadsResolution import org.enso.compiler.pass.resolve.OverloadsResolution
import scala.annotation.unused
/** This pass implements demand analysis for Enso. /** This pass implements demand analysis for Enso.
* *
* Demand analysis is the process of determining _when_ a suspended term needs * Demand analysis is the process of determining _when_ a suspended term needs
@ -76,12 +74,6 @@ case object DemandAnalysis extends IRPass {
isInsideCallArgument = false isInsideCallArgument = false
) )
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
/** Performs demand analysis on an arbitrary program expression. /** Performs demand analysis on an arbitrary program expression.
* *
* @param expression the expression to perform demand analysis on * @param expression the expression to perform demand analysis on

View File

@ -6,8 +6,6 @@ import org.enso.compiler.core.ir.MetadataStorage._
import org.enso.compiler.pass.IRPass import org.enso.compiler.pass.IRPass
import org.enso.compiler.pass.resolve.TypeSignatures import org.enso.compiler.pass.resolve.TypeSignatures
import scala.annotation.unused
/** A pass that traverses the given root IR and accumulates all the encountered /** A pass that traverses the given root IR and accumulates all the encountered
* diagnostic nodes in the root. * diagnostic nodes in the root.
* *
@ -50,12 +48,6 @@ case object GatherDiagnostics extends IRPass {
inlineContext: InlineContext inlineContext: InlineContext
): IR.Expression = ir.updateMetadata(this -->> gatherMetadata(ir)) ): IR.Expression = ir.updateMetadata(this -->> gatherMetadata(ir))
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
/** Gathers diagnostics from all children of an IR node. /** Gathers diagnostics from all children of an IR node.
* *
* @param ir the node to gather diagnostics from * @param ir the node to gather diagnostics from

View File

@ -6,8 +6,6 @@ import org.enso.compiler.data.BindingsMap
import org.enso.compiler.pass.IRPass import org.enso.compiler.pass.IRPass
import org.enso.compiler.pass.desugar.GenerateMethodBodies import org.enso.compiler.pass.desugar.GenerateMethodBodies
import scala.annotation.unused
/** Performs analysis of `from ... import sym1, sym2, ...` statements - checks that all /** Performs analysis of `from ... import sym1, sym2, ...` statements - checks that all
* the symbols imported from the module can be resolved, i.e., exists. * the symbols imported from the module can be resolved, i.e., exists.
* In case of unresolved symbols, replaces the IR import with [[IR.Error.ImportExport]]. * In case of unresolved symbols, replaces the IR import with [[IR.Error.ImportExport]].
@ -119,10 +117,4 @@ case object ImportSymbolAnalysis extends IRPass {
): Boolean = { ): Boolean = {
importTarget.findExportedSymbolsFor(symbol.name).nonEmpty importTarget.findExportedSymbolsFor(symbol.name).nonEmpty
} }
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
} }

View File

@ -9,8 +9,6 @@ import org.enso.compiler.pass.IRPass
import org.enso.compiler.pass.desugar._ import org.enso.compiler.pass.desugar._
import org.enso.compiler.pass.resolve.{ExpressionAnnotations, GlobalNames} import org.enso.compiler.pass.resolve.{ExpressionAnnotations, GlobalNames}
import scala.annotation.unused
/** This pass performs tail call analysis on the Enso IR. /** This pass performs tail call analysis on the Enso IR.
* *
* It is responsible for marking every single expression with whether it is in * It is responsible for marking every single expression with whether it is in
@ -76,12 +74,6 @@ case object TailCall extends IRPass {
) )
) )
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
/** Performs tail call analysis on a top-level definition in a module. /** Performs tail call analysis on a top-level definition in a module.
* *
* @param definition the top-level definition to analyse * @param definition the top-level definition to analyse

View File

@ -95,12 +95,6 @@ case object ComplexType extends IRPass {
inlineContext: InlineContext inlineContext: InlineContext
): IR.Expression = ir ): IR.Expression = ir
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
sourceIr: T,
copyOfIr: T
): T = copyOfIr
// === Pass Internals ======================================================= // === Pass Internals =======================================================
/** Desugars a complex type definition into a series of top-level definitions. /** Desugars a complex type definition into a series of top-level definitions.

View File

@ -78,12 +78,6 @@ case object FunctionBinding extends IRPass {
inlineContext: InlineContext inlineContext: InlineContext
): IR.Expression = desugarExpression(ir) ): IR.Expression = desugarExpression(ir)
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
sourceIr: T,
copyOfIr: T
): T = copyOfIr
// === Pass Internals ======================================================= // === Pass Internals =======================================================
/** Performs desugaring on an arbitrary Enso expression. /** Performs desugaring on an arbitrary Enso expression.

View File

@ -15,7 +15,7 @@ import org.enso.compiler.pass.optimise.LambdaConsolidate
import org.enso.interpreter.epb.EpbParser import org.enso.interpreter.epb.EpbParser
import org.enso.interpreter.epb.EpbParser.ForeignLanguage import org.enso.interpreter.epb.EpbParser.ForeignLanguage
import scala.annotation.{tailrec, unused} import scala.annotation.{tailrec}
/** This pass is responsible for ensuring that method bodies are in the correct /** This pass is responsible for ensuring that method bodies are in the correct
* format. * format.
@ -274,12 +274,6 @@ case object GenerateMethodBodies extends IRPass {
inlineContext: InlineContext inlineContext: InlineContext
): IR.Expression = ir ): IR.Expression = ir
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
/** Collects the argument list of a chain of function definitions. /** Collects the argument list of a chain of function definitions.
* *
* @param function the function to collect args for * @param function the function to collect args for

View File

@ -4,8 +4,6 @@ import org.enso.compiler.context.{InlineContext, ModuleContext}
import org.enso.compiler.core.IR import org.enso.compiler.core.IR
import org.enso.compiler.pass.IRPass import org.enso.compiler.pass.IRPass
import scala.annotation.unused
/** Desugars shorthand syntaxes in import and export statements. /** Desugars shorthand syntaxes in import and export statements.
*/ */
case object Imports extends IRPass { case object Imports extends IRPass {
@ -107,12 +105,6 @@ case object Imports extends IRPass {
inlineContext: InlineContext inlineContext: InlineContext
): IR.Expression = ir ): IR.Expression = ir
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
private def computeRename( private def computeRename(
originalRename: Option[IR.Name.Literal], originalRename: Option[IR.Name.Literal],
onlyNamesOrAll: Boolean, onlyNamesOrAll: Boolean,

View File

@ -21,8 +21,6 @@ import org.enso.compiler.pass.resolve.{
OverloadsResolution OverloadsResolution
} }
import scala.annotation.unused
/** This pass translates `_` arguments at application sites to lambda functions. /** This pass translates `_` arguments at application sites to lambda functions.
* *
* This pass has no configuration. * This pass has no configuration.
@ -106,12 +104,6 @@ case object LambdaShorthandToLambda extends IRPass {
desugarExpression(ir, freshNameSupply) desugarExpression(ir, freshNameSupply)
} }
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
// === Pass Internals ======================================================= // === Pass Internals =======================================================
/** Performs lambda shorthand desugaring on an arbitrary expression. /** Performs lambda shorthand desugaring on an arbitrary expression.

View File

@ -126,12 +126,6 @@ case object NestedPatternMatch extends IRPass {
} }
} }
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
// === Pass Internals ======================================================= // === Pass Internals =======================================================
/** Desugars an arbitrary expression. /** Desugars an arbitrary expression.

View File

@ -9,8 +9,6 @@ import org.enso.compiler.pass.analyse.{
DemandAnalysis DemandAnalysis
} }
import scala.annotation.unused
/** This pass converts usages of operators to calls to standard functions. /** This pass converts usages of operators to calls to standard functions.
* *
* This pass requires the context to provide: * This pass requires the context to provide:
@ -87,10 +85,4 @@ case object OperatorToFunction extends IRPass {
diag diag
) )
} }
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
} }

View File

@ -8,8 +8,6 @@ import org.enso.compiler.pass.IRPass
import org.enso.compiler.pass.analyse._ import org.enso.compiler.pass.analyse._
import org.enso.compiler.pass.lint.UnusedBindings import org.enso.compiler.pass.lint.UnusedBindings
import scala.annotation.unused
/** This pass converts operator sections to applications of binary operators. /** This pass converts operator sections to applications of binary operators.
* *
* This pass has no configuration. * This pass has no configuration.
@ -80,12 +78,6 @@ case object SectionsToBinOp extends IRPass {
} }
} }
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
/** Desugars operator sections to fully-saturated applications of operators. /** Desugars operator sections to fully-saturated applications of operators.
* *
* For a left sections it will generate a partially-applied function. For * For a left sections it will generate a partially-applied function. For

View File

@ -5,8 +5,6 @@ import org.enso.compiler.core.IR
import org.enso.compiler.pass.IRPass import org.enso.compiler.pass.IRPass
import org.enso.compiler.pass.desugar.ComplexType import org.enso.compiler.pass.desugar.ComplexType
import scala.annotation.unused
/** Generates warnings about potential name conflicts between types and synthetic modules /** Generates warnings about potential name conflicts between types and synthetic modules
*/ */
case object ModuleNameConflicts extends IRPass { case object ModuleNameConflicts extends IRPass {
@ -73,12 +71,6 @@ case object ModuleNameConflicts extends IRPass {
): IR.Expression = ): IR.Expression =
ir ir
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
// === Pass Internals ======================================================= // === Pass Internals =======================================================
/** Lints a binding /** Lints a binding

View File

@ -0,0 +1,103 @@
package org.enso.compiler.pass.lint
import org.enso.compiler.context.{InlineContext, ModuleContext}
import org.enso.compiler.core.{CompilerError, IR}
import org.enso.compiler.pass.IRPass
import org.enso.compiler.pass.desugar.GenerateMethodBodies
/** This linting pass ensures that `self` argument is not used in static methods.
*
* This pass requires the context to provide:
* - Nothing
*/
object NoSelfInStatic extends IRPass {
override type Metadata = IRPass.Metadata.Empty
override type Config = IRPass.Configuration.Default
override val precursorPasses: Seq[IRPass] =
Seq(GenerateMethodBodies)
override val invalidatedPasses: Seq[IRPass] = List()
override def runModule(
ir: IR.Module,
moduleContext: ModuleContext
): IR.Module = {
ir.copy(
bindings = ir.bindings.map {
case method: IR.Module.Scope.Definition.Method.Explicit
if isStaticMethod(method) =>
method.copy(
body = method.body.transformExpressions(transformSelfToError)
)
case method: IR.Module.Scope.Definition.Method.Binding =>
throw new CompilerError(
s"unexpected Method.Binding $method present in pass NoSelfInStatic"
)
case binding => binding
}
)
}
private def transformSelfToError
: PartialFunction[IR.Expression, IR.Expression] = {
case IR.Name.Self(location, false, passData, diagnostics) =>
IR.Error.Syntax(
location.get,
IR.Error.Syntax.InvalidSelfArgUsage,
passData,
diagnostics
)
}
/** A method is static if it is either not defined within a type, or if it does not
* contain a non-synthetic `self` argument.
* @param method
* @return
*/
private def isStaticMethod(
method: IR.Module.Scope.Definition.Method
): Boolean = {
def findSelfArgument(
arguments: List[IR.DefinitionArgument]
): Option[IR.DefinitionArgument] = {
arguments.collectFirst {
case arg @ IR.DefinitionArgument.Specified(
IR.Name.Self(_, false, _, _),
_,
_,
_,
_,
_,
_
) =>
arg
}
}
method.typeName match {
case Some(_) =>
method.body match {
case IR.Function.Lambda(
arguments,
_,
_,
_,
_,
_
) =>
findSelfArgument(arguments).isEmpty
case body =>
throw new CompilerError(
s"Method body is not a lambda: $body - should have been transformed to lambda by GenerateMethodBodies pass"
)
}
case None => true
}
}
override def runExpression(
ir: IR.Expression,
inlineContext: InlineContext
): IR.Expression = ir
}

View File

@ -76,12 +76,6 @@ case object ShadowedPatternFields extends IRPass {
} }
} }
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
// === Pass Internals ======================================================= // === Pass Internals =======================================================
/** Lints for shadowed pattern variables on an arbitrary expression. /** Lints for shadowed pattern variables on an arbitrary expression.

View File

@ -10,8 +10,6 @@ import org.enso.compiler.pass.desugar._
import org.enso.compiler.pass.optimise.LambdaConsolidate import org.enso.compiler.pass.optimise.LambdaConsolidate
import org.enso.compiler.pass.resolve.{ExpressionAnnotations, IgnoredBindings} import org.enso.compiler.pass.resolve.{ExpressionAnnotations, IgnoredBindings}
import scala.annotation.unused
/** This pass performs linting for unused names, generating warnings if it finds /** This pass performs linting for unused names, generating warnings if it finds
* any. * any.
* *
@ -77,12 +75,6 @@ case object UnusedBindings extends IRPass {
} }
} else ir } else ir
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
// === Pass Internals ======================================================= // === Pass Internals =======================================================
/** Lints a binding. /** Lints a binding.

View File

@ -11,8 +11,6 @@ import org.enso.interpreter.node.{ExpressionNode => RuntimeExpression}
import org.enso.interpreter.runtime.callable.argument.CallArgument import org.enso.interpreter.runtime.callable.argument.CallArgument
import org.enso.interpreter.runtime.scope.{LocalScope, ModuleScope} import org.enso.interpreter.runtime.scope.{LocalScope, ModuleScope}
import scala.annotation.unused
/** This optimisation pass recognises fully-saturated applications of known /** This optimisation pass recognises fully-saturated applications of known
* functions and writes analysis data that allows optimisation of them to * functions and writes analysis data that allows optimisation of them to
* specific nodes at codegen time. * specific nodes at codegen time.
@ -180,12 +178,6 @@ case object ApplicationSaturation extends IRPass {
} }
} }
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
/** Configuration for this pass /** Configuration for this pass
* *
* @param knownFunctions the mapping of known functions * @param knownFunctions the mapping of known functions

View File

@ -15,8 +15,6 @@ import org.enso.compiler.pass.desugar._
import org.enso.compiler.pass.resolve.IgnoredBindings import org.enso.compiler.pass.resolve.IgnoredBindings
import org.enso.syntax.text.Location import org.enso.syntax.text.Location
import scala.annotation.unused
/** This pass consolidates chains of lambdas into multi-argument lambdas /** This pass consolidates chains of lambdas into multi-argument lambdas
* internally. * internally.
* *
@ -111,12 +109,6 @@ case object LambdaConsolidate extends IRPass {
} }
} }
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
/** Collapses chained lambdas for a function definition where possible. /** Collapses chained lambdas for a function definition where possible.
* *
* @param function the function definition to optimise * @param function the function definition to optimise

View File

@ -89,12 +89,6 @@ case object UnreachableMatchBranches extends IRPass {
} }
} }
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
// === Pass Internals ======================================================= // === Pass Internals =======================================================
/** Optimizes an expression by removing unreachable branches in case /** Optimizes an expression by removing unreachable branches in case

View File

@ -57,10 +57,6 @@ case object DocumentationComments extends IRPass {
): IR.Expression = resolveExpression(ir) ): IR.Expression = resolveExpression(ir)
/** @inheritdoc */ /** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
sourceIr: T,
copyOfIr: T
): T = copyOfIr
// === Pass Internals ======================================================= // === Pass Internals =======================================================

View File

@ -58,10 +58,6 @@ case object ExpressionAnnotations extends IRPass {
} }
/** @inheritdoc */ /** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
sourceIr: T,
copyOfIr: T
): T = copyOfIr
private def doExpression( private def doExpression(
ir: IR.Expression ir: IR.Expression

View File

@ -18,9 +18,6 @@ object FullyAppliedFunctionUses extends IRPass {
Seq(GlobalNames) Seq(GlobalNames)
override val invalidatedPasses: Seq[IRPass] = Seq() override val invalidatedPasses: Seq[IRPass] = Seq()
override def updateMetadataInDuplicate[T <: IR](sourceIr: T, copyOfIr: T): T =
copyOfIr
/** Executes the pass on the provided `ir`, and returns a possibly transformed /** Executes the pass on the provided `ir`, and returns a possibly transformed
* or annotated version of `ir`. * or annotated version of `ir`.
* *

View File

@ -366,25 +366,6 @@ case object FullyQualifiedNames extends IRPass {
.getOrElse(Right(None)) .getOrElse(Right(None))
} }
/** Updates the metadata in a copy of the IR when updating that metadata
* requires global state.
*
* This is usually the case in the presence of structures that are shared
* throughout the IR, and need to maintain that sharing for correctness. This
* must be called with `copyOfIr` as the result of an `ir.duplicate` call.
*
* Additionally this method _must not_ alter the structure of the IR. It
* should only update its metadata.
*
* @param sourceIr the IR being copied
* @param copyOfIr a duplicate of `sourceIr`
* @tparam T the concrete [[IR]] type
* @return the result of updating metadata in `copyOfIr` globally using
* information from `sourceIr`
*/
override def updateMetadataInDuplicate[T <: IR](sourceIr: T, copyOfIr: T): T =
copyOfIr
private def isLocalVar(name: IR.Name.Literal): Boolean = { private def isLocalVar(name: IR.Name.Literal): Boolean = {
val aliasInfo = name val aliasInfo = name
.unsafeGetMetadata( .unsafeGetMetadata(

View File

@ -82,8 +82,5 @@ case object GenericAnnotations extends IRPass {
): IR.Expression = ir ): IR.Expression = ir
/** @inheritdoc */ /** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
sourceIr: T,
copyOfIr: T
): T = copyOfIr
} }

View File

@ -93,10 +93,6 @@ case object GlobalNames extends IRPass {
} }
/** @inheritdoc */ /** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
sourceIr: T,
copyOfIr: T
): T = copyOfIr
private def processModuleDefinition( private def processModuleDefinition(
definition: IR.Module.Scope.Definition, definition: IR.Module.Scope.Definition,

View File

@ -19,8 +19,6 @@ import org.enso.compiler.pass.desugar.{
NestedPatternMatch NestedPatternMatch
} }
import scala.annotation.unused
/** This pass translates ignored bindings (of the form `_`) into fresh names /** This pass translates ignored bindings (of the form `_`) into fresh names
* internally, as well as marks all bindings as whether or not they were * internally, as well as marks all bindings as whether or not they were
* ignored. * ignored.
@ -95,12 +93,6 @@ case object IgnoredBindings extends IRPass {
} else ir } else ir
} }
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
private def setNotIgnored[T <: IR](ir: T): T = { private def setNotIgnored[T <: IR](ir: T): T = {
if (ir.getMetadata(this).isEmpty) { if (ir.getMetadata(this).isEmpty) {
ir.updateMetadata(this -->> State.NotIgnored) ir.updateMetadata(this -->> State.NotIgnored)

View File

@ -20,9 +20,6 @@ object MethodCalls extends IRPass {
Seq(BindingAnalysis, GlobalNames) Seq(BindingAnalysis, GlobalNames)
override val invalidatedPasses: Seq[IRPass] = Seq() override val invalidatedPasses: Seq[IRPass] = Seq()
override def updateMetadataInDuplicate[T <: IR](sourceIr: T, copyOfIr: T): T =
copyOfIr
/** Executes the pass on the provided `ir`, and returns a possibly transformed /** Executes the pass on the provided `ir`, and returns a possibly transformed
* or annotated version of `ir`. * or annotated version of `ir`.
* *

View File

@ -14,8 +14,6 @@ import org.enso.compiler.pass.desugar.{
GenerateMethodBodies GenerateMethodBodies
} }
import scala.annotation.unused
/** Resolves the correct `self` argument type for method definitions and stores /** Resolves the correct `self` argument type for method definitions and stores
* the resolution in the method's metadata. * the resolution in the method's metadata.
*/ */
@ -198,9 +196,4 @@ case object MethodDefinitions extends IRPass {
inlineContext: InlineContext inlineContext: InlineContext
): IR.Expression = ir ): IR.Expression = ir
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
} }

View File

@ -106,10 +106,6 @@ case object ModuleAnnotations extends IRPass {
): IR.Expression = ir ): IR.Expression = ir
/** @inheritdoc */ /** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
sourceIr: T,
copyOfIr: T
): T = copyOfIr
/** A container for annotations on an IR construct. /** A container for annotations on an IR construct.
* *

View File

@ -154,8 +154,5 @@ case object OverloadsResolution extends IRPass {
): IR.Expression = ir ): IR.Expression = ir
/** @inheritdoc */ /** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
sourceIr: T,
copyOfIr: T
): T = copyOfIr
} }

View File

@ -9,8 +9,6 @@ import org.enso.compiler.pass.IRPass
import org.enso.compiler.pass.analyse.{AliasAnalysis, BindingAnalysis} import org.enso.compiler.pass.analyse.{AliasAnalysis, BindingAnalysis}
import org.enso.compiler.pass.desugar.{GenerateMethodBodies, NestedPatternMatch} import org.enso.compiler.pass.desugar.{GenerateMethodBodies, NestedPatternMatch}
import scala.annotation.unused
/** Resolves constructors in pattern matches and validates their arity. /** Resolves constructors in pattern matches and validates their arity.
*/ */
object Patterns extends IRPass { object Patterns extends IRPass {
@ -62,12 +60,6 @@ object Patterns extends IRPass {
doExpression(ir, bindings, None) doExpression(ir, bindings, None)
} }
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
private def doDefinition( private def doDefinition(
ir: IR.Module.Scope.Definition, ir: IR.Module.Scope.Definition,
bindings: BindingsMap bindings: BindingsMap

View File

@ -87,10 +87,6 @@ case object SuspendedArguments extends IRPass {
): IR.Expression = resolveExpression(ir) ): IR.Expression = resolveExpression(ir)
/** @inheritdoc */ /** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
sourceIr: T,
copyOfIr: T
): T = copyOfIr
// === Pass Internals ======================================================= // === Pass Internals =======================================================

View File

@ -75,12 +75,6 @@ case object TypeFunctions extends IRPass {
resolveExpression(a) resolveExpression(a)
} }
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
// === Pass Internals ======================================================= // === Pass Internals =======================================================
/** The names of the known typing functions. */ /** The names of the known typing functions. */

View File

@ -8,8 +8,6 @@ import org.enso.compiler.data.BindingsMap.{Resolution, ResolvedModule}
import org.enso.compiler.pass.IRPass import org.enso.compiler.pass.IRPass
import org.enso.compiler.pass.analyse.BindingAnalysis import org.enso.compiler.pass.analyse.BindingAnalysis
import scala.annotation.unused
/** Resolves and desugars referent name occurrences in type positions. /** Resolves and desugars referent name occurrences in type positions.
*/ */
case object TypeNames extends IRPass { case object TypeNames extends IRPass {
@ -152,9 +150,4 @@ case object TypeNames extends IRPass {
ir ir
} }
/** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
@unused sourceIr: T,
copyOfIr: T
): T = copyOfIr
} }

View File

@ -63,10 +63,6 @@ case object TypeSignatures extends IRPass {
): IR.Expression = resolveExpression(ir) ): IR.Expression = resolveExpression(ir)
/** @inheritdoc */ /** @inheritdoc */
override def updateMetadataInDuplicate[T <: IR](
sourceIr: T,
copyOfIr: T
): T = copyOfIr
// === Pass Internals ======================================================= // === Pass Internals =======================================================

View File

@ -35,11 +35,6 @@ class PassesTest extends CompilerTest {
ir: IR.Expression, ir: IR.Expression,
inlineContext: InlineContext inlineContext: InlineContext
): IR.Expression = ir ): IR.Expression = ir
override def updateMetadataInDuplicate[T <: IR](
sourceIr: T,
copyOfIr: T
): T = copyOfIr
} }
// === The Tests ============================================================ // === The Tests ============================================================

View File

@ -30,11 +30,6 @@ class MetadataStorageTest extends CompilerTest {
inlineContext: InlineContext inlineContext: InlineContext
): IR.Expression = ir ): IR.Expression = ir
override def updateMetadataInDuplicate[T <: IR](
sourceIr: T,
copyOfIr: T
): T = copyOfIr
sealed case class Metadata1() extends IRPass.IRMetadata { sealed case class Metadata1() extends IRPass.IRMetadata {
override val metadataName: String = "TestPass1.Metadata1" override val metadataName: String = "TestPass1.Metadata1"
@ -67,11 +62,6 @@ class MetadataStorageTest extends CompilerTest {
inlineContext: InlineContext inlineContext: InlineContext
): IR.Expression = ir ): IR.Expression = ir
override def updateMetadataInDuplicate[T <: IR](
sourceIr: T,
copyOfIr: T
): T = copyOfIr
sealed case class Metadata2() extends IRPass.IRMetadata { sealed case class Metadata2() extends IRPass.IRMetadata {
override val metadataName: String = "TestPass2.Metadata2" override val metadataName: String = "TestPass2.Metadata2"

View File

@ -28,11 +28,6 @@ class PassConfigurationTest extends CompilerTest {
inlineContext: InlineContext inlineContext: InlineContext
): IR.Expression = ir ): IR.Expression = ir
override def updateMetadataInDuplicate[T <: IR](
sourceIr: T,
copyOfIr: T
): T = copyOfIr
sealed case class Configuration1() extends IRPass.Configuration { sealed case class Configuration1() extends IRPass.Configuration {
override var shouldWriteToContext: Boolean = false override var shouldWriteToContext: Boolean = false
} }
@ -55,11 +50,6 @@ class PassConfigurationTest extends CompilerTest {
inlineContext: InlineContext inlineContext: InlineContext
): IR.Expression = ir ): IR.Expression = ir
override def updateMetadataInDuplicate[T <: IR](
sourceIr: T,
copyOfIr: T
): T = copyOfIr
sealed case class Configuration2() extends IRPass.Configuration { sealed case class Configuration2() extends IRPass.Configuration {
override var shouldWriteToContext: Boolean = true override var shouldWriteToContext: Boolean = true
} }

View File

@ -0,0 +1,132 @@
package org.enso.compiler.test.pass.lint
import org.enso.compiler.Passes
import org.enso.compiler.context.{FreshNameSupply, ModuleContext}
import org.enso.compiler.core.IR
import org.enso.compiler.pass.{PassConfiguration, PassGroup, PassManager}
import org.enso.compiler.pass.lint.NoSelfInStatic
import org.enso.compiler.test.CompilerTest
class NoSelfInStaticTests extends CompilerTest {
val passes = new Passes(defaultConfig)
val precursorPasses: PassGroup = passes.getPrecursors(NoSelfInStatic).get
val passConfiguration: PassConfiguration = PassConfiguration()
implicit val passManager: PassManager =
new PassManager(List(precursorPasses), passConfiguration)
/** Adds an extension method for running linting on the input IR.
*
* @param ir the IR to lint
*/
implicit class LintModule(ir: IR.Module) {
/** Runs unused name linting on [[ir]].
*
* @param moduleContext the inline context in which the desugaring takes
* place
* @return [[ir]], with all unused names linted
*/
def lint(implicit moduleContext: ModuleContext): IR.Module = {
NoSelfInStatic.runModule(ir, moduleContext)
}
}
/** Makes a module context.
*
* @return a new inline context
*/
def mkModuleContext: ModuleContext = {
buildModuleContext(freshNameSupply = Some(new FreshNameSupply))
}
// === The Tests ============================================================
"No self argument in static methods linting" should {
"generate an error when self argument is used in a type static method" in {
implicit val ctx: ModuleContext = mkModuleContext
val ir =
"""
|type Foo
| Value x
| bar = self.x + self.x
|""".stripMargin.preprocessModule.lint
val errs = ir.bindings.flatMap(_.preorder).collect {
case err @ IR.Error
.Syntax(_, IR.Error.Syntax.InvalidSelfArgUsage, _, _) =>
err
}
errs should have size 2
}
"generate an error when self argument is used in a module static method" in {
implicit val ctx: ModuleContext = mkModuleContext
val ir =
"""
|static_method x y = x + y + self.data
|""".stripMargin.preprocessModule.lint
val errs = ir.bindings.flatMap(_.preorder).collect {
case err @ IR.Error
.Syntax(_, IR.Error.Syntax.InvalidSelfArgUsage, _, _) =>
err
}
errs should have size 1
}
"generate an error when self argument is used in a nested static method" in {
implicit val ctx: ModuleContext = mkModuleContext
val ir =
"""
|static_method x y =
| nested_method z =
| tmp = z + x + y
| self.data + tmp
| nested_method (x + y)
|""".stripMargin.preprocessModule.lint
val errs = ir.bindings.flatMap(_.preorder).collect {
case err @ IR.Error
.Syntax(_, IR.Error.Syntax.InvalidSelfArgUsage, _, _) =>
err
}
errs should have size 1
}
"succeed when self argument is used in a nested instance method" in {
implicit val ctx: ModuleContext = mkModuleContext
val ir =
"""
|type My_Type
| Value value
|
| instance_method self =
| nested_method x = self.value + 1
| nested_method 42
|""".stripMargin.preprocessModule.lint
val errs = ir.bindings.flatMap(_.preorder).collect {
case err @ IR.Error
.Syntax(_, IR.Error.Syntax.InvalidSelfArgUsage, _, _) =>
err
}
errs should be(empty)
}
"generate an error when self argument is used in a static extension method" in {
implicit val ctx: ModuleContext = mkModuleContext
val ir =
"""
|type My_Type
| Value value
|
|My_Type.extension_method = self.value + 1
|""".stripMargin.preprocessModule.lint
val errs = ir.bindings.flatMap(_.preorder).collect {
case err @ IR.Error
.Syntax(_, IR.Error.Syntax.InvalidSelfArgUsage, _, _) =>
err
}
errs should have size 1
}
}
}

View File

@ -4,10 +4,10 @@ from Standard.Test import Test, Test_Suite
import Standard.Test.Extensions import Standard.Test.Extensions
polyglot java import java.lang.Double polyglot java import java.lang.Double
polyglot java import java.lang.Integer polyglot java import java.lang.Integer as Java_Integer
polyglot java import java.lang.String polyglot java import java.lang.String
polyglot java import java.time.LocalDate polyglot java import java.time.LocalDate
polyglot java import java.util.function.Function polyglot java import java.util.function.Function as Java_Function
polyglot java import org.enso.base_test_helpers.IntHolder polyglot java import org.enso.base_test_helpers.IntHolder
spec = Test.group "Polyglot" <| spec = Test.group "Polyglot" <|
@ -23,7 +23,7 @@ spec = Test.group "Polyglot" <|
Polyglot.new String ["42"].to_array . should_equal "42" Polyglot.new String ["42"].to_array . should_equal "42"
Test.specify "use Integer created by constructor" <| Test.specify "use Integer created by constructor" <|
Polyglot.new Integer [42] . should_equal 42 Polyglot.new Java_Integer [42] . should_equal 42
Test.specify "use Double created by constructor" <| Test.specify "use Double created by constructor" <|
Polyglot.new Double [42] . should_equal 42 Polyglot.new Double [42] . should_equal 42
@ -35,7 +35,7 @@ spec = Test.group "Polyglot" <|
js_meaning.meaning . should_equal 42 js_meaning.meaning . should_equal 42
Test.specify "use Integer obtained from a call" <| Test.specify "use Integer obtained from a call" <|
Integer.parseInt "42" . should_equal 42 Java_Integer.parseInt "42" . should_equal 42
Test.specify "use Integer obtained from a read" <| Test.specify "use Integer obtained from a read" <|
hold = IntHolder.new (6 * 7) hold = IntHolder.new (6 * 7)
@ -43,7 +43,7 @@ spec = Test.group "Polyglot" <|
hold.boxed . should_equal 42 hold.boxed . should_equal 42
Test.specify "should be able to execute a polyglot function object along with corresponding arguments" <| Test.specify "should be able to execute a polyglot function object along with corresponding arguments" <|
fun = Function.identity fun = Java_Function.identity
Polyglot.execute fun ["42"] . should_equal "42" Polyglot.execute fun ["42"] . should_equal "42"
Polyglot.execute fun ["42"].to_array . should_equal "42" Polyglot.execute fun ["42"].to_array . should_equal "42"

View File

@ -2,17 +2,12 @@ from Standard.Test import Test, Test_Suite
import Standard.Test.Extensions import Standard.Test.Extensions
type Generator type Generator
Value h t Value n ~next
natural = natural =
gen ~n = if (n >= 10) then self else Generator.Value n (@Tail_Call gen n+1) gen n = Generator.Value n (gen n+1)
gen 2 gen 2
Generator.n self = case self of
Generator.Value n _ -> n
Generator.next self = case self of
Generator.Value _ n -> n
spec = Test.group "Lazy Generator" <| spec = Test.group "Lazy Generator" <|
Test.specify "Generates four numbers properly" <| Test.specify "Generates four numbers properly" <|
two = natural two = natural

View File

@ -6,7 +6,7 @@ import Standard.Test.Extensions
from project.Semantic.Default_Args_Spec.Box import all from project.Semantic.Default_Args_Spec.Box import all
type Box type Box
Foo (v : Bool = True) Foo (v : Boolean = True)
type Bar (a : Integer = 1) (b : Box = (Foo False)) (c : Boolean = b.v) type Bar (a : Integer = 1) (b : Box = (Foo False)) (c : Boolean = b.v)