Skip to content

Commit 32b35ec

Browse files
authored
Merge pull request #8469 from dotty-staging/fix-#4908
Restrict Eta-reduction to Java-defined classes
2 parents 435397f + 144d554 commit 32b35ec

File tree

6 files changed

+116
-5
lines changed

6 files changed

+116
-5
lines changed

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -605,11 +605,11 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
605605
if (tparams1.nonEmpty)
606606
return recur(tp1.EtaExpand(tparams1), tp2) || fourthTry
607607
tp2 match {
608-
case EtaExpansion(tycon2) if tycon2.symbol.isClass =>
609-
return recur(tp1, tycon2)
608+
case EtaExpansion(tycon2) if tycon2.symbol.isClass && tycon2.symbol.is(JavaDefined) =>
609+
recur(tp1, tycon2) || fourthTry
610610
case _ =>
611+
fourthTry
611612
}
612-
fourthTry
613613
}
614614
compareTypeLambda
615615
case OrType(tp21, tp22) =>
@@ -773,7 +773,10 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
773773
isNewSubType(tp1.parent)
774774
case tp1: HKTypeLambda =>
775775
def compareHKLambda = tp1 match {
776-
case EtaExpansion(tycon1) => recur(tycon1, tp2)
776+
case EtaExpansion(tycon1) if tycon1.symbol.isClass && tycon1.symbol.is(JavaDefined) =>
777+
// It's a raw type that was mistakenly eta-expanded to a hk-type.
778+
// This can happen because we do not cook types coming from Java sources
779+
recur(tycon1, tp2)
777780
case _ => tp2 match {
778781
case tp2: HKTypeLambda => false // this case was covered in thirdTry
779782
case _ => tp2.typeParams.hasSameLengthAs(tp1.paramRefs) && isSubType(tp1.resultType, tp2.appliedTo(tp1.paramRefs))
@@ -2591,7 +2594,11 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
25912594
}
25922595

25932596
override def isSubType(tp1: Type, tp2: Type, approx: ApproxState): Boolean =
2594-
traceIndented(s"${show(tp1)} <:< ${show(tp2)}${if (Config.verboseExplainSubtype) s" ${tp1.getClass} ${tp2.getClass}" else ""} $approx ${if (frozenConstraint) " frozen" else ""}") {
2597+
def moreInfo =
2598+
if Config.verboseExplainSubtype || ctx.settings.verbose.value
2599+
then s" ${tp1.getClass} ${tp2.getClass}"
2600+
else ""
2601+
traceIndented(s"${show(tp1)} <:< ${show(tp2)}$moreInfo $approx ${if (frozenConstraint) " frozen" else ""}") {
25952602
super.isSubType(tp1, tp2, approx)
25962603
}
25972604

tests/pending/pos/i4908.scala

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
object Test {
2+
trait A
3+
trait B
4+
trait TestConstructor1 { type F[X <: A]
5+
trait FromSet[C[_ <: A with B]]
6+
7+
trait MSetLike[X <: A with B, This <: MSet[X] with MSetLike[X, This]] {
8+
def to[C[X <: A with B] <: MSet[X] with MSetLike[X, C[X]]](fi: FromSet[C]): C[X] = ???
9+
}
10+
trait MSet[X <: A with B] extends MSetLike[X, MSet[X]]
11+
object MSetFactory extends FromSet[MSet]
12+
}
13+
14+
trait TestConstructor4[D] {
15+
trait TestConstructor5[E] {
16+
trait FromSet[C[_ <: D with E]]
17+
18+
trait MSetLike[X <: D with E, This <: MSet[X] with MSetLike[X, This]] {
19+
def to[C[X <: D with E] <: MSet[X] with MSetLike[X, C[X]]](fi: FromSet[C]): C[X] = ???
20+
}
21+
trait MSet[X <: D with E] extends MSetLike[X, MSet[X]]
22+
object MSetFactory extends FromSet[MSet]
23+
}
24+
}
25+
26+
type C = A & B
27+
val v1: TestConstructor1 => Unit = { f =>
28+
type P[a <: A] = f.F[a]
29+
30+
type P1[c <: C] = f.MSet[c]
31+
(f.MSetFactory: f.FromSet[f.MSet]): Unit
32+
(x: P1[C]) => x.to(f.MSetFactory)
33+
}
34+
35+
def f3(f: TestConstructor4[A])(g: f.TestConstructor5[B]): Unit = {
36+
type P1[c <: C] = g.MSet[c]
37+
(g.MSetFactory: g.FromSet[g.MSet]): Unit
38+
(x: P1[C]) => x.to(g.MSetFactory)
39+
(x: P1[C]) => x.to[g.MSet](g.MSetFactory)
40+
}
41+
}

tests/pos/i4742.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import scala.reflect.ClassTag
2+
3+
class Test {
4+
def foo[T <: String: ClassTag](f: T => Int) = 1
5+
def bar(f: String => Int) = foo(f)
6+
}

tests/pos/i4854.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class C {
2+
def f(x: Int): Unit = ()
3+
val f: String => Unit = s => ()
4+
f("a")
5+
}

tests/pos/i4867.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
object UnionMapping {
2+
private def parse(string: String): Int | Double = {
3+
if(string.contains("."))
4+
string.toDouble
5+
else
6+
string.toInt
7+
}
8+
9+
def test_number = {
10+
val strings: Seq[String] = Seq("123", "2.0", "42")
11+
// Works
12+
val asdf: Seq[AnyVal] = strings.map(parse(_))
13+
// Fails to compile
14+
val union: Seq[Int | Double] = strings.map(parse(_))
15+
}
16+
}

tests/pos/i4906.scala

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
object Test {
2+
trait A
3+
trait TestConstructor1 { type F[_ <: A] }
4+
trait TestConstructor2[D] {
5+
type F[_ <: D]
6+
class G[X <: D]
7+
trait TestConstructor3[E] {
8+
type G[_ <: D & E]
9+
class H[X <: D & E]
10+
}
11+
}
12+
13+
val v1: TestConstructor1 => Unit = { f =>
14+
type P[a <: A] = f.F[a] // OK
15+
}
16+
17+
val v2: TestConstructor2[A] => Unit = { f =>
18+
type P[a <: A] = f.F[a] // Error! Type argument a does not conform to upper bound D
19+
}
20+
21+
def f2(f: TestConstructor2[A]): Unit = {
22+
type P[a <: A] = f.F[a] // Error! Type argument a does not conform to upper bound D
23+
}
24+
25+
val v3: (f: TestConstructor2[A]) => (g: f.TestConstructor3[A]) => Unit = ??? // ok
26+
val v4: (f: TestConstructor2[A]) => (g: f.TestConstructor3[A]) => Unit = {f => ???}
27+
val v5: (f: TestConstructor2[A]) => (g: f.TestConstructor3[A]) => Unit = {(f: TestConstructor2[A]) => ???}
28+
// }
29+
def f3(f: TestConstructor2[A], g: f.TestConstructor3[A]): Unit = {
30+
type P[a <: A] = f.F[a] // Error! Type argument a does not conform to upper bound D
31+
type Q[a <: A] = g.G[a]
32+
// type R[a <: A] = (f.F & g.G)[a] // compiler error
33+
type R[a <: A] = ([X <: A] =>> f.F[X] & g.G[X])[a]
34+
type S[a <: A] = f.G[a] & g.H[a]
35+
}
36+
}

0 commit comments

Comments
 (0)