mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 23:22:14 +03:00
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:
parent
b4d0a40c7d
commit
60ef7e0ba3
@ -1117,7 +1117,7 @@ type Number_Parse_Error
|
||||
## PRIVATE
|
||||
Pretty print the syntax error.
|
||||
to_display_text : Text
|
||||
to_display_text =
|
||||
to_display_text self =
|
||||
"Could not parse " + self.text.to_text + " as a double."
|
||||
|
||||
## PRIVATE
|
||||
|
@ -7868,6 +7868,11 @@ object IR {
|
||||
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 {
|
||||
override def explanation: String = "Unrecognized token"
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.enso.interpreter.bench.benchmarks.semantic;
|
||||
|
||||
import org.enso.polyglot.MethodNames.Module;
|
||||
import org.graalvm.polyglot.Context;
|
||||
import org.graalvm.polyglot.Value;
|
||||
import org.openjdk.jmh.annotations.*;
|
||||
@ -22,7 +23,6 @@ public class TypePatternBenchmarks {
|
||||
private Value patternMatch;
|
||||
private Value avg;
|
||||
private Value vec;
|
||||
private Value self;
|
||||
|
||||
@Setup
|
||||
public void initializeBenchmark(BenchmarkParams params) throws Exception {
|
||||
@ -43,8 +43,8 @@ public class TypePatternBenchmarks {
|
||||
@Tail_Call sum (acc + arr.at i) i+1
|
||||
(sum 0 0) / arr.length
|
||||
|
||||
avg_pattern self arr pattern =
|
||||
avg (arr.map (pattern self))
|
||||
avg_pattern arr pattern =
|
||||
avg (arr.map (pattern _))
|
||||
|
||||
gen_vec size value =
|
||||
b = Vector.new_builder size
|
||||
@ -65,20 +65,14 @@ public class TypePatternBenchmarks {
|
||||
var src = SrcUtil.source(benchmarkName, code);
|
||||
var module = ctx.eval(src);
|
||||
|
||||
this.self = module.invokeMember("get_associated_type");
|
||||
Function<String,Value> getMethod = (name) -> module.invokeMember("get_method", self, name);
|
||||
Function<String,Value> getMethod = (name) -> module.invokeMember(Module.EVAL_EXPRESSION, name);
|
||||
|
||||
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)) {
|
||||
case "matchOverAny":
|
||||
this.patternMatch = getMethod.apply("match_any");
|
||||
break;
|
||||
case "matchOverDecimal":
|
||||
this.patternMatch = getMethod.apply("match_dec");
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected benchmark: " + params.getBenchmark());
|
||||
case "matchOverAny" -> this.patternMatch = getMethod.apply("match_any");
|
||||
case "matchOverDecimal" -> this.patternMatch = getMethod.apply("match_dec");
|
||||
default -> throw new IllegalStateException("Unexpected benchmark: " + params.getBenchmark());
|
||||
}
|
||||
this.avg = getMethod.apply("avg_pattern");
|
||||
}
|
||||
@ -98,7 +92,7 @@ public class TypePatternBenchmarks {
|
||||
}
|
||||
|
||||
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()) {
|
||||
throw new AssertionError("Shall be a double: " + average);
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ public final class Function implements TruffleObject {
|
||||
private final RootCallTarget callTarget;
|
||||
private final MaterializedFrame scope;
|
||||
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;
|
||||
|
||||
/**
|
||||
|
@ -6,6 +6,7 @@ import org.enso.compiler.pass.analyse._
|
||||
import org.enso.compiler.pass.desugar._
|
||||
import org.enso.compiler.pass.lint.{
|
||||
ModuleNameConflicts,
|
||||
NoSelfInStatic,
|
||||
ShadowedPatternFields,
|
||||
UnusedBindings
|
||||
}
|
||||
@ -87,6 +88,7 @@ class Passes(
|
||||
DataflowAnalysis,
|
||||
CachePreferenceAnalysis,
|
||||
UnusedBindings,
|
||||
NoSelfInStatic,
|
||||
GenericAnnotations
|
||||
)
|
||||
)
|
||||
|
@ -77,7 +77,8 @@ trait IRPass extends ProcessingPass {
|
||||
* @return the result of updating metadata in `copyOfIr` globally using
|
||||
* 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 {
|
||||
|
||||
|
@ -50,11 +50,6 @@ case object AmbiguousImportsAnalysis extends IRPass {
|
||||
inlineContext: InlineContext
|
||||
): IR.Expression = ir
|
||||
|
||||
/** @inheritdoc
|
||||
*/
|
||||
override def updateMetadataInDuplicate[T <: IR](sourceIr: T, copyOfIr: T): T =
|
||||
copyOfIr
|
||||
|
||||
/** @inheritdoc
|
||||
*/
|
||||
override def runModule(
|
||||
|
@ -41,9 +41,6 @@ object AutomaticParallelism extends IRPass {
|
||||
DataflowAnalysis
|
||||
)
|
||||
|
||||
override def updateMetadataInDuplicate[T <: IR](sourceIr: T, copyOfIr: T): T =
|
||||
copyOfIr
|
||||
|
||||
/** An assignment of a line to a given thread.
|
||||
*/
|
||||
sealed private trait BlockAssignment
|
||||
|
@ -17,8 +17,6 @@ import org.enso.compiler.pass.resolve.{
|
||||
Patterns
|
||||
}
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** Recognizes all defined bindings in the current module and constructs
|
||||
* a mapping data structure that can later be used for symbol resolution.
|
||||
*/
|
||||
@ -114,10 +112,4 @@ case object BindingAnalysis extends IRPass {
|
||||
ir: IR.Expression,
|
||||
inlineContext: InlineContext
|
||||
): IR.Expression = ir
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import org.enso.compiler.pass.IRPass
|
||||
import org.enso.compiler.pass.desugar._
|
||||
|
||||
import java.util
|
||||
import scala.annotation.unused
|
||||
import scala.collection.mutable
|
||||
import scala.jdk.CollectionConverters._
|
||||
|
||||
@ -67,12 +66,6 @@ case object CachePreferenceAnalysis extends IRPass {
|
||||
): IR.Expression =
|
||||
analyseExpression(ir, WeightInfo())
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
// === Pass Internals =======================================================
|
||||
|
||||
/** Performas preference analysis on a module definition.
|
||||
|
@ -7,8 +7,6 @@ import org.enso.compiler.pass.IRPass
|
||||
import org.enso.compiler.pass.optimise.LambdaConsolidate
|
||||
import org.enso.compiler.pass.resolve.OverloadsResolution
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** This pass implements demand analysis for Enso.
|
||||
*
|
||||
* Demand analysis is the process of determining _when_ a suspended term needs
|
||||
@ -76,12 +74,6 @@ case object DemandAnalysis extends IRPass {
|
||||
isInsideCallArgument = false
|
||||
)
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
/** Performs demand analysis on an arbitrary program expression.
|
||||
*
|
||||
* @param expression the expression to perform demand analysis on
|
||||
|
@ -6,8 +6,6 @@ import org.enso.compiler.core.ir.MetadataStorage._
|
||||
import org.enso.compiler.pass.IRPass
|
||||
import org.enso.compiler.pass.resolve.TypeSignatures
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** A pass that traverses the given root IR and accumulates all the encountered
|
||||
* diagnostic nodes in the root.
|
||||
*
|
||||
@ -50,12 +48,6 @@ case object GatherDiagnostics extends IRPass {
|
||||
inlineContext: InlineContext
|
||||
): 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.
|
||||
*
|
||||
* @param ir the node to gather diagnostics from
|
||||
|
@ -6,8 +6,6 @@ import org.enso.compiler.data.BindingsMap
|
||||
import org.enso.compiler.pass.IRPass
|
||||
import org.enso.compiler.pass.desugar.GenerateMethodBodies
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** Performs analysis of `from ... import sym1, sym2, ...` statements - checks that all
|
||||
* 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]].
|
||||
@ -119,10 +117,4 @@ case object ImportSymbolAnalysis extends IRPass {
|
||||
): Boolean = {
|
||||
importTarget.findExportedSymbolsFor(symbol.name).nonEmpty
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
}
|
||||
|
@ -9,8 +9,6 @@ import org.enso.compiler.pass.IRPass
|
||||
import org.enso.compiler.pass.desugar._
|
||||
import org.enso.compiler.pass.resolve.{ExpressionAnnotations, GlobalNames}
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** This pass performs tail call analysis on the Enso IR.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @param definition the top-level definition to analyse
|
||||
|
@ -95,12 +95,6 @@ case object ComplexType extends IRPass {
|
||||
inlineContext: InlineContext
|
||||
): IR.Expression = ir
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
// === Pass Internals =======================================================
|
||||
|
||||
/** Desugars a complex type definition into a series of top-level definitions.
|
||||
|
@ -78,12 +78,6 @@ case object FunctionBinding extends IRPass {
|
||||
inlineContext: InlineContext
|
||||
): IR.Expression = desugarExpression(ir)
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
// === Pass Internals =======================================================
|
||||
|
||||
/** Performs desugaring on an arbitrary Enso expression.
|
||||
|
@ -15,7 +15,7 @@ import org.enso.compiler.pass.optimise.LambdaConsolidate
|
||||
import org.enso.interpreter.epb.EpbParser
|
||||
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
|
||||
* format.
|
||||
@ -274,12 +274,6 @@ case object GenerateMethodBodies extends IRPass {
|
||||
inlineContext: InlineContext
|
||||
): 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.
|
||||
*
|
||||
* @param function the function to collect args for
|
||||
|
@ -4,8 +4,6 @@ import org.enso.compiler.context.{InlineContext, ModuleContext}
|
||||
import org.enso.compiler.core.IR
|
||||
import org.enso.compiler.pass.IRPass
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** Desugars shorthand syntaxes in import and export statements.
|
||||
*/
|
||||
case object Imports extends IRPass {
|
||||
@ -107,12 +105,6 @@ case object Imports extends IRPass {
|
||||
inlineContext: InlineContext
|
||||
): IR.Expression = ir
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
private def computeRename(
|
||||
originalRename: Option[IR.Name.Literal],
|
||||
onlyNamesOrAll: Boolean,
|
||||
|
@ -21,8 +21,6 @@ import org.enso.compiler.pass.resolve.{
|
||||
OverloadsResolution
|
||||
}
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** This pass translates `_` arguments at application sites to lambda functions.
|
||||
*
|
||||
* This pass has no configuration.
|
||||
@ -106,12 +104,6 @@ case object LambdaShorthandToLambda extends IRPass {
|
||||
desugarExpression(ir, freshNameSupply)
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
// === Pass Internals =======================================================
|
||||
|
||||
/** Performs lambda shorthand desugaring on an arbitrary expression.
|
||||
|
@ -126,12 +126,6 @@ case object NestedPatternMatch extends IRPass {
|
||||
}
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
// === Pass Internals =======================================================
|
||||
|
||||
/** Desugars an arbitrary expression.
|
||||
|
@ -9,8 +9,6 @@ import org.enso.compiler.pass.analyse.{
|
||||
DemandAnalysis
|
||||
}
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** This pass converts usages of operators to calls to standard functions.
|
||||
*
|
||||
* This pass requires the context to provide:
|
||||
@ -87,10 +85,4 @@ case object OperatorToFunction extends IRPass {
|
||||
diag
|
||||
)
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
}
|
||||
|
@ -8,8 +8,6 @@ import org.enso.compiler.pass.IRPass
|
||||
import org.enso.compiler.pass.analyse._
|
||||
import org.enso.compiler.pass.lint.UnusedBindings
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** This pass converts operator sections to applications of binary operators.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* For a left sections it will generate a partially-applied function. For
|
||||
|
@ -5,8 +5,6 @@ import org.enso.compiler.core.IR
|
||||
import org.enso.compiler.pass.IRPass
|
||||
import org.enso.compiler.pass.desugar.ComplexType
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** Generates warnings about potential name conflicts between types and synthetic modules
|
||||
*/
|
||||
case object ModuleNameConflicts extends IRPass {
|
||||
@ -73,12 +71,6 @@ case object ModuleNameConflicts extends IRPass {
|
||||
): IR.Expression =
|
||||
ir
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
// === Pass Internals =======================================================
|
||||
|
||||
/** Lints a binding
|
||||
|
@ -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
|
||||
}
|
@ -76,12 +76,6 @@ case object ShadowedPatternFields extends IRPass {
|
||||
}
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
// === Pass Internals =======================================================
|
||||
|
||||
/** Lints for shadowed pattern variables on an arbitrary expression.
|
||||
|
@ -10,8 +10,6 @@ import org.enso.compiler.pass.desugar._
|
||||
import org.enso.compiler.pass.optimise.LambdaConsolidate
|
||||
import org.enso.compiler.pass.resolve.{ExpressionAnnotations, IgnoredBindings}
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** This pass performs linting for unused names, generating warnings if it finds
|
||||
* any.
|
||||
*
|
||||
@ -77,12 +75,6 @@ case object UnusedBindings extends IRPass {
|
||||
}
|
||||
} else ir
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
// === Pass Internals =======================================================
|
||||
|
||||
/** Lints a binding.
|
||||
|
@ -11,8 +11,6 @@ import org.enso.interpreter.node.{ExpressionNode => RuntimeExpression}
|
||||
import org.enso.interpreter.runtime.callable.argument.CallArgument
|
||||
import org.enso.interpreter.runtime.scope.{LocalScope, ModuleScope}
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** This optimisation pass recognises fully-saturated applications of known
|
||||
* functions and writes analysis data that allows optimisation of them to
|
||||
* 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
|
||||
*
|
||||
* @param knownFunctions the mapping of known functions
|
||||
|
@ -15,8 +15,6 @@ import org.enso.compiler.pass.desugar._
|
||||
import org.enso.compiler.pass.resolve.IgnoredBindings
|
||||
import org.enso.syntax.text.Location
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** This pass consolidates chains of lambdas into multi-argument lambdas
|
||||
* 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.
|
||||
*
|
||||
* @param function the function definition to optimise
|
||||
|
@ -89,12 +89,6 @@ case object UnreachableMatchBranches extends IRPass {
|
||||
}
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
// === Pass Internals =======================================================
|
||||
|
||||
/** Optimizes an expression by removing unreachable branches in case
|
||||
|
@ -57,10 +57,6 @@ case object DocumentationComments extends IRPass {
|
||||
): IR.Expression = resolveExpression(ir)
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
// === Pass Internals =======================================================
|
||||
|
||||
|
@ -58,10 +58,6 @@ case object ExpressionAnnotations extends IRPass {
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
private def doExpression(
|
||||
ir: IR.Expression
|
||||
|
@ -18,9 +18,6 @@ object FullyAppliedFunctionUses extends IRPass {
|
||||
Seq(GlobalNames)
|
||||
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
|
||||
* or annotated version of `ir`.
|
||||
*
|
||||
|
@ -366,25 +366,6 @@ case object FullyQualifiedNames extends IRPass {
|
||||
.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 = {
|
||||
val aliasInfo = name
|
||||
.unsafeGetMetadata(
|
||||
|
@ -82,8 +82,5 @@ case object GenericAnnotations extends IRPass {
|
||||
): IR.Expression = ir
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
}
|
||||
|
@ -93,10 +93,6 @@ case object GlobalNames extends IRPass {
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
private def processModuleDefinition(
|
||||
definition: IR.Module.Scope.Definition,
|
||||
|
@ -19,8 +19,6 @@ import org.enso.compiler.pass.desugar.{
|
||||
NestedPatternMatch
|
||||
}
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** This pass translates ignored bindings (of the form `_`) into fresh names
|
||||
* internally, as well as marks all bindings as whether or not they were
|
||||
* ignored.
|
||||
@ -95,12 +93,6 @@ case object IgnoredBindings extends IRPass {
|
||||
} else ir
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
private def setNotIgnored[T <: IR](ir: T): T = {
|
||||
if (ir.getMetadata(this).isEmpty) {
|
||||
ir.updateMetadata(this -->> State.NotIgnored)
|
||||
|
@ -20,9 +20,6 @@ object MethodCalls extends IRPass {
|
||||
Seq(BindingAnalysis, GlobalNames)
|
||||
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
|
||||
* or annotated version of `ir`.
|
||||
*
|
||||
|
@ -14,8 +14,6 @@ import org.enso.compiler.pass.desugar.{
|
||||
GenerateMethodBodies
|
||||
}
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** Resolves the correct `self` argument type for method definitions and stores
|
||||
* the resolution in the method's metadata.
|
||||
*/
|
||||
@ -198,9 +196,4 @@ case object MethodDefinitions extends IRPass {
|
||||
inlineContext: InlineContext
|
||||
): IR.Expression = ir
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
}
|
||||
|
@ -106,10 +106,6 @@ case object ModuleAnnotations extends IRPass {
|
||||
): IR.Expression = ir
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
/** A container for annotations on an IR construct.
|
||||
*
|
||||
|
@ -154,8 +154,5 @@ case object OverloadsResolution extends IRPass {
|
||||
): IR.Expression = ir
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
}
|
||||
|
@ -9,8 +9,6 @@ import org.enso.compiler.pass.IRPass
|
||||
import org.enso.compiler.pass.analyse.{AliasAnalysis, BindingAnalysis}
|
||||
import org.enso.compiler.pass.desugar.{GenerateMethodBodies, NestedPatternMatch}
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** Resolves constructors in pattern matches and validates their arity.
|
||||
*/
|
||||
object Patterns extends IRPass {
|
||||
@ -62,12 +60,6 @@ object Patterns extends IRPass {
|
||||
doExpression(ir, bindings, None)
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
private def doDefinition(
|
||||
ir: IR.Module.Scope.Definition,
|
||||
bindings: BindingsMap
|
||||
|
@ -87,10 +87,6 @@ case object SuspendedArguments extends IRPass {
|
||||
): IR.Expression = resolveExpression(ir)
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
// === Pass Internals =======================================================
|
||||
|
||||
|
@ -75,12 +75,6 @@ case object TypeFunctions extends IRPass {
|
||||
resolveExpression(a)
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
// === Pass Internals =======================================================
|
||||
|
||||
/** The names of the known typing functions. */
|
||||
|
@ -8,8 +8,6 @@ import org.enso.compiler.data.BindingsMap.{Resolution, ResolvedModule}
|
||||
import org.enso.compiler.pass.IRPass
|
||||
import org.enso.compiler.pass.analyse.BindingAnalysis
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
/** Resolves and desugars referent name occurrences in type positions.
|
||||
*/
|
||||
case object TypeNames extends IRPass {
|
||||
@ -152,9 +150,4 @@ case object TypeNames extends IRPass {
|
||||
ir
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
@unused sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
}
|
||||
|
@ -63,10 +63,6 @@ case object TypeSignatures extends IRPass {
|
||||
): IR.Expression = resolveExpression(ir)
|
||||
|
||||
/** @inheritdoc */
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
// === Pass Internals =======================================================
|
||||
|
||||
|
@ -35,11 +35,6 @@ class PassesTest extends CompilerTest {
|
||||
ir: IR.Expression,
|
||||
inlineContext: InlineContext
|
||||
): IR.Expression = ir
|
||||
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
}
|
||||
|
||||
// === The Tests ============================================================
|
||||
|
@ -30,11 +30,6 @@ class MetadataStorageTest extends CompilerTest {
|
||||
inlineContext: InlineContext
|
||||
): IR.Expression = ir
|
||||
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
sealed case class Metadata1() extends IRPass.IRMetadata {
|
||||
override val metadataName: String = "TestPass1.Metadata1"
|
||||
|
||||
@ -67,11 +62,6 @@ class MetadataStorageTest extends CompilerTest {
|
||||
inlineContext: InlineContext
|
||||
): IR.Expression = ir
|
||||
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
sealed case class Metadata2() extends IRPass.IRMetadata {
|
||||
override val metadataName: String = "TestPass2.Metadata2"
|
||||
|
||||
|
@ -28,11 +28,6 @@ class PassConfigurationTest extends CompilerTest {
|
||||
inlineContext: InlineContext
|
||||
): IR.Expression = ir
|
||||
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
sealed case class Configuration1() extends IRPass.Configuration {
|
||||
override var shouldWriteToContext: Boolean = false
|
||||
}
|
||||
@ -55,11 +50,6 @@ class PassConfigurationTest extends CompilerTest {
|
||||
inlineContext: InlineContext
|
||||
): IR.Expression = ir
|
||||
|
||||
override def updateMetadataInDuplicate[T <: IR](
|
||||
sourceIr: T,
|
||||
copyOfIr: T
|
||||
): T = copyOfIr
|
||||
|
||||
sealed case class Configuration2() extends IRPass.Configuration {
|
||||
override var shouldWriteToContext: Boolean = true
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -4,10 +4,10 @@ from Standard.Test import Test, Test_Suite
|
||||
import Standard.Test.Extensions
|
||||
|
||||
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.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
|
||||
|
||||
spec = Test.group "Polyglot" <|
|
||||
@ -23,7 +23,7 @@ spec = Test.group "Polyglot" <|
|
||||
Polyglot.new String ["42"].to_array . should_equal "42"
|
||||
|
||||
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" <|
|
||||
Polyglot.new Double [42] . should_equal 42
|
||||
@ -35,7 +35,7 @@ spec = Test.group "Polyglot" <|
|
||||
js_meaning.meaning . should_equal 42
|
||||
|
||||
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" <|
|
||||
hold = IntHolder.new (6 * 7)
|
||||
@ -43,7 +43,7 @@ spec = Test.group "Polyglot" <|
|
||||
hold.boxed . should_equal 42
|
||||
|
||||
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"].to_array . should_equal "42"
|
||||
|
||||
|
@ -2,17 +2,12 @@ from Standard.Test import Test, Test_Suite
|
||||
import Standard.Test.Extensions
|
||||
|
||||
type Generator
|
||||
Value h t
|
||||
Value n ~next
|
||||
|
||||
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
|
||||
|
||||
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" <|
|
||||
Test.specify "Generates four numbers properly" <|
|
||||
two = natural
|
||||
|
@ -6,7 +6,7 @@ import Standard.Test.Extensions
|
||||
from project.Semantic.Default_Args_Spec.Box import all
|
||||
|
||||
type Box
|
||||
Foo (v : Bool = True)
|
||||
Foo (v : Boolean = True)
|
||||
|
||||
type Bar (a : Integer = 1) (b : Box = (Foo False)) (c : Boolean = b.v)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user