Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Static, but instance, but static #3764

Merged
merged 7 commits into from
Oct 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@
- [Invalidate module's IR cache if imported module changed][3703]
- [Don't rename imported Main module that only imports names][3710]
- [Notify node status to the IDE][3729]
- [Make instance methods callable like statics][3764]
- [Distinguish static and instance methods][3740]
- [By-type pattern matching][3742]
- [Fix performance of method calls on polyglot arrays][3781]
Expand Down Expand Up @@ -431,6 +432,7 @@
[3710]: https://github.com/enso-org/enso/pull/3710
[3729]: https://github.com/enso-org/enso/pull/3729
[3740]: https://github.com/enso-org/enso/pull/3740
[3764]: https://github.com/enso-org/enso/pull/3764
[3742]: https://github.com/enso-org/enso/pull/3742
[3781]: https://github.com/enso-org/enso/pull/3781

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1474,7 +1474,11 @@ class IrToTruffle(

val argName = arg.getName

if (seenArgNames contains argName) {
if (
argName != Constants.Names.SELF_ARGUMENT && seenArgNames.contains(
argName
)
) {
throw new IllegalStateException(
s"A duplicate argument name, $argName, was found during codegen."
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,14 @@ final class SuggestionBuilder[A: IndexedSource](val source: A) {

go(tree ++= tpSuggestions.map(Tree.Node(_, Vector())), scope)

case IR.Module.Scope.Definition.Method
case m @ IR.Module.Scope.Definition.Method
.Explicit(
IR.Name.MethodReference(typePtr, methodName, _, _, _),
IR.Function.Lambda(args, body, _, _, _, _),
_,
_,
_
) =>
) if !m.isStaticWrapperForInstanceMethod =>
val typeSignature = ir.getMetadata(TypeSignatures)
val selfTypeOpt = typePtr match {
case Some(typePtr) =>
Expand Down
15 changes: 15 additions & 0 deletions engine/runtime/src/main/scala/org/enso/compiler/core/IR.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1455,6 +1455,21 @@ object IR {
true // if it's not a function, it has no arguments, therefore no `self`
}

def isStaticWrapperForInstanceMethod: Boolean = body match {
case function: Function.Lambda =>
function.arguments.map(_.name) match {
case IR.Name.Self(_, true, _, _) :: IR.Name.Self(
_,
false,
_,
_
) :: _ =>
true
case _ => false
}
case _ => false
}

}

/** The definition of a method for a given constructor using sugared
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import org.enso.compiler.context.{InlineContext, ModuleContext}
import org.enso.compiler.core.IR
import org.enso.compiler.core.ir.MetadataStorage.ToPair
import org.enso.compiler.data.BindingsMap
import org.enso.compiler.data.BindingsMap.{Resolution, ResolvedType}
import org.enso.compiler.exception.CompilerError
import org.enso.compiler.pass.IRPass
import org.enso.compiler.pass.analyse.BindingAnalysis
Expand Down Expand Up @@ -84,7 +85,38 @@ case object MethodDefinitions extends IRPass {
case other => other
}

ir.copy(bindings = newDefs)
val withStaticAliases = newDefs.flatMap {
case method: IR.Module.Scope.Definition.Method.Explicit
if !method.isStatic =>
method.methodReference.typePointer.flatMap(
_.getMetadata(this)
) match {
case Some(Resolution(ResolvedType(_, tp))) if tp.members.nonEmpty =>
val dup = method.duplicate()
val static = dup.copy(body =
IR.Function.Lambda(
List(
IR.DefinitionArgument
.Specified(
IR.Name.Self(None, true),
None,
None,
false,
None
)
),
dup.body,
None
)
)
List(method, static)
case _ => List(method)
}

case other => List(other)
}

ir.copy(bindings = withStaticAliases)
}

private def resolveType(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ case object OverloadsResolution extends IRPass {
ir: IR.Module,
@unused moduleContext: ModuleContext
): IR.Module = {
var seenTypes: Set[String] = Set()
var seenMethods: Map[Option[String], Set[String]] = Map()
var seenTypes: Set[String] = Set()
var seenMethods: Map[Option[String], Set[(String, Boolean)]] = Map()

val types = ir.bindings.collect {
case tp: IR.Module.Scope.Definition.Type => tp
Expand All @@ -72,7 +72,7 @@ case object OverloadsResolution extends IRPass {
val newMethods: List[IR.Module.Scope.Definition] = methods.map(method => {
if (
seenMethods(method.typeName.map(_.name))
.contains(method.methodName.name)
.contains((method.methodName.name, method.isStatic))
) {
IR.Error.Redefined
.Method(method.typeName, method.methodName, method.location)
Expand All @@ -85,10 +85,10 @@ case object OverloadsResolution extends IRPass {
method.location
)
case _ =>
val currentMethods = seenMethods(method.typeName.map(_.name))
val currentMethods: Set[(String, Boolean)] =
seenMethods(method.typeName.map(_.name))
seenMethods = seenMethods + (method.typeName.map(_.name) ->
(currentMethods + method.methodName.name))

(currentMethods + ((method.methodName.name, method.isStatic))))
method
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,19 +165,25 @@ class MethodsTest extends InterpreterTest {
eval(code).toString shouldEqual "(Mk_Foo 123)"
}

"not be callable on types when non-static" in {
"be callable on types when non-static, with additional self arg" in {
val code =
"""
"""from Standard.Base.IO import all
|
|type Foo
| Mk_Foo a
|
| inc self = Mk_Foo self.a
| inc self = Foo.Mk_Foo self.a+1
|
|main = Foo.inc
|main =
| IO.println (Foo.inc (Foo.Mk_Foo 12))
| IO.println (Foo.Mk_Foo 13).inc
| IO.println (.inc self=Foo self=(Foo.Mk_Foo 14))
| IO.println (Foo.inc self=(Foo.Mk_Foo 15))
|""".stripMargin
the[InterpreterException] thrownBy eval(
code
) should have message "Method `inc` of Foo could not be found."
eval(code)
consumeOut.shouldEqual(
List("(Mk_Foo 13)", "(Mk_Foo 14)", "(Mk_Foo 15)", "(Mk_Foo 16)")
)
}

"not be callable on instances when static" in {
Expand Down