Skip to content

Commit

Permalink
Allow eta-expansion of methods with dependent types
Browse files Browse the repository at this point in the history
  • Loading branch information
lrytz committed Sep 27, 2022
1 parent 8c6b49b commit 11e65dd
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 21 deletions.
5 changes: 0 additions & 5 deletions src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
Expand Up @@ -834,11 +834,6 @@ trait ContextErrors extends splain.SplainErrors {
setError(tree)
}

def DependentMethodTpeConversionToFunctionError(tree: Tree, tp: Type): Tree = {
issueNormalTypeError(tree, "method with dependent type " + tp + " cannot be converted to function value")
setError(tree)
}

// cases where we do not necessarily return trees

//checkStarPatOK
Expand Down
9 changes: 3 additions & 6 deletions src/compiler/scala/tools/nsc/typechecker/Typers.scala
Expand Up @@ -3202,12 +3202,9 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
def typedEtaExpansion(tree: Tree, mode: Mode, pt: Type): Tree = {
debuglog(s"eta-expanding $tree: ${tree.tpe} to $pt")

if (tree.tpe.isDependentMethodType) DependentMethodTpeConversionToFunctionError(tree, tree.tpe) // TODO: support this
else {
val expansion = etaExpand(tree, context.owner)
if (context.undetparams.isEmpty) typed(expansion, mode, pt)
else instantiate(typed(expansion, mode), mode, pt)
}
val expansion = etaExpand(tree, context.owner)
if (context.undetparams.isEmpty) typed(expansion, mode, pt)
else instantiate(typed(expansion, mode), mode, pt)
}

def typedRefinement(templ: Template): Unit = {
Expand Down
2 changes: 1 addition & 1 deletion src/reflect/scala/reflect/internal/Definitions.scala
Expand Up @@ -855,7 +855,7 @@ trait Definitions extends api.StandardDefinitions {
| was: $restpe
| now""")(methodToExpressionTp(restpe))
case mt @ MethodType(_, restpe) if mt.isImplicit => methodToExpressionTp(restpe)
case mt @ MethodType(_, restpe) if !mt.isDependentMethodType =>
case mt @ MethodType(_, restpe) =>
if (phase.erasedTypes) FunctionClass(mt.params.length).tpe
else functionType(mt.paramTypes, methodToExpressionTp(restpe))
case NullaryMethodType(restpe) => methodToExpressionTp(restpe)
Expand Down

This file was deleted.

This file was deleted.

17 changes: 17 additions & 0 deletions test/files/run/eta-dependent.check
@@ -0,0 +1,17 @@

scala> val a = "obj"
val a: String = obj

scala> def f(x: Int): a.type = a
def f(x: Int): a.type

scala> val f1 = f _
val f1: Int => a.type = $Lambda

scala> val f2: Int => a.type = f
val f2: Int => a.type = $Lambda

scala> val f3: Int => Object = f
val f3: Int => Object = $Lambda

scala> :quit
59 changes: 59 additions & 0 deletions test/files/run/eta-dependent.scala
@@ -0,0 +1,59 @@
object NoMoreNeg {
def foo(x: AnyRef): x.type = x
val x: AnyRef => Any = foo
}

object t12641 {
def f(sb: StringBuilder) = Option("").foreach(sb.append)
}

object t12641a {
trait A {
def foo(s: String): this.type
def foo(s: Int): this.type
}
trait T {
val a1: A
val o: Option[String]

def t(a2: A): Unit = {
o.foreach(a1.foo)
o.foreach(a2.foo)

val f2: String => a2.type = a2.foo
val f3: String => A = a2.foo
}
}
}

object t12641b {
trait A {
def foo(s: String): this.type
}
trait T {
val a1: A
val o: Option[String]

def t(a2: A): Unit = {
o.foreach(a1.foo)
o.foreach(a2.foo)

val f1 = a2.foo _
val f2: String => a2.type = a2.foo
val f3: String => A = a2.foo
}
}
}

import scala.tools.partest.ReplTest

object Test extends ReplTest {
override protected def normalize(s: String): String = s.replaceAll("(Lambda).*", "$1")
def code = """
val a = "obj"
def f(x: Int): a.type = a
val f1 = f _
val f2: Int => a.type = f
val f3: Int => Object = f
""".trim
}

0 comments on commit 11e65dd

Please sign in to comment.