Skip to content

Commit 33d1d7c

Browse files
committed
Fix scala#4884: asSeenFrom on incorrect prefix in type applications
In this code we fetch the type parameter bounds from the definition, so we must substitute their definition using `asSeenFrom` with the correct prefix. The correct prefix is however hard to find: `TypeApplications.typeParams` finds a `self: TypeRefs` (after however many steps), the correct prefix is `self.prefix`. In fact, a compositional typing rule would obtain the bounds from the type (or, well, kind) of the type constructor; that would avoid the need for using `asSeenFrom`. We only have a way to obtain such a kind for `NamedType` (where we can take the `info`). However, that seems enough.
1 parent c42e325 commit 33d1d7c

File tree

2 files changed

+46
-1
lines changed

2 files changed

+46
-1
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,14 @@ object Checking {
6565
* cannot handle those.
6666
*/
6767
def checkAppliedType(tree: AppliedTypeTree, boundsCheck: Boolean)(implicit ctx: Context) = {
68+
def kind(tp: Type): Type = tp match {
69+
case nTp: NamedType => nTp.info
70+
case _ => tp
71+
}
6872
val AppliedTypeTree(tycon, args) = tree
6973
// If `args` is a list of named arguments, return corresponding type parameters,
7074
// otherwise return type parameters unchanged
71-
val tparams = tycon.tpe.typeParams
75+
val tparams = kind(tycon.tpe).typeParams
7276
def argNamed(tparam: ParamInfo) = args.find {
7377
case NamedArg(name, _) => name == tparam.paramName
7478
case _ => false

tests/pos/i4884.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 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 = { f => g =>
26+
// type P[a <: A] = f.F[a] // Error! Type argument a does not conform to upper bound D
27+
// // type Q[a <: A] = g.G[a]
28+
// // type R[a <: A] = (f.F & g.G)[a]
29+
// // type R[a <: A] = ([X] => f.F[X] & g.G[X])[a]
30+
// }
31+
def f3(f: TestConstructor2[A], g: f.TestConstructor3[A]): Unit = {
32+
type P[a <: A] = f.F[a] // Error! Type argument a does not conform to upper bound D
33+
type Q[a <: A] = g.G[a]
34+
// type R[a <: A] = (f.F & g.G)[a] // compiler error
35+
type R[a <: A] = ([X <: A] => f.F[X] & g.G[X])[a]
36+
type S[a <: A] = f.G[a] & g.H[a]
37+
}
38+
//val v4: (f: TestConstructor2[A]) => (g: f.TestConstructor3[A]) => Unit = {f => ???} // crash
39+
//val v5: (f: TestConstructor2[A]) => (g: f.TestConstructor3[A]) => Unit = {(f: TestConstructor2[A]) => ???} // crash
40+
//val v6: (f: TestConstructor2[A]) => (g: f.TestConstructor3[A]) => Unit = {(f: TestConstructor2[A]) => (g: f.TestConstructor3[A]) => ???} // crash
41+
}

0 commit comments

Comments
 (0)