1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
|
package scala
package reflect
package internal
package tpe
import scala.collection.mutable
import scala.annotation.tailrec
import util.Statistics
import Variance._
private[internal] trait GlbLubs {
self: SymbolTable =>
import definitions._
import TypesStats._
private final val printLubs = scala.sys.props contains "scalac.debug.lub"
private final val strictInference = settings.strictInference
/** In case anyone wants to turn off lub verification without reverting anything. */
private final val verifyLubs = true
private def printLubMatrix(btsMap: Map[Type, List[Type]], depth: Depth) {
import util.TableDef
import TableDef.Column
def str(tp: Type) = {
if (tp == NoType) ""
else {
val s = ("" + tp).replaceAll("""[\w.]+\.(\w+)""", "$1")
if (s.length < 60) s
else (s take 57) + "..."
}
}
val sorted = btsMap.toList.sortWith((x, y) => x._1.typeSymbol isLess y._1.typeSymbol)
val maxSeqLength = sorted.map(_._2.size).max
val padded = sorted map (_._2.padTo(maxSeqLength, NoType))
val transposed = padded.transpose
val columns: List[Column[List[Type]]] = mapWithIndex(sorted) {
case ((k, v), idx) =>
Column(str(k), (xs: List[Type]) => str(xs(idx)), left = true)
}
val tableDef = TableDef(columns: _*)
val formatted = tableDef.table(transposed)
println("** Depth is " + depth + "\n" + formatted)
}
/** From a list of types, find any which take type parameters
* where the type parameter bounds contain references to other
* any types in the list (including itself.)
*
* @return List of symbol pairs holding the recursive type
* parameter and the parameter which references it.
*/
def findRecursiveBounds(ts: List[Type]): List[(Symbol, Symbol)] = {
if (ts.isEmpty) Nil
else {
val sym = ts.head.typeSymbol
require(ts.tail forall (_.typeSymbol == sym), ts)
for (p <- sym.typeParams ; in <- sym.typeParams ; if in.info.bounds contains p) yield
p -> in
}
}
// only called when strictInference
private def willViolateRecursiveBounds(tp: Type, ts: List[Type], tsElimSub: List[Type]) = {
val typeSym = ts.head.typeSymbol // we're uniform, the `.head` is as good as any.
def fbounds = findRecursiveBounds(ts) map (_._2)
def isRecursive = typeSym.typeParams exists fbounds.contains
isRecursive && (transposeSafe(tsElimSub map (_.normalize.typeArgs)) match {
case Some(arggsTransposed) =>
val mergedTypeArgs = (tp match { case et: ExistentialType => et.underlying; case _ => tp}).typeArgs
exists3(typeSym.typeParams, mergedTypeArgs, arggsTransposed) {
(param, arg, lubbedArgs) =>
val isExistential = arg.typeSymbol.isExistentiallyBound
val isInFBound = fbounds contains param
val wasLubbed = !lubbedArgs.exists(_ =:= arg)
(!isExistential && isInFBound && wasLubbed)
}
case None => false
})
}
/** Given a matrix `tsBts` whose columns are basetype sequences (and the symbols `tsParams` that should be interpreted as type parameters in this matrix),
* compute its least sorted upwards closed upper bound relative to the following ordering <= between lists of types:
*
* xs <= ys iff forall y in ys exists x in xs such that x <: y
*
* @arg tsParams for each type in the original list of types `ts0`, its list of type parameters (if that type is a type constructor)
* (these type parameters may be referred to by type arguments in the BTS column of those types,
* and must be interpreted as bound variables; i.e., under a type lambda that wraps the types that refer to these type params)
* @arg tsBts a matrix whose columns are basetype sequences
* the first row is the original list of types for which we're computing the lub
* (except that type constructors have been applied to their dummyArgs)
* @See baseTypeSeq for a definition of sorted and upwards closed.
*/
def lubList(ts: List[Type], depth: Depth): List[Type] = {
var lubListDepth = Depth.Zero
// This catches some recursive situations which would otherwise
// befuddle us, e.g. pos/hklub0.scala
def isHotForTs(xs: List[Type]) = ts exists (_.typeParams == xs.map(_.typeSymbol))
def elimHigherOrderTypeParam(tp: Type) = tp match {
case TypeRef(_, _, args) if args.nonEmpty && isHotForTs(args) =>
logResult("Retracting dummies from " + tp + " in lublist")(tp.typeConstructor)
case _ => tp
}
// pretypes is a tail-recursion-preserving accumulator.
@tailrec
def loop(pretypes: List[Type], tsBts: List[List[Type]]): List[Type] = {
lubListDepth = lubListDepth.incr
if (tsBts.isEmpty || (tsBts exists typeListIsEmpty)) pretypes.reverse
else if (tsBts.tail.isEmpty) pretypes.reverse ++ tsBts.head
else {
// ts0 is the 1-dimensional frontier of symbols cutting through 2-dimensional tsBts.
// Invariant: all symbols "under" (closer to the first row) the frontier
// are smaller (according to _.isLess) than the ones "on and beyond" the frontier
val ts0 = tsBts map (_.head)
// Is the frontier made up of types with the same symbol?
val isUniformFrontier = (ts0: @unchecked) match {
case t :: ts => ts forall (_.typeSymbol == t.typeSymbol)
}
// Produce a single type for this frontier by merging the prefixes and arguments of those
// typerefs that share the same symbol: that symbol is the current maximal symbol for which
// the invariant holds, i.e., the one that conveys most information regarding subtyping. Before
// merging, strip targs that refer to bound tparams (when we're computing the lub of type
// constructors.) Also filter out all types that are a subtype of some other type.
if (isUniformFrontier) {
val tails = tsBts map (_.tail)
val ts1 = elimSub(ts0, depth) map elimHigherOrderTypeParam
mergePrefixAndArgs(ts1, Covariant, depth) match {
case NoType => loop(pretypes, tails)
case tp if strictInference && willViolateRecursiveBounds(tp, ts0, ts1) =>
log(s"Breaking recursion in lublist, advancing frontier and discarding merged prefix/args from $tp")
loop(pretypes, tails)
case tp =>
loop(tp :: pretypes, tails)
}
} else {
// frontier is not uniform yet, move it beyond the current minimal symbol;
// lather, rinse, repeat
val sym = minSym(ts0)
val newtps = tsBts map (ts => if (ts.head.typeSymbol == sym) ts.tail else ts)
if (printLubs) {
val str = (newtps.zipWithIndex map { case (tps, idx) =>
tps.map(" " + _ + "\n").mkString(" (" + idx + ")\n", "", "\n")
}).mkString("")
println("Frontier(\n" + str + ")")
printLubMatrix((ts zip tsBts).toMap, lubListDepth)
}
loop(pretypes, newtps)
}
}
}
val initialBTSes = ts map (_.baseTypeSeq.toList)
if (printLubs)
printLubMatrix((ts zip initialBTSes).toMap, depth)
loop(Nil, initialBTSes)
}
/** The minimal symbol of a list of types (as determined by `Symbol.isLess`). */
private def minSym(tps: List[Type]): Symbol =
(tps.head.typeSymbol /: tps.tail) {
(sym1, tp2) => if (tp2.typeSymbol isLess sym1) tp2.typeSymbol else sym1
}
/** A minimal type list which has a given list of types as its base type sequence */
def spanningTypes(ts: List[Type]): List[Type] = ts match {
case List() => List()
case first :: rest =>
first :: spanningTypes(
rest filter (t => !first.typeSymbol.isSubClass(t.typeSymbol)))
}
/** Eliminate from list of types all elements which are a supertype
* of some other element of the list. */
private def elimSuper(ts: List[Type]): List[Type] = ts match {
case List() => List()
case List(t) => List(t)
case t :: ts1 =>
val rest = elimSuper(ts1 filter (t1 => !(t <:< t1)))
if (rest exists (t1 => t1 <:< t)) rest else t :: rest
}
/** Eliminate from list of types all elements which are a subtype
* of some other element of the list. */
private def elimSub(ts: List[Type], depth: Depth): List[Type] = {
def elimSub0(ts: List[Type]): List[Type] = ts match {
case List() => List()
case List(t) => List(t)
case t :: ts1 =>
val rest = elimSub0(ts1 filter (t1 => !isSubType(t1, t, depth.decr)))
if (rest exists (t1 => isSubType(t, t1, depth.decr))) rest else t :: rest
}
val ts0 = elimSub0(ts)
if (ts0.isEmpty || ts0.tail.isEmpty) ts0
else {
val ts1 = ts0 mapConserve (t => elimAnonymousClass(t.dealiasWiden))
if (ts1 eq ts0) ts0
else elimSub(ts1, depth)
}
}
/** Does this set of types have the same weak lub as
* it does regular lub? This is exposed so lub callers
* can discover whether the trees they are typing will
* may require further adaptation. It may return false
* negatives, but it will not return false positives.
*/
def sameWeakLubAsLub(tps: List[Type]) = tps match {
case Nil => true
case tp :: Nil => !typeHasAnnotations(tp)
case tps => !(tps exists typeHasAnnotations) && !(tps forall isNumericValueType)
}
/** If the arguments are all numeric value types, the numeric
* lub according to the weak conformance spec. If any argument
* has type annotations, take the lub of the unannotated type
* and call the analyzerPlugin method annotationsLub so it can
* be further altered. Otherwise, the regular lub.
*/
def weakLub(tps: List[Type]): Type = (
if (tps.isEmpty)
NothingTpe
else if (tps forall isNumericValueType)
numericLub(tps)
else if (tps exists typeHasAnnotations)
annotationsLub(lub(tps map (_.withoutAnnotations)), tps)
else
lub(tps)
)
def numericLub(ts: List[Type]) =
ts reduceLeft ((t1, t2) =>
if (isNumericSubType(t1, t2)) t2
else if (isNumericSubType(t2, t1)) t1
else IntTpe)
private val _lubResults = new mutable.HashMap[(Depth, List[Type]), Type]
def lubResults = _lubResults
private val _glbResults = new mutable.HashMap[(Depth, List[Type]), Type]
def glbResults = _glbResults
def lub(ts: List[Type]): Type = ts match {
case Nil => NothingTpe
case t :: Nil => t
case _ =>
if (Statistics.canEnable) Statistics.incCounter(lubCount)
val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, lubNanos) else null
try {
val res = lub(ts, lubDepth(ts))
// If the number of unapplied type parameters in all incoming
// types is consistent, and the lub does not match that, return
// the type constructor of the calculated lub instead. This
// is because lubbing type constructors tends to result in types
// which have been applied to dummies or Nothing.
ts.map(_.typeParams.size).distinct match {
case x :: Nil if res.typeParams.size != x =>
logResult(s"Stripping type args from lub because $res is not consistent with $ts")(res.typeConstructor)
case _ =>
res
}
}
finally {
lubResults.clear()
glbResults.clear()
if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
}
}
/** The least upper bound wrt <:< of a list of types */
protected[internal] def lub(ts: List[Type], depth: Depth): Type = {
def lub0(ts0: List[Type]): Type = elimSub(ts0, depth) match {
case List() => NothingTpe
case List(t) => t
case ts @ PolyType(tparams, _) :: _ =>
val tparams1 = map2(tparams, matchingBounds(ts, tparams).transpose)((tparam, bounds) =>
tparam.cloneSymbol.setInfo(glb(bounds, depth)))
PolyType(tparams1, lub0(matchingInstTypes(ts, tparams1)))
case ts @ (mt @ MethodType(params, _)) :: rest =>
MethodType(params, lub0(matchingRestypes(ts, mt.paramTypes)))
case ts @ NullaryMethodType(_) :: rest =>
NullaryMethodType(lub0(matchingRestypes(ts, Nil)))
case ts @ TypeBounds(_, _) :: rest =>
TypeBounds(glb(ts map (_.bounds.lo), depth), lub(ts map (_.bounds.hi), depth))
case ts @ AnnotatedType(annots, tpe) :: rest =>
annotationsLub(lub0(ts map (_.withoutAnnotations)), ts)
case ts =>
lubResults get ((depth, ts)) match {
case Some(lubType) =>
lubType
case None =>
lubResults((depth, ts)) = AnyTpe
val res = if (depth.isNegative) AnyTpe else lub1(ts)
lubResults((depth, ts)) = res
res
}
}
def lub1(ts0: List[Type]): Type = {
val (ts, tparams) = stripExistentialsAndTypeVars(ts0)
val lubBaseTypes: List[Type] = lubList(ts, depth)
val lubParents = spanningTypes(lubBaseTypes)
val lubOwner = commonOwner(ts)
val lubBase = intersectionType(lubParents, lubOwner)
val lubType =
if (phase.erasedTypes || depth.isZero ) lubBase
else {
val lubRefined = refinedType(lubParents, lubOwner)
val lubThisType = lubRefined.typeSymbol.thisType
val narrowts = ts map (_.narrow)
def excludeFromLub(sym: Symbol) = (
sym.isClass
|| sym.isConstructor
|| !sym.isPublic
|| isGetClass(sym)
|| sym.isFinal
|| narrowts.exists(t => !refines(t, sym))
)
def lubsym(proto: Symbol): Symbol = {
val prototp = lubThisType.memberInfo(proto)
val syms = narrowts map (t =>
// SI-7602 With erroneous code, we could end up with overloaded symbols after filtering
// so `suchThat` unsuitable.
t.nonPrivateMember(proto.name).filter(sym =>
sym.tpe matches prototp.substThis(lubThisType.typeSymbol, t)))
if (syms contains NoSymbol) NoSymbol
else {
val symtypes =
map2(narrowts, syms)((t, sym) => t.memberInfo(sym).substThis(t.typeSymbol, lubThisType))
if (proto.isTerm) // possible problem: owner of info is still the old one, instead of new refinement class
proto.cloneSymbol(lubRefined.typeSymbol).setInfoOwnerAdjusted(lub(symtypes, depth.decr))
else if (symtypes.tail forall (symtypes.head =:= _))
proto.cloneSymbol(lubRefined.typeSymbol).setInfoOwnerAdjusted(symtypes.head)
else {
def lubBounds(bnds: List[TypeBounds]): TypeBounds =
TypeBounds(glb(bnds map (_.lo), depth.decr), lub(bnds map (_.hi), depth.decr))
lubRefined.typeSymbol.newAbstractType(proto.name.toTypeName, proto.pos)
.setInfoOwnerAdjusted(lubBounds(symtypes map (_.bounds)))
}
}
}
def refines(tp: Type, sym: Symbol): Boolean = {
val syms = tp.nonPrivateMember(sym.name).alternatives
!syms.isEmpty && (syms forall (alt =>
// todo alt != sym is strictly speaking not correct, but without it we lose
// efficiency.
alt != sym && !specializesSym(lubThisType, sym, tp, alt, depth)))
}
// add a refinement symbol for all non-class members of lubBase
// which are refined by every type in ts.
for (sym <- lubBase.nonPrivateMembers ; if !excludeFromLub(sym)) {
try lubsym(sym) andAlso (addMember(lubThisType, lubRefined, _, depth))
catch {
case ex: NoCommonType =>
}
}
if (lubRefined.decls.isEmpty) lubBase
else if (!verifyLubs) lubRefined
else {
// Verify that every given type conforms to the calculated lub.
// In theory this should not be necessary, but higher-order type
// parameters are not handled correctly.
val ok = ts forall { t =>
isSubType(t, lubRefined, depth) || {
if (settings.debug || printLubs) {
Console.println(
"Malformed lub: " + lubRefined + "\n" +
"Argument " + t + " does not conform. Falling back to " + lubBase
)
}
false
}
}
// If not, fall back on the more conservative calculation.
if (ok) lubRefined
else lubBase
}
}
// dropIllegalStarTypes is a localized fix for SI-6897. We should probably
// integrate that transformation at a lower level in master, but lubs are
// the likely and maybe only spot they escape, so fixing here for 2.10.1.
existentialAbstraction(tparams, dropIllegalStarTypes(lubType))
}
if (printLubs) {
println(indent + "lub of " + ts + " at depth "+depth)//debug
indent = indent + " "
assert(indent.length <= 100)
}
if (Statistics.canEnable) Statistics.incCounter(nestedLubCount)
val res = lub0(ts)
if (printLubs) {
indent = indent stripSuffix " "
println(indent + "lub of " + ts + " is " + res)//debug
}
res
}
val GlbFailure = new Throwable
/** A global counter for glb calls in the `specializes` query connected to the `addMembers`
* call in `glb`. There's a possible infinite recursion when `specializes` calls
* memberType, which calls baseTypeSeq, which calls mergePrefixAndArgs, which calls glb.
* The counter breaks this recursion after two calls.
* If the recursion is broken, no member is added to the glb.
*/
private var globalGlbDepth = Depth.Zero
private final val globalGlbLimit = Depth(2)
/** The greatest lower bound of a list of types (as determined by `<:<`). */
def glb(ts: List[Type]): Type = elimSuper(ts) match {
case List() => AnyTpe
case List(t) => t
case ts0 =>
if (Statistics.canEnable) Statistics.incCounter(lubCount)
val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, lubNanos) else null
try {
glbNorm(ts0, lubDepth(ts0))
} finally {
lubResults.clear()
glbResults.clear()
if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
}
}
protected[internal] def glb(ts: List[Type], depth: Depth): Type = elimSuper(ts) match {
case List() => AnyTpe
case List(t) => t
case ts0 => glbNorm(ts0, depth)
}
/** The greatest lower bound of a list of types (as determined by `<:<`), which have been normalized
* with regard to `elimSuper`. */
protected def glbNorm(ts: List[Type], depth: Depth): Type = {
def glb0(ts0: List[Type]): Type = ts0 match {
case List() => AnyTpe
case List(t) => t
case ts @ PolyType(tparams, _) :: _ =>
val tparams1 = map2(tparams, matchingBounds(ts, tparams).transpose)((tparam, bounds) =>
tparam.cloneSymbol.setInfo(lub(bounds, depth)))
PolyType(tparams1, glbNorm(matchingInstTypes(ts, tparams1), depth))
case ts @ (mt @ MethodType(params, _)) :: rest =>
MethodType(params, glbNorm(matchingRestypes(ts, mt.paramTypes), depth))
case ts @ NullaryMethodType(_) :: rest =>
NullaryMethodType(glbNorm(matchingRestypes(ts, Nil), depth))
case ts @ TypeBounds(_, _) :: rest =>
TypeBounds(lub(ts map (_.bounds.lo), depth), glb(ts map (_.bounds.hi), depth))
case ts =>
glbResults get ((depth, ts)) match {
case Some(glbType) =>
glbType
case _ =>
glbResults((depth, ts)) = NothingTpe
val res = if (depth.isNegative) NothingTpe else glb1(ts)
glbResults((depth, ts)) = res
res
}
}
def glb1(ts0: List[Type]): Type = {
try {
val (ts, tparams) = stripExistentialsAndTypeVars(ts0)
val glbOwner = commonOwner(ts)
def refinedToParents(t: Type): List[Type] = t match {
case RefinedType(ps, _) => ps flatMap refinedToParents
case _ => List(t)
}
def refinedToDecls(t: Type): List[Scope] = t match {
case RefinedType(ps, decls) =>
val dss = ps flatMap refinedToDecls
if (decls.isEmpty) dss else decls :: dss
case _ => List()
}
val ts1 = ts flatMap refinedToParents
val glbBase = intersectionType(ts1, glbOwner)
val glbType =
if (phase.erasedTypes || depth.isZero) glbBase
else {
val glbRefined = refinedType(ts1, glbOwner)
val glbThisType = glbRefined.typeSymbol.thisType
def glbsym(proto: Symbol): Symbol = {
val prototp = glbThisType.memberInfo(proto)
val syms = for (t <- ts;
alt <- (t.nonPrivateMember(proto.name).alternatives)
if glbThisType.memberInfo(alt) matches prototp
) yield alt
val symtypes = syms map glbThisType.memberInfo
assert(!symtypes.isEmpty)
proto.cloneSymbol(glbRefined.typeSymbol).setInfoOwnerAdjusted(
if (proto.isTerm) glb(symtypes, depth.decr)
else {
def isTypeBound(tp: Type) = tp match {
case TypeBounds(_, _) => true
case _ => false
}
def glbBounds(bnds: List[Type]): TypeBounds = {
val lo = lub(bnds map (_.bounds.lo), depth.decr)
val hi = glb(bnds map (_.bounds.hi), depth.decr)
if (lo <:< hi) TypeBounds(lo, hi)
else throw GlbFailure
}
val symbounds = symtypes filter isTypeBound
var result: Type =
if (symbounds.isEmpty)
TypeBounds.empty
else glbBounds(symbounds)
for (t <- symtypes if !isTypeBound(t))
if (result.bounds containsType t) result = t
else throw GlbFailure
result
})
}
if (globalGlbDepth < globalGlbLimit)
try {
globalGlbDepth = globalGlbDepth.incr
val dss = ts flatMap refinedToDecls
for (ds <- dss; sym <- ds.iterator)
if (globalGlbDepth < globalGlbLimit && !specializesSym(glbThisType, sym, depth))
try {
addMember(glbThisType, glbRefined, glbsym(sym), depth)
} catch {
case ex: NoCommonType =>
}
} finally {
globalGlbDepth = globalGlbDepth.decr
}
if (glbRefined.decls.isEmpty) glbBase else glbRefined
}
existentialAbstraction(tparams, glbType)
} catch {
case GlbFailure =>
if (ts forall (t => NullTpe <:< t)) NullTpe
else NothingTpe
}
}
// if (settings.debug.value) { println(indent + "glb of " + ts + " at depth "+depth); indent = indent + " " } //DEBUG
if (Statistics.canEnable) Statistics.incCounter(nestedLubCount)
glb0(ts)
// if (settings.debug.value) { indent = indent.substring(0, indent.length() - 2); log(indent + "glb of " + ts + " is " + res) }//DEBUG
}
/** All types in list must be polytypes with type parameter lists of
* same length as tparams.
* Returns list of list of bounds infos, where corresponding type
* parameters are renamed to tparams.
*/
private def matchingBounds(tps: List[Type], tparams: List[Symbol]): List[List[Type]] = {
def getBounds(tp: Type): List[Type] = tp match {
case PolyType(tparams1, _) if sameLength(tparams1, tparams) =>
tparams1 map (tparam => tparam.info.substSym(tparams1, tparams))
case tp =>
if (tp ne tp.normalize) getBounds(tp.normalize)
else throw new NoCommonType(tps)
}
tps map getBounds
}
/** All types in list must be polytypes with type parameter lists of
* same length as tparams.
* Returns list of instance types, where corresponding type
* parameters are renamed to tparams.
*/
private def matchingInstTypes(tps: List[Type], tparams: List[Symbol]): List[Type] = {
def transformResultType(tp: Type): Type = tp match {
case PolyType(tparams1, restpe) if sameLength(tparams1, tparams) =>
restpe.substSym(tparams1, tparams)
case tp =>
if (tp ne tp.normalize) transformResultType(tp.normalize)
else throw new NoCommonType(tps)
}
tps map transformResultType
}
/** All types in list must be method types with equal parameter types.
* Returns list of their result types.
*/
private def matchingRestypes(tps: List[Type], pts: List[Type]): List[Type] =
tps map {
case mt @ MethodType(params1, res) if isSameTypes(mt.paramTypes, pts) =>
res
case NullaryMethodType(res) if pts.isEmpty =>
res
case _ =>
throw new NoCommonType(tps)
}
}
|