diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 203ab7624835..364846d3d782 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -76,7 +76,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def seq(stats: List[Tree], expr: Tree)(implicit ctx: Context): Tree = if (stats.isEmpty) expr else expr match { - case Block(estats, eexpr) => cpy.Block(expr)(stats ::: estats, eexpr) + case Block(estats, eexpr) => + cpy.Block(expr)(stats ::: estats, eexpr).withType(ta.avoidingType(eexpr, stats)) case _ => Block(stats, expr) } diff --git a/compiler/src/dotty/tools/dotc/core/ParamInfo.scala b/compiler/src/dotty/tools/dotc/core/ParamInfo.scala index 46e378fc2560..ba28e3bc2efc 100644 --- a/compiler/src/dotty/tools/dotc/core/ParamInfo.scala +++ b/compiler/src/dotty/tools/dotc/core/ParamInfo.scala @@ -27,7 +27,7 @@ trait ParamInfo { * For type lambda parameters, it's the same as `paramInfos` as * `asSeenFrom` has already been applied to the whole type lambda. */ - def paramInfoAsSeenFrom(pre: Type)(implicit ctx: Context): Type + def paramInfoAsSeenFrom(prefix: Type)(implicit ctx: Context): Type /** The parameter bounds, or the completer if the type parameter * is an as-yet uncompleted symbol. diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 75732475ac73..da1554fb9d67 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -168,14 +168,18 @@ class TypeApplications(val self: Type) extends AnyVal { * any type parameter that is-rebound by the refinement. */ final def typeParams(implicit ctx: Context): List[TypeParamInfo] = /*>|>*/ track("typeParams") /*<|<*/ { + def isTrivial(prefix: Type, tycon: Symbol) = prefix match { + case prefix: ThisType => prefix.cls `eq` tycon.owner + case NoPrefix => true + case _ => false + } try self match { case self: TypeRef => val tsym = self.symbol if (tsym.isClass) tsym.typeParams - else if (!tsym.exists) self.info.typeParams else tsym.infoOrCompleter match { - case info: LazyType => info.completerTypeParams(tsym) - case info => info.typeParams + case info: LazyType if isTrivial(self.prefix, tsym) => info.completerTypeParams(tsym) + case _ => self.info.typeParams } case self: AppliedType => if (self.tycon.typeSymbol.isClass) Nil diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 0d1d29008300..f0136716a9ab 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3195,7 +3195,7 @@ object Types { def isTypeParam(implicit ctx: Context) = tl.paramNames.head.isTypeName def paramName(implicit ctx: Context) = tl.paramNames(n) def paramInfo(implicit ctx: Context) = tl.paramInfos(n) - def paramInfoAsSeenFrom(pre: Type)(implicit ctx: Context) = paramInfo.asSeenFrom(pre, pre.classSymbol) + def paramInfoAsSeenFrom(pre: Type)(implicit ctx: Context) = paramInfo def paramInfoOrCompleter(implicit ctx: Context): Type = paramInfo def paramVariance(implicit ctx: Context): Int = tl.paramNames(n).variance def paramRef(implicit ctx: Context): Type = tl.paramRefs(n) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 51d9280efbc6..a09433adb627 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1238,9 +1238,10 @@ class Typer extends Namer args = args.take(tparams.length) } def typedArg(arg: untpd.Tree, tparam: ParamInfo) = { + def tparamBounds = tparam.paramInfoAsSeenFrom(tpt1.tpe.appliedTo(tparams.map(_ => TypeBounds.empty))) val (desugaredArg, argPt) = if (ctx.mode is Mode.Pattern) - (if (untpd.isVarPattern(arg)) desugar.patternVar(arg) else arg, tparam.paramInfo) + (if (untpd.isVarPattern(arg)) desugar.patternVar(arg) else arg, tparamBounds) else (arg, WildcardType) if (tpt1.symbol.isClass) @@ -1259,10 +1260,10 @@ class Typer extends Namer // An unbounded `_` automatically adapts to type parameter bounds. This means: // If we have wildcard application C[_], where `C` is a class replace // with C[_ >: L <: H] where `L` and `H` are the bounds of the corresponding - // type parameter in `C`, avoiding any referemces to parameters of `C`. - // The transform does not apply for patters, where empty bounds translate to + // type parameter in `C`. + // The transform does not apply for patterns, where empty bounds translate to // wildcard identifiers `_` instead. - res = res.withType(avoid(tparam.paramInfo, tpt1.tpe.typeParamSymbols)) + res = res.withType(tparamBounds) case _ => } res diff --git a/tests/pos/i4884.scala b/tests/pos/i4884.scala new file mode 100644 index 000000000000..0270bbe8129f --- /dev/null +++ b/tests/pos/i4884.scala @@ -0,0 +1,48 @@ +object Test { + trait A + trait B + trait TestConstructor1 { type F[X <: A] <: TestConstructor2[A] } + trait TestConstructor2[D] { + type F[_ <: D] + class G[X <: D] + trait TestConstructor3[E] { + type G[X <: D & E] <: TestConstructor2.this.F[X] & H[X] + class H[X <: D & E] { + type A <: G[X] + } + } + } + trait TestConstructor4[D] { + trait TestConstructor5[E] { + trait MSetLike[X <: D & E, This <: MSet[X] with MSetLike[X, This]] + trait MSet[X <: D & E] extends MSetLike[X, MSet[X]] + } + } + + val v1: TestConstructor1 => Unit = { f => + type P[a <: A] = f.F[a] + } + + val v2: TestConstructor2[A] => Unit = { f => + type P[a <: A] = f.F[a] + } + + def f2(f: TestConstructor2[A]): Unit = { + type P[a <: A] = f.F[a] + } + + type C = A & B + def f3(f: TestConstructor2[A], g: f.TestConstructor3[B]): Unit = { + type P1[a <: A] = f.F[a] + type P2[a <: A] = f.G[a] + type Q1[c <: C] = g.G[c] + type Q2[c <: C] = g.H[c] + type R1[c <: C] = f.G[c] & g.H[c] + type R2[c <: C] = f.G[c] | g.H[c] + type S1[c <: C] = ([X <: C] => f.F[X] & g.G[X])[c] + type S2[c <: C] = ([X <: C] => f.F[X] | g.G[X])[c] + } + def f3(f: TestConstructor4[A], g: f.TestConstructor5[B]): Unit = { + type P1[c <: C] = g.MSet[c] + } +} diff --git a/tests/run/Tuple.scala b/tests/run/Tuple.scala index 34eadf2b45bc..a40afd5bae29 100644 --- a/tests/run/Tuple.scala +++ b/tests/run/Tuple.scala @@ -1,38 +1,81 @@ import annotation.showAsInfix +object typelevel { + erased def erasedValue[T]: T = ??? + class Typed[T](val value: T) { type Type = T } +} + sealed trait Tuple +object Empty extends Tuple -object Tuple { - object Empty extends Tuple +@showAsInfix +final case class *: [H, T <: Tuple](hd: H, tl: T) extends Tuple +object Tuple { + import typelevel._ type Empty = Empty.type - @showAsInfix - final case class *: [H, T <: Tuple](hd: H, tl: T) extends Tuple + class TupleOps(val xs: Tuple) extends AnyVal { + transparent def *: [H] (x: H): Tuple = new *:(x, xs) + transparent def size: Int = xs match { + case Empty => 0 + case _ *: xs1 => xs1.size + 1 + } + transparent def apply(n: Int): Any = xs match { + case x *: _ if n == 0 => x + case _ *: xs1 if n > 0 => xs1.apply(n - 1) + } + transparent def **: (ys: Tuple): Tuple = ys match { + case Empty => xs + case y *: ys1 => y *: (ys1 **: xs) + } + transparent def head = xs match { + case x *: _ => x + } + transparent def tail = xs match { + case _ *: xs => xs + } + } - class HListDeco(val xs: Tuple) extends AnyVal { - transparent def *: [H] (x: H): Tuple = Tuple.*:.apply(x, xs) + val emptyArray = Array[Object]() - transparent def size: Int = Tuple.size(xs) - } + transparent def toObj(t: Any) = t.asInstanceOf[Object] - transparent def size(xs: Tuple): Int = xs match { - case Empty => 0 - case _ *: xs1 => size(xs1) + 1 + transparent def toArray(t: Tuple): Array[Object] = t.size match { + case 0 => emptyArray + case 1 => Array(toObj(t(0))) + case 2 => Array(toObj(t(0)), toObj(t(1))) + case 3 => Array(toObj(t(0)), toObj(t(1)), toObj(t(2))) + case 4 => Array(toObj(t(0)), toObj(t(1)), toObj(t(2)), toObj(t(3))) } - transparent implicit def hlistDeco(xs: Tuple): HListDeco = new HListDeco(xs) + transparent implicit def tupleDeco(xs: Tuple): TupleOps = new TupleOps(xs) transparent def apply(): Tuple = Empty transparent def apply(x1: Any): Tuple = x1 *: Empty transparent def apply(x1: Any, x2: Any) = x1 *: x2 *: Empty + transparent def apply(x1: Any, x2: Any, x3: Any) = x1 *: x2 *: x3 *: Empty val xs0 = Tuple() val xs1 = Tuple(2) val xs2 = Tuple(2, "a") - val s0 = xs0.size - val s1 = xs1.size - val s2 = xs2.size + val xs3 = Tuple(true, 1, 2.0) + transparent val s0 = xs0.size; val s0c: 0 = s0 + transparent val s1 = xs1.size; val s1c: 1 = s1 + transparent val s2 = xs2.size; val s2c: 2 = s2 + transparent val s3 = xs3.size; val s3c: 3 = s3 + val e0 = xs3(0); val e0c: Boolean = e0 + val e1 = xs3(1); val e1c: Int = e1 + val e2 = xs3(2); val e2c: Double = e2 + + val conc0 = xs0 **: xs3 + val conc1 = xs3 **: xs0 + val conc2 = xs2 **: xs3 + val e3c: Int = conc0(1) + val e4c: Int = conc1(1) + val e5c: Int = conc2(0) + val e6c: Double = conc2(4) + } object Test extends App \ No newline at end of file diff --git a/tests/run/TupleImpl.scala b/tests/run/TupleImpl.scala new file mode 100644 index 000000000000..3d382f99038b --- /dev/null +++ b/tests/run/TupleImpl.scala @@ -0,0 +1,125 @@ +package test { + +import annotation.showAsInfix + +object typelevel { + erased def erasedValue[T]: T = ??? + case class Typed[T](val value: T) { type Type = T } +} + +sealed trait Tuple +object Empty extends Tuple + +@showAsInfix +case class *: [+H, +T <: Tuple](hd: H, tl: T) extends Tuple + +object Tuple { + import typelevel._ + type Empty = Empty.type + + transparent def _cons[H, T <: Tuple] (x: H, xs: T): Tuple = new *:(x, xs) + + transparent def _size(xs: Tuple): Int = xs match { + case Empty => 0 + case _ *: xs1 => _size(xs1) + 1 + } + + transparent def _index(xs: Tuple, n: Int): Any = xs match { + case x *: _ if n == 0 => x + case _ *: xs1 if n > 0 => _index(xs1, n - 1) + } + + class TupleOps(val xs: Tuple) extends AnyVal { + + transparent def *: [H] (x: H): Tuple = new *:(x, xs) + transparent def size: Int = _size(xs) + + transparent def apply(n: Int): Any = { + erased val typed = Typed(_index(xs, n)) + val result = _size(xs) match { + case 1 => + n match { + case 1 => xs.asInstanceOf[Tuple1[_]].__1 + } + case 2 => + n match { + case 1 => xs.asInstanceOf[Tuple2[_, _]].__1 + case 2 => xs.asInstanceOf[Tuple2[_, _]].__2 + } + case 3 => + n match { + case 1 => xs.asInstanceOf[Tuple3[_, _, _]].__1 + case 2 => xs.asInstanceOf[Tuple3[_, _, _]].__2 + case 3 => xs.asInstanceOf[Tuple3[_, _, _]].__3 + } + case 4 => + n match { + case 1 => xs.asInstanceOf[Tuple4[_, _, _, _]].__1 + case 2 => xs.asInstanceOf[Tuple4[_, _, _, _]].__2 + case 3 => xs.asInstanceOf[Tuple4[_, _, _, _]].__3 + case 4 => xs.asInstanceOf[Tuple4[_, _, _, _]].__4 + } + } + result.asInstanceOf[typed.Type] + } + transparent def **: (ys: Tuple): Tuple = ys match { + case Empty => xs + case y *: ys1 => y *: (ys1 **: xs) + } + transparent def head = xs match { + case x *: _ => x + } + transparent def tail = xs match { + case _ *: xs => xs + } + } + + val emptyArray = Array[Object]() + + transparent def toObj(t: Any) = t.asInstanceOf[Object] + + transparent def toArray(t: Tuple): Array[Object] = t.size match { + case 0 => emptyArray + case 1 => Array(toObj(t(0))) + case 2 => Array(toObj(t(0)), toObj(t(1))) + case 3 => Array(toObj(t(0)), toObj(t(1)), toObj(t(2))) + case 4 => Array(toObj(t(0)), toObj(t(1)), toObj(t(2)), toObj(t(3))) + } + + transparent implicit def tupleDeco(xs: Tuple): TupleOps = new TupleOps(xs) + + transparent def apply(): Tuple = Empty + transparent def apply(x1: Any): Tuple = x1 *: Empty + transparent def apply(x1: Any, x2: Any) = x1 *: x2 *: Empty + transparent def apply(x1: Any, x2: Any, x3: Any) = x1 *: x2 *: x3 *: Empty + + val xs0 = Tuple() + val xs1 = Tuple(2) + val xs2 = Tuple(2, "a") + val xs3 = Tuple(true, 1, 2.0) + transparent val s0 = xs0.size; val s0c: 0 = s0 + transparent val s1 = xs1.size; val s1c: 1 = s1 + transparent val s2 = xs2.size; val s2c: 2 = s2 + transparent val s3 = xs3.size; val s3c: 3 = s3 + val e0 = xs3(0); val e0c: Boolean = e0 + val e1 = xs3(1); val e1c: Int = e1 + val e2 = xs3(2); val e2c: Double = e2 + + val conc0 = xs0 **: xs3 + val conc1 = xs3 **: xs0 + val conc2 = xs2 **: xs3 + val e3c: Int = conc0(1) + val e4c: Int = conc1(1) + val e5c: Int = conc2(0) + val e6c: Double = conc2(4) + +} + +class Tuple1[+T1](val __1: T1) extends *:(__1, Empty) +class Tuple2[+T1, +T2](val __1: T1, val __2: T2) extends *:(__1, *:(__2, Empty)) +class Tuple3[+T1, +T2, +T3](val __1: T1, val __2: T2, val __3: T3) extends *:(__1, *:(__2, *:(__3, Empty))) +class Tuple4[+T1, +T2, +T3, +T4](val __1: T1, val __2: T2, val __3: T3, val __4: T4) extends *:(__1, *:(__2, *:(__3, *:(__4, Empty)))) + +} + +object Test extends App \ No newline at end of file