Skip to content

Commit f3dacf9

Browse files
committed
Fix of scala#34
The root cause of scala#34 was that we took a type argument which was an existential type. These are returned as type bounds, which make no sense in the calling context. To avoid that problem in the future, `typeArgs` got renamed to `argInfos`, so it is clear we get an info, not necessarily a value type. There are also added method `argTypes`, `argTypesLo`, `argTypesHi`, which return a type, but either throw an exception or return a lower/upper approximation of the argument is an existential type. There's another issue that the existential type only arose when compiling the same couple fo files the seciond time. We need to chase that one down separately.
1 parent f0d5662 commit f3dacf9

11 files changed

+88
-33
lines changed

src/dotty/tools/dotc/ast/CheckTrees.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ object CheckTrees {
135135
check(finalizer.isTerm)
136136
check(handler.isTerm)
137137
check(handler.tpe derivesFrom defn.FunctionClass(1))
138-
check(handler.tpe.baseTypeArgs(defn.FunctionClass(1)).head <:< defn.ThrowableType)
138+
check(handler.tpe.baseArgInfos(defn.FunctionClass(1)).head <:< defn.ThrowableType)
139139
case Throw(expr) =>
140140
check(expr.isValue)
141141
check(expr.tpe.derivesFrom(defn.ThrowableClass))
@@ -210,9 +210,9 @@ object CheckTrees {
210210
check(args.isEmpty)
211211
else {
212212
check(rtp isRef defn.OptionClass)
213-
val normArgs = rtp.typeArgs match {
213+
val normArgs = rtp.argTypesHi match {
214214
case optionArg :: Nil =>
215-
optionArg.typeArgs match {
215+
optionArg.argTypesHi match {
216216
case Nil =>
217217
optionArg :: Nil
218218
case tupleArgs if defn.isTupleType(optionArg) =>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
336336

337337
/** new C(args) */
338338
def New(tp: Type, args: List[Tree])(implicit ctx: Context): Apply = {
339-
val targs = tp.typeArgs
339+
val targs = tp.argTypes
340340
Apply(
341341
Select(
342342
New(tp withoutArgs targs),

src/dotty/tools/dotc/ast/untpd.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ object untpd extends Trees.Instance[Untyped] with TreeInfo[Untyped] {
124124
case TypedSplice(AppliedTypeTree(tycon, targs)) =>
125125
(TypedSplice(tycon), targs map TypedSplice)
126126
case TypedSplice(tpt1: Tree) =>
127-
val argTypes = tpt1.tpe.typeArgs
127+
val argTypes = tpt1.tpe.argTypes
128128
val tycon = tpt1.tpe.withoutArgs(argTypes)
129129
def wrap(tpe: Type) = TypeTree(tpe) withPos tpt.pos
130130
(wrap(tycon), argTypes map wrap)

src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ class Definitions {
286286
def unapply(ft: Type): Option[(List[Type], Type)] = { // Dotty deviation: Type annotation needed because inferred type
287287
// is Some[(List[Type], Type)] | None, which is not a legal unapply type.
288288
val tsym = ft.typeSymbol
289-
lazy val targs = ft.typeArgs
289+
lazy val targs = ft.argInfos
290290
if ((FunctionClasses contains tsym) &&
291291
(targs.length - 1 <= MaxFunctionArity) &&
292292
(FunctionClass(targs.length - 1) == tsym)) Some((targs.init, targs.last)) // Dotty deviation: no auto-tupling
@@ -317,7 +317,7 @@ class Definitions {
317317
lazy val RootImports = List[Symbol](JavaLangPackageVal, ScalaPackageVal, ScalaPredefModule, DottyPredefModule)
318318

319319
def isTupleType(tp: Type) = {
320-
val arity = tp.dealias.typeArgs.length
320+
val arity = tp.dealias.argInfos.length
321321
arity <= MaxTupleArity && (tp isRef TupleClass(arity))
322322
}
323323

@@ -329,7 +329,7 @@ class Definitions {
329329
0 <= arity && arity <= MaxFunctionArity && (tp isRef FunctionClass(arity))
330330
}
331331

332-
def functionArity(tp: Type) = tp.dealias.typeArgs.length - 1
332+
def functionArity(tp: Type) = tp.dealias.argInfos.length - 1
333333

334334
// ----- Higher kinds machinery ------------------------------------------
335335

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

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,29 @@ import Flags._
1212
import util.Positions.Position
1313
import collection.mutable
1414

15+
object TypeApplications {
16+
17+
/** Assert type is not a TypeBounds instance and return it unchanged */
18+
val noBounds = (tp: Type) => tp match {
19+
case tp: TypeBounds => throw new AssertionError("no TypeBounds allowed")
20+
case _ => tp
21+
}
22+
23+
/** If `tp` is a TypeBounds instance return its lower bound else return `tp` */
24+
val boundsToLo = (tp: Type) => tp match {
25+
case tp: TypeBounds => tp.lo
26+
case _ => tp
27+
}
28+
29+
/** If `tp` is a TypeBounds instance return its upper bound else return `tp` */
30+
val boundsToHi = (tp: Type) => tp match {
31+
case tp: TypeBounds => tp.hi
32+
case _ => tp
33+
}
34+
}
35+
36+
import TypeApplications._
37+
1538
/** A decorator that provides methods for modeling type application */
1639
class TypeApplications(val self: Type) extends AnyVal {
1740

@@ -135,24 +158,43 @@ class TypeApplications(val self: Type) extends AnyVal {
135158
else TypeAlias(self, v)
136159
}
137160

138-
/** The type arguments of the base type instance wrt `base` of this type */
139-
final def baseTypeArgs(base: Symbol)(implicit ctx: Context): List[Type] =
161+
/** The type arguments of this type's base type instance wrt.`base`.
162+
* Existential types in arguments are returned as TypeBounds instances.
163+
*/
164+
final def baseArgInfos(base: Symbol)(implicit ctx: Context): List[Type] =
140165
if (self derivesFrom base)
141-
base.typeParams map (param => self.member(param.name).info.argType(param))
166+
base.typeParams map (param => self.member(param.name).info.argInfo(param))
142167
else
143168
Nil
144169

170+
/** The type arguments of this type's base type instance wrt.`base`.
171+
* Existential types in arguments are disallowed.
172+
*/
173+
final def baseArgTypes(base: Symbol)(implicit ctx: Context): List[Type] = baseArgInfos(base) mapConserve noBounds
174+
175+
/** The type arguments of this type's base type instance wrt.`base`.
176+
* Existential types in arguments are approximanted by their lower bound.
177+
*/
178+
final def baseArgTypesLo(base: Symbol)(implicit ctx: Context): List[Type] = baseArgInfos(base) mapConserve boundsToLo
179+
180+
/** The type arguments of this type's base type instance wrt.`base`.
181+
* Existential types in arguments are approximanted by their upper bound.
182+
*/
183+
final def baseArgTypesHi(base: Symbol)(implicit ctx: Context): List[Type] = baseArgInfos(base) mapConserve boundsToHi
184+
145185
/** The first type argument of the base type instance wrt `base` of this type */
146-
final def firstBaseTypeArg(base: Symbol)(implicit ctx: Context): Type = base.typeParams match {
186+
final def firstBaseArgInfo(base: Symbol)(implicit ctx: Context): Type = base.typeParams match {
147187
case param :: _ if self derivesFrom base =>
148-
self.member(param.name).info.argType(param)
188+
self.member(param.name).info.argInfo(param)
149189
case _ =>
150190
NoType
151191
}
152192

153-
/** The base type including all type arguments of this type */
193+
/** The base type including all type arguments of this type.
194+
* Existential types in arguments are returned as TypeBounds instances.
195+
*/
154196
final def baseTypeWithArgs(base: Symbol)(implicit ctx: Context): Type =
155-
self.baseTypeRef(base).appliedTo(baseTypeArgs(base))
197+
self.baseTypeRef(base).appliedTo(baseArgInfos(base))
156198

157199
/** Translate a type of the form From[T] to To[T], keep other types as they are.
158200
* `from` and `to` must be static classes, both with one type parameter, and the same variance.
@@ -163,9 +205,10 @@ class TypeApplications(val self: Type) extends AnyVal {
163205
else self
164206

165207
/** If this is an encoding of a (partially) applied type, return its arguments,
166-
* otherwise return Nil
208+
* otherwise return Nil.
209+
* Existential types in arguments are returned as TypeBounds instances.
167210
*/
168-
final def typeArgs(implicit ctx: Context): List[Type] = {
211+
final def argInfos(implicit ctx: Context): List[Type] = {
169212
var tparams: List[TypeSymbol] = null
170213
def recur(tp: Type, refineCount: Int): mutable.ListBuffer[Type] = tp.stripTypeVar match {
171214
case tp @ RefinedType(tycon, name) =>
@@ -175,7 +218,7 @@ class TypeApplications(val self: Type) extends AnyVal {
175218
if (tparams == null) tparams = tycon.typeParams
176219
if (buf.size < tparams.length) {
177220
val tparam = tparams(buf.size)
178-
if (name == tparam.name) buf += tp.refinedInfo.argType(tparam)
221+
if (name == tparam.name) buf += tp.refinedInfo.argInfo(tparam)
179222
else null
180223
} else null
181224
}
@@ -187,6 +230,15 @@ class TypeApplications(val self: Type) extends AnyVal {
187230
if (buf == null) Nil else buf.toList
188231
}
189232

233+
/** Argument types where existential types in arguments are disallowed */
234+
def argTypes(implicit ctx: Context) = argInfos mapConserve noBounds
235+
236+
/** Argument types where existential types in arguments are approximated by their lower bound */
237+
def argTypesLo(implicit ctx: Context) = argInfos mapConserve boundsToLo
238+
239+
/** Argument types where existential types in arguments are approximated by their upper bound */
240+
def argTypesHi(implicit ctx: Context) = argInfos mapConserve boundsToHi
241+
190242
/** The core type without any type arguments.
191243
* @param `typeArgs` must be the type arguments of this type.
192244
*/
@@ -201,7 +253,7 @@ class TypeApplications(val self: Type) extends AnyVal {
201253
/** If this is the image of a type argument to type parameter `tparam`,
202254
* recover the type argument, otherwise NoType.
203255
*/
204-
final def argType(tparam: Symbol)(implicit ctx: Context): Type = self match {
256+
final def argInfo(tparam: Symbol)(implicit ctx: Context): Type = self match {
205257
case TypeBounds(lo, hi) =>
206258
if (lo eq hi) hi
207259
else {
@@ -216,7 +268,7 @@ class TypeApplications(val self: Type) extends AnyVal {
216268

217269
/** The element type of a sequence or array */
218270
def elemType(implicit ctx: Context): Type =
219-
firstBaseTypeArg(defn.SeqClass) orElse firstBaseTypeArg(defn.ArrayClass)
271+
firstBaseArgInfo(defn.SeqClass) orElse firstBaseArgInfo(defn.ArrayClass)
220272

221273
/** If this type is of the normalized form Array[...[Array[T]...]
222274
* return the number of Array wrappers and T.
@@ -225,7 +277,7 @@ class TypeApplications(val self: Type) extends AnyVal {
225277
final def splitArray(implicit ctx: Context): (Int, Type) = {
226278
def recur(n: Int, tp: Type): (Int, Type) = tp.stripTypeVar match {
227279
case RefinedType(tycon, _) if tycon isRef defn.ArrayClass =>
228-
tp.typeArgs match {
280+
tp.argInfos match {
229281
case arg :: Nil => recur(n + 1, arg)
230282
case _ => (n, tp)
231283
}
@@ -274,7 +326,7 @@ class TypeApplications(val self: Type) extends AnyVal {
274326

275327
val correspondingParamName: Map[Symbol, TypeName] = {
276328
for {
277-
(tparam, targ: TypeRef) <- cls.typeParams zip typeArgs
329+
(tparam, targ: TypeRef) <- cls.typeParams zip argInfos
278330
if boundSyms contains targ.symbol
279331
} yield targ.symbol -> tparam.name
280332
}.toMap

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ class TypeComparer(initctx: Context) extends DotClass {
616616
*/
617617
def isSubTypeHK(tp1: Type, tp2: Type): Boolean = {
618618
val tparams = tp1.typeParams
619-
val hkArgs = tp2.typeArgs
619+
val hkArgs = tp2.argInfos
620620
(hkArgs.length == tparams.length) && {
621621
val base = tp1.narrow
622622
(tparams, hkArgs).zipped.forall { (tparam, hkArg) =>
@@ -752,7 +752,7 @@ class TypeComparer(initctx: Context) extends DotClass {
752752
/** The least upper bound of two types
753753
* @note We do not admit singleton types in or-types as lubs.
754754
*/
755-
def lub(tp1: Type, tp2: Type): Type =
755+
def lub(tp1: Type, tp2: Type): Type = /*>|>*/ ctx.traceIndented(s"lub(${tp1.show}, ${tp2.show})", typr, show = true) /*<|<*/ {
756756
if (tp1 eq tp2) tp1
757757
else if (!tp1.exists) tp1
758758
else if (!tp2.exists) tp2
@@ -772,6 +772,7 @@ class TypeComparer(initctx: Context) extends DotClass {
772772
}
773773
}
774774
}
775+
}
775776

776777
/** The least upper bound of a list of types */
777778
final def lub(tps: List[Type]): Type =

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ object Types {
9696
else thissym eq sym
9797
case this1: RefinedType =>
9898
// make sure all refinements are type arguments
99-
this1.parent.isRef(sym) && this.typeArgs.nonEmpty
99+
this1.parent.isRef(sym) && this.argInfos.nonEmpty
100100
case _ =>
101101
false
102102
}

src/dotty/tools/dotc/core/pickling/UnPickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ object UnPickler {
7676
case tp @ MethodType(paramNames, paramTypes) =>
7777
val lastArg = paramTypes.last
7878
assert(lastArg isRef defn.ArrayClass)
79-
val elemtp0 :: Nil = lastArg.baseTypeArgs(defn.ArrayClass)
79+
val elemtp0 :: Nil = lastArg.baseArgInfos(defn.ArrayClass)
8080
val elemtp = elemtp0 match {
8181
case AndType(t1, t2) if t1.typeSymbol.isAbstractType && (t2 isRef defn.ObjectClass) =>
8282
t1 // drop intersection with Object for abstract types in varargs. UnCurry can handle them.

src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
9696
}
9797
tp match {
9898
case tp: RefinedType =>
99-
val args = tp.typeArgs
99+
val args = tp.argInfos
100100
if (args.nonEmpty) {
101101
val tycon = tp.unrefine
102102
val cls = tycon.typeSymbol

src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import EtaExpansion._
2424
import collection.mutable
2525
import reflect.ClassTag
2626
import config.Printers._
27+
import TypeApplications._
2728
import language.implicitConversions
2829

2930
object Applications {
@@ -266,7 +267,7 @@ trait Applications extends Compatibility { self: Typer =>
266267
case arg :: Nil if isVarArg(arg) =>
267268
addTyped(arg, formal)
268269
case _ =>
269-
val elemFormal = formal.typeArgs.head
270+
val elemFormal = formal.argTypesLo.head
270271
args foreach (addTyped(_, elemFormal))
271272
makeVarArg(args.length, elemFormal)
272273
}
@@ -609,7 +610,7 @@ trait Applications extends Compatibility { self: Typer =>
609610
if (extractorMemberType(unapplyResult, nme.isDefined) isRef defn.BooleanClass) {
610611
if (getTp.exists)
611612
if (unapply.symbol.name == nme.unapplySeq) {
612-
val seqArg = getTp.firstBaseTypeArg(defn.SeqClass)
613+
val seqArg = boundsToHi(getTp.firstBaseArgInfo(defn.SeqClass))
613614
if (seqArg.exists) return args map Function.const(seqArg)
614615
}
615616
else return getSelectors(getTp)
@@ -683,6 +684,7 @@ trait Applications extends Compatibility { self: Typer =>
683684
}
684685

685686
var argTypes = unapplyArgs(unapplyApp.tpe)
687+
for (argType <- argTypes) assert(!argType.isInstanceOf[TypeBounds], unapplyApp.tpe.show)
686688
val bunchedArgs = argTypes match {
687689
case argType :: Nil if argType.isRepeatedParam => untpd.SeqLiteral(args) :: Nil
688690
case _ => args
@@ -770,7 +772,7 @@ trait Applications extends Compatibility { self: Typer =>
770772
val tparams = ctx.newTypeParams(alt1.symbol.owner, tp1.paramNames, EmptyFlags, bounds)
771773
isAsSpecific(alt1, tp1.instantiate(tparams map (_.typeRef)), alt2, tp2)
772774
case tp1: MethodType =>
773-
def repeatedToSingle(tp: Type) = if (tp.isRepeatedParam) tp.typeArgs.head else tp
775+
def repeatedToSingle(tp: Type) = if (tp.isRepeatedParam) tp.argTypesHi.head else tp
774776
isApplicable(alt2, tp1.paramTypes map repeatedToSingle, WildcardType) ||
775777
tp1.paramTypes.isEmpty && tp2.isInstanceOf[MethodOrPoly]
776778
case _ =>

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ class Typer extends Namer with Applications with Implicits {
438438
}
439439

440440
def typedPair(tree: untpd.Pair, pt: Type)(implicit ctx: Context) = track("typedPair") {
441-
val (leftProto, rightProto) = pt.typeArgs match {
441+
val (leftProto, rightProto) = pt.argTypesLo match {
442442
case l :: r :: Nil if pt isRef defn.PairClass => (l, r)
443443
case _ => (WildcardType, WildcardType)
444444
}
@@ -561,7 +561,7 @@ class Typer extends Namer with Applications with Implicits {
561561
val params = args.asInstanceOf[List[untpd.ValDef]]
562562
val (protoFormals, protoResult): (List[Type], Type) = pt match {
563563
case _ if defn.isFunctionType(pt) =>
564-
(pt.dealias.typeArgs.init, pt.dealias.typeArgs.last)
564+
(pt.dealias.argInfos.init, pt.dealias.argInfos.last)
565565
case SAMType(meth) =>
566566
val mt @ MethodType(_, paramTypes) = meth.info
567567
(paramTypes, mt.resultType)
@@ -750,7 +750,7 @@ class Typer extends Namer with Applications with Implicits {
750750
val expr1 = typed(tree.expr, pt)
751751
val handler1 = typed(tree.handler, defn.FunctionType(defn.ThrowableType :: Nil, pt))
752752
val finalizer1 = typed(tree.finalizer, defn.UnitType)
753-
val handlerTypeArgs = handler1.tpe.baseTypeArgs(defn.FunctionClass(1))
753+
val handlerTypeArgs = handler1.tpe.baseArgTypesHi(defn.FunctionClass(1))
754754
val ownType = if (handlerTypeArgs.nonEmpty) expr1.tpe | handlerTypeArgs(1) else expr1.tpe
755755
cpy.Try(tree, expr1, handler1, finalizer1) withType ownType
756756
}

0 commit comments

Comments
 (0)