Skip to content

Commit 183d84e

Browse files
committed
Eta-expand methods even if the expected type is a polymorphic function
In that case, let eta-expansion produce an untyped monomorphic lambda as usual. Thanks to the previous commit, a type parameter clause for this lambda will be inferred if possible.
1 parent 73b0e75 commit 183d84e

File tree

3 files changed

+38
-2
lines changed

3 files changed

+38
-2
lines changed

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4344,6 +4344,29 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
43444344
if isApplyProxy(tree) then newExpr
43454345
else if pt.isInstanceOf[PolyProto] then tree
43464346
else
4347+
if Feature.enabled(Feature.typeClauseInference) then
4348+
// If `tree` is a polymorphic method reference and the expected
4349+
// type is a polymorphic function, perform a monomorphic
4350+
// eta-expansion of the method reference.
4351+
// For example, this means that
4352+
//
4353+
// (1, 2.0).map(Option.apply)
4354+
//
4355+
// will expand to:
4356+
//
4357+
// (1, 2.0).map(x => Option.apply(x))
4358+
//
4359+
// A type parameter clause for the lambda will subsequently be
4360+
// inferred (from its expected type) in typedFunctionValue.
4361+
pt match
4362+
case defn.PolyFunctionOf(_: PolyType) =>
4363+
poly.resultType match
4364+
case mt: MethodType =>
4365+
val expanded = etaExpand(tree, mt, mt.paramInfos.length)
4366+
return simplify(typed(expanded, pt), pt, locked)
4367+
case _ =>
4368+
case _ =>
4369+
end if
43474370
var typeArgs = tree match
43484371
case Select(qual, nme.CONSTRUCTOR) => qual.tpe.widenDealias.argTypesLo.map(TypeTree(_))
43494372
case _ => Nil

tests/neg/typeClauseInference.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
import scala.language.experimental.typeClauseInference
22

33
val notInScopeInferred: [T] => T => T = x => (x: T) // error
4+
5+
def bar[A]: A => A = x => x
6+
val barf1: [T] => T => T = bar(_) // ok
7+
val barf2: [T] => T => T = bar // error, unlike in the original SIP-49.

tests/pos/typeClauseInference.scala

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,14 @@ class Test:
77
val it3: [T, S <: List[T]] => (T, S) => List[T] = (x, y) => x :: y
88
val tuple1: (String, String) = (1, 2.0).map[[_] =>> String](_.toString)
99
val tuple2: (List[Int], List[Double]) = (1, 2.0).map(List(_))
10-
// Not supported yet, require eta-expansion with a polymorphic expected type
11-
// val tuple3: (List[Int], List[Double]) = (1, 2.0).map(List.apply)
10+
11+
// Eta-expansion
12+
val e1: [T] => T => Option[T] = Option.apply
13+
val tuple3: (Option[Int], Option[Double]) = (1, 2.0).map(Option.apply)
14+
15+
// Eta-expansion that wouldn't work with the original SIP-49
16+
def pair[S, T](x: S, y: T): (S, T) = (x, y)
17+
val f5: [T] => (Int, T) => (Int, T) = pair
18+
val f6: [T] => (T, Int) => (T, Int) = pair
19+
def id[T](x: T): T = x
20+
val f7: [S] => List[S] => List[S] = id

0 commit comments

Comments
 (0)