Skip to content

Commit 5e56416

Browse files
committed
Fix #9971: Fix EtaExpansion unapply method
The unapply method of EtaExpansion was missing several necessary conditions, which are now added: - parameters and arguments must have same length - bounds must conform
1 parent 61d66c3 commit 5e56416

File tree

3 files changed

+44
-10
lines changed

3 files changed

+44
-10
lines changed

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

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,25 +26,46 @@ object TypeApplications {
2626

2727
/** Extractor for
2828
*
29-
* [v1 X1: B1, ..., vn Xn: Bn] -> C[X1, ..., Xn]
29+
* [X1: B1, ..., Xn: Bn] -> C[X1, ..., Xn]
3030
*
31-
* where v1, ..., vn and B1, ..., Bn are the variances and bounds of the type parameters
32-
* of the class C.
31+
* where B1, ..., Bn are bounds of the type parameters of the class C.
3332
*
3433
* @param tycon C
3534
*/
36-
object EtaExpansion {
37-
def apply(tycon: Type)(using Context): Type = {
35+
object EtaExpansion:
36+
37+
def apply(tycon: Type)(using Context): Type =
3838
assert(tycon.typeParams.nonEmpty, tycon)
3939
tycon.EtaExpand(tycon.typeParamSymbols)
40-
}
4140

42-
def unapply(tp: Type)(using Context): Option[Type] = tp match {
41+
/** Test that the parameter bounds in a hk type lambda `[X1,...,Xn] => C[X1, ..., Xn]`
42+
* contain the bounds of the type parameters of `C`. This is necessary to be able to
43+
* contract the hk lambda to `C`.
44+
*/
45+
private def weakerBounds(tp: HKTypeLambda, tparams: List[ParamInfo])(using Context): Boolean =
46+
val onlyEmptyBounds = tp.typeParams.forall(_.paramInfo == TypeBounds.empty)
47+
onlyEmptyBounds
48+
// Note: this pre-test helps efficiency. It is also necessary since in some cases
49+
// tparams is empty. This can happen when we change the owners of inlined local
50+
// classes in mapSymbols. See pos/reference/delegates.scala for an example.
51+
// In this case, we can still return true if we know that the hk lambda bounds
52+
// are empty anyway.
53+
|| {
54+
val paramRefs = tparams.map(_.paramRef)
55+
tp.typeParams.corresponds(tparams) { (param1, param2) =>
56+
param2.paramInfo <:< param1.paramInfo.substParams(tp, paramRefs)
57+
}
58+
}
59+
60+
def unapply(tp: Type)(using Context): Option[Type] = tp match
4361
case tp @ HKTypeLambda(tparams, AppliedType(fn: Type, args))
44-
if args.lazyZip(tparams).forall((arg, tparam) => arg == tparam.paramRef) => Some(fn)
62+
if fn.typeSymbol.isClass
63+
&& tparams.hasSameLengthAs(args)
64+
&& args.lazyZip(tparams).forall((arg, tparam) => arg == tparam.paramRef)
65+
&& weakerBounds(tp, fn.typeParams) => Some(fn)
4566
case _ => None
46-
}
47-
}
67+
68+
end EtaExpansion
4869

4970
/** Adapt all arguments to possible higher-kinded type parameters using etaExpandIfHK
5071
*/

tests/neg/i9958.check

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,8 @@
22
1 |val x = summon[[X] =>> (X, X)] // error
33
| ^
44
| no implicit argument of type [X] =>> (X, X) was found for parameter x of method summon in object DottyPredef
5+
-- [E007] Type Mismatch Error: tests/neg/i9958.scala:8:10 --------------------------------------------------------------
6+
8 |def b = f(a) // error
7+
| ^
8+
| Found: G[[A <: Int] =>> List[A]]
9+
| Required: G[List]

tests/neg/i9958.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,9 @@
11
val x = summon[[X] =>> (X, X)] // error
2+
// #9971:
3+
trait G[F[_]]
4+
5+
def f(x: G[List]) = ???
6+
7+
def a: G[[A <: Int] =>> List[A]] = ???
8+
def b = f(a) // error
9+

0 commit comments

Comments
 (0)