Skip to content

Commit 6485f89

Browse files
authored
Merge pull request #4902 from dotty-staging/fix-transparent-2
Fix #4884: Fix handling of bounds of type lambdas
2 parents 486b731 + 3f639b6 commit 6485f89

File tree

8 files changed

+247
-25
lines changed

8 files changed

+247
-25
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
7676
def seq(stats: List[Tree], expr: Tree)(implicit ctx: Context): Tree =
7777
if (stats.isEmpty) expr
7878
else expr match {
79-
case Block(estats, eexpr) => cpy.Block(expr)(stats ::: estats, eexpr)
79+
case Block(estats, eexpr) =>
80+
cpy.Block(expr)(stats ::: estats, eexpr).withType(ta.avoidingType(eexpr, stats))
8081
case _ => Block(stats, expr)
8182
}
8283

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ trait ParamInfo {
2727
* For type lambda parameters, it's the same as `paramInfos` as
2828
* `asSeenFrom` has already been applied to the whole type lambda.
2929
*/
30-
def paramInfoAsSeenFrom(pre: Type)(implicit ctx: Context): Type
30+
def paramInfoAsSeenFrom(prefix: Type)(implicit ctx: Context): Type
3131

3232
/** The parameter bounds, or the completer if the type parameter
3333
* is an as-yet uncompleted symbol.

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,14 +168,18 @@ class TypeApplications(val self: Type) extends AnyVal {
168168
* any type parameter that is-rebound by the refinement.
169169
*/
170170
final def typeParams(implicit ctx: Context): List[TypeParamInfo] = /*>|>*/ track("typeParams") /*<|<*/ {
171+
def isTrivial(prefix: Type, tycon: Symbol) = prefix match {
172+
case prefix: ThisType => prefix.cls `eq` tycon.owner
173+
case NoPrefix => true
174+
case _ => false
175+
}
171176
try self match {
172177
case self: TypeRef =>
173178
val tsym = self.symbol
174179
if (tsym.isClass) tsym.typeParams
175-
else if (!tsym.exists) self.info.typeParams
176180
else tsym.infoOrCompleter match {
177-
case info: LazyType => info.completerTypeParams(tsym)
178-
case info => info.typeParams
181+
case info: LazyType if isTrivial(self.prefix, tsym) => info.completerTypeParams(tsym)
182+
case _ => self.info.typeParams
179183
}
180184
case self: AppliedType =>
181185
if (self.tycon.typeSymbol.isClass) Nil

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3195,7 +3195,7 @@ object Types {
31953195
def isTypeParam(implicit ctx: Context) = tl.paramNames.head.isTypeName
31963196
def paramName(implicit ctx: Context) = tl.paramNames(n)
31973197
def paramInfo(implicit ctx: Context) = tl.paramInfos(n)
3198-
def paramInfoAsSeenFrom(pre: Type)(implicit ctx: Context) = paramInfo.asSeenFrom(pre, pre.classSymbol)
3198+
def paramInfoAsSeenFrom(pre: Type)(implicit ctx: Context) = paramInfo
31993199
def paramInfoOrCompleter(implicit ctx: Context): Type = paramInfo
32003200
def paramVariance(implicit ctx: Context): Int = tl.paramNames(n).variance
32013201
def paramRef(implicit ctx: Context): Type = tl.paramRefs(n)

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,9 +1238,10 @@ class Typer extends Namer
12381238
args = args.take(tparams.length)
12391239
}
12401240
def typedArg(arg: untpd.Tree, tparam: ParamInfo) = {
1241+
def tparamBounds = tparam.paramInfoAsSeenFrom(tpt1.tpe.appliedTo(tparams.map(_ => TypeBounds.empty)))
12411242
val (desugaredArg, argPt) =
12421243
if (ctx.mode is Mode.Pattern)
1243-
(if (untpd.isVarPattern(arg)) desugar.patternVar(arg) else arg, tparam.paramInfo)
1244+
(if (untpd.isVarPattern(arg)) desugar.patternVar(arg) else arg, tparamBounds)
12441245
else
12451246
(arg, WildcardType)
12461247
if (tpt1.symbol.isClass)
@@ -1259,10 +1260,10 @@ class Typer extends Namer
12591260
// An unbounded `_` automatically adapts to type parameter bounds. This means:
12601261
// If we have wildcard application C[_], where `C` is a class replace
12611262
// with C[_ >: L <: H] where `L` and `H` are the bounds of the corresponding
1262-
// type parameter in `C`, avoiding any referemces to parameters of `C`.
1263-
// The transform does not apply for patters, where empty bounds translate to
1263+
// type parameter in `C`.
1264+
// The transform does not apply for patterns, where empty bounds translate to
12641265
// wildcard identifiers `_` instead.
1265-
res = res.withType(avoid(tparam.paramInfo, tpt1.tpe.typeParamSymbols))
1266+
res = res.withType(tparamBounds)
12661267
case _ =>
12671268
}
12681269
res

tests/pos/i4884.scala

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
object Test {
2+
trait A
3+
trait B
4+
trait TestConstructor1 { type F[X <: A] <: TestConstructor2[A] }
5+
trait TestConstructor2[D] {
6+
type F[_ <: D]
7+
class G[X <: D]
8+
trait TestConstructor3[E] {
9+
type G[X <: D & E] <: TestConstructor2.this.F[X] & H[X]
10+
class H[X <: D & E] {
11+
type A <: G[X]
12+
}
13+
}
14+
}
15+
trait TestConstructor4[D] {
16+
trait TestConstructor5[E] {
17+
trait MSetLike[X <: D & E, This <: MSet[X] with MSetLike[X, This]]
18+
trait MSet[X <: D & E] extends MSetLike[X, MSet[X]]
19+
}
20+
}
21+
22+
val v1: TestConstructor1 => Unit = { f =>
23+
type P[a <: A] = f.F[a]
24+
}
25+
26+
val v2: TestConstructor2[A] => Unit = { f =>
27+
type P[a <: A] = f.F[a]
28+
}
29+
30+
def f2(f: TestConstructor2[A]): Unit = {
31+
type P[a <: A] = f.F[a]
32+
}
33+
34+
type C = A & B
35+
def f3(f: TestConstructor2[A], g: f.TestConstructor3[B]): Unit = {
36+
type P1[a <: A] = f.F[a]
37+
type P2[a <: A] = f.G[a]
38+
type Q1[c <: C] = g.G[c]
39+
type Q2[c <: C] = g.H[c]
40+
type R1[c <: C] = f.G[c] & g.H[c]
41+
type R2[c <: C] = f.G[c] | g.H[c]
42+
type S1[c <: C] = ([X <: C] => f.F[X] & g.G[X])[c]
43+
type S2[c <: C] = ([X <: C] => f.F[X] | g.G[X])[c]
44+
}
45+
def f3(f: TestConstructor4[A], g: f.TestConstructor5[B]): Unit = {
46+
type P1[c <: C] = g.MSet[c]
47+
}
48+
}

tests/run/Tuple.scala

Lines changed: 58 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,81 @@
11
import annotation.showAsInfix
22

3+
object typelevel {
4+
erased def erasedValue[T]: T = ???
5+
class Typed[T](val value: T) { type Type = T }
6+
}
7+
38
sealed trait Tuple
9+
object Empty extends Tuple
410

5-
object Tuple {
6-
object Empty extends Tuple
11+
@showAsInfix
12+
final case class *: [H, T <: Tuple](hd: H, tl: T) extends Tuple
713

14+
object Tuple {
15+
import typelevel._
816
type Empty = Empty.type
917

10-
@showAsInfix
11-
final case class *: [H, T <: Tuple](hd: H, tl: T) extends Tuple
18+
class TupleOps(val xs: Tuple) extends AnyVal {
19+
transparent def *: [H] (x: H): Tuple = new *:(x, xs)
20+
transparent def size: Int = xs match {
21+
case Empty => 0
22+
case _ *: xs1 => xs1.size + 1
23+
}
24+
transparent def apply(n: Int): Any = xs match {
25+
case x *: _ if n == 0 => x
26+
case _ *: xs1 if n > 0 => xs1.apply(n - 1)
27+
}
28+
transparent def **: (ys: Tuple): Tuple = ys match {
29+
case Empty => xs
30+
case y *: ys1 => y *: (ys1 **: xs)
31+
}
32+
transparent def head = xs match {
33+
case x *: _ => x
34+
}
35+
transparent def tail = xs match {
36+
case _ *: xs => xs
37+
}
38+
}
1239

13-
class HListDeco(val xs: Tuple) extends AnyVal {
14-
transparent def *: [H] (x: H): Tuple = Tuple.*:.apply(x, xs)
40+
val emptyArray = Array[Object]()
1541

16-
transparent def size: Int = Tuple.size(xs)
17-
}
42+
transparent def toObj(t: Any) = t.asInstanceOf[Object]
1843

19-
transparent def size(xs: Tuple): Int = xs match {
20-
case Empty => 0
21-
case _ *: xs1 => size(xs1) + 1
44+
transparent def toArray(t: Tuple): Array[Object] = t.size match {
45+
case 0 => emptyArray
46+
case 1 => Array(toObj(t(0)))
47+
case 2 => Array(toObj(t(0)), toObj(t(1)))
48+
case 3 => Array(toObj(t(0)), toObj(t(1)), toObj(t(2)))
49+
case 4 => Array(toObj(t(0)), toObj(t(1)), toObj(t(2)), toObj(t(3)))
2250
}
2351

24-
transparent implicit def hlistDeco(xs: Tuple): HListDeco = new HListDeco(xs)
52+
transparent implicit def tupleDeco(xs: Tuple): TupleOps = new TupleOps(xs)
2553

2654
transparent def apply(): Tuple = Empty
2755
transparent def apply(x1: Any): Tuple = x1 *: Empty
2856
transparent def apply(x1: Any, x2: Any) = x1 *: x2 *: Empty
57+
transparent def apply(x1: Any, x2: Any, x3: Any) = x1 *: x2 *: x3 *: Empty
2958

3059
val xs0 = Tuple()
3160
val xs1 = Tuple(2)
3261
val xs2 = Tuple(2, "a")
33-
val s0 = xs0.size
34-
val s1 = xs1.size
35-
val s2 = xs2.size
62+
val xs3 = Tuple(true, 1, 2.0)
63+
transparent val s0 = xs0.size; val s0c: 0 = s0
64+
transparent val s1 = xs1.size; val s1c: 1 = s1
65+
transparent val s2 = xs2.size; val s2c: 2 = s2
66+
transparent val s3 = xs3.size; val s3c: 3 = s3
67+
val e0 = xs3(0); val e0c: Boolean = e0
68+
val e1 = xs3(1); val e1c: Int = e1
69+
val e2 = xs3(2); val e2c: Double = e2
70+
71+
val conc0 = xs0 **: xs3
72+
val conc1 = xs3 **: xs0
73+
val conc2 = xs2 **: xs3
74+
val e3c: Int = conc0(1)
75+
val e4c: Int = conc1(1)
76+
val e5c: Int = conc2(0)
77+
val e6c: Double = conc2(4)
78+
3679
}
3780

3881
object Test extends App

tests/run/TupleImpl.scala

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package test {
2+
3+
import annotation.showAsInfix
4+
5+
object typelevel {
6+
erased def erasedValue[T]: T = ???
7+
case class Typed[T](val value: T) { type Type = T }
8+
}
9+
10+
sealed trait Tuple
11+
object Empty extends Tuple
12+
13+
@showAsInfix
14+
case class *: [+H, +T <: Tuple](hd: H, tl: T) extends Tuple
15+
16+
object Tuple {
17+
import typelevel._
18+
type Empty = Empty.type
19+
20+
transparent def _cons[H, T <: Tuple] (x: H, xs: T): Tuple = new *:(x, xs)
21+
22+
transparent def _size(xs: Tuple): Int = xs match {
23+
case Empty => 0
24+
case _ *: xs1 => _size(xs1) + 1
25+
}
26+
27+
transparent def _index(xs: Tuple, n: Int): Any = xs match {
28+
case x *: _ if n == 0 => x
29+
case _ *: xs1 if n > 0 => _index(xs1, n - 1)
30+
}
31+
32+
class TupleOps(val xs: Tuple) extends AnyVal {
33+
34+
transparent def *: [H] (x: H): Tuple = new *:(x, xs)
35+
transparent def size: Int = _size(xs)
36+
37+
transparent def apply(n: Int): Any = {
38+
erased val typed = Typed(_index(xs, n))
39+
val result = _size(xs) match {
40+
case 1 =>
41+
n match {
42+
case 1 => xs.asInstanceOf[Tuple1[_]].__1
43+
}
44+
case 2 =>
45+
n match {
46+
case 1 => xs.asInstanceOf[Tuple2[_, _]].__1
47+
case 2 => xs.asInstanceOf[Tuple2[_, _]].__2
48+
}
49+
case 3 =>
50+
n match {
51+
case 1 => xs.asInstanceOf[Tuple3[_, _, _]].__1
52+
case 2 => xs.asInstanceOf[Tuple3[_, _, _]].__2
53+
case 3 => xs.asInstanceOf[Tuple3[_, _, _]].__3
54+
}
55+
case 4 =>
56+
n match {
57+
case 1 => xs.asInstanceOf[Tuple4[_, _, _, _]].__1
58+
case 2 => xs.asInstanceOf[Tuple4[_, _, _, _]].__2
59+
case 3 => xs.asInstanceOf[Tuple4[_, _, _, _]].__3
60+
case 4 => xs.asInstanceOf[Tuple4[_, _, _, _]].__4
61+
}
62+
}
63+
result.asInstanceOf[typed.Type]
64+
}
65+
transparent def **: (ys: Tuple): Tuple = ys match {
66+
case Empty => xs
67+
case y *: ys1 => y *: (ys1 **: xs)
68+
}
69+
transparent def head = xs match {
70+
case x *: _ => x
71+
}
72+
transparent def tail = xs match {
73+
case _ *: xs => xs
74+
}
75+
}
76+
77+
val emptyArray = Array[Object]()
78+
79+
transparent def toObj(t: Any) = t.asInstanceOf[Object]
80+
81+
transparent def toArray(t: Tuple): Array[Object] = t.size match {
82+
case 0 => emptyArray
83+
case 1 => Array(toObj(t(0)))
84+
case 2 => Array(toObj(t(0)), toObj(t(1)))
85+
case 3 => Array(toObj(t(0)), toObj(t(1)), toObj(t(2)))
86+
case 4 => Array(toObj(t(0)), toObj(t(1)), toObj(t(2)), toObj(t(3)))
87+
}
88+
89+
transparent implicit def tupleDeco(xs: Tuple): TupleOps = new TupleOps(xs)
90+
91+
transparent def apply(): Tuple = Empty
92+
transparent def apply(x1: Any): Tuple = x1 *: Empty
93+
transparent def apply(x1: Any, x2: Any) = x1 *: x2 *: Empty
94+
transparent def apply(x1: Any, x2: Any, x3: Any) = x1 *: x2 *: x3 *: Empty
95+
96+
val xs0 = Tuple()
97+
val xs1 = Tuple(2)
98+
val xs2 = Tuple(2, "a")
99+
val xs3 = Tuple(true, 1, 2.0)
100+
transparent val s0 = xs0.size; val s0c: 0 = s0
101+
transparent val s1 = xs1.size; val s1c: 1 = s1
102+
transparent val s2 = xs2.size; val s2c: 2 = s2
103+
transparent val s3 = xs3.size; val s3c: 3 = s3
104+
val e0 = xs3(0); val e0c: Boolean = e0
105+
val e1 = xs3(1); val e1c: Int = e1
106+
val e2 = xs3(2); val e2c: Double = e2
107+
108+
val conc0 = xs0 **: xs3
109+
val conc1 = xs3 **: xs0
110+
val conc2 = xs2 **: xs3
111+
val e3c: Int = conc0(1)
112+
val e4c: Int = conc1(1)
113+
val e5c: Int = conc2(0)
114+
val e6c: Double = conc2(4)
115+
116+
}
117+
118+
class Tuple1[+T1](val __1: T1) extends *:(__1, Empty)
119+
class Tuple2[+T1, +T2](val __1: T1, val __2: T2) extends *:(__1, *:(__2, Empty))
120+
class Tuple3[+T1, +T2, +T3](val __1: T1, val __2: T2, val __3: T3) extends *:(__1, *:(__2, *:(__3, Empty)))
121+
class Tuple4[+T1, +T2, +T3, +T4](val __1: T1, val __2: T2, val __3: T3, val __4: T4) extends *:(__1, *:(__2, *:(__3, *:(__4, Empty))))
122+
123+
}
124+
125+
object Test extends App

0 commit comments

Comments
 (0)