@@ -221,9 +221,44 @@ trait Implicits {
221
221
private var tpeCache : Type = null
222
222
private var isErroneousCache : TriState = TriState .Unknown
223
223
224
+ var paramTypeInfoss : List [Array [Type ]] = Nil
225
+ var paramTypeSymss : List [Array [Symbol ]] = Nil
226
+ var resultType : Type = null
227
+
224
228
/** Computes member type of implicit from prefix `pre` (cached). */
225
229
def tpe : Type = {
226
- if (tpeCache eq null ) tpeCache = pre.memberType(sym)
230
+ if (tpeCache eq null ) {
231
+ tpeCache = pre.memberType(sym)
232
+ def loop (tp : Type ): Unit = tp match {
233
+ case PolyType (_, res) => loop(res)
234
+ case mt @ MethodType (params, res) =>
235
+ if (mt.isImplicit) loop(res)
236
+ else {
237
+ loop(res)
238
+ val len = params.length
239
+ var i = 0
240
+ val paramTypeInfos = new Array [Type ](len)
241
+ val paramTypeSyms = new Array [Symbol ](len)
242
+ var ps = params
243
+ while (i < len) {
244
+ val paramTypeSym = ps.head.info match {
245
+ case TypeRef (_, sym, _) if sym.isClass => sym
246
+ case _ => NoSymbol
247
+ }
248
+ paramTypeInfos(i) = ps.head.info
249
+ paramTypeSyms(i) = paramTypeSym
250
+ i += 1
251
+ ps = ps.tail
252
+ }
253
+ paramTypeInfoss ::= paramTypeInfos
254
+ paramTypeSymss ::= paramTypeSyms
255
+ res.finalResultType
256
+ }
257
+ case tp =>
258
+ resultType = tp
259
+ }
260
+ loop(tpeCache.underlying)
261
+ }
227
262
tpeCache
228
263
}
229
264
@@ -386,9 +421,23 @@ trait Implicits {
386
421
/** The type parameters to instantiate */
387
422
val undetParams = if (isView) Nil else context.outer.undetparams
388
423
val wildPt = approximate(pt)
389
- private val ptFunctionArity : Int = {
390
- val dealiased = pt.dealiasWiden
391
- if (isFunctionTypeDirect(dealiased)) dealiased.typeArgs.length - 1 else - 1
424
+ private var ptFunctionResult : Type = null
425
+ private val ptFunctionSig : List [Array [Type ]] = {
426
+ var result : List [Array [Type ]] = Nil
427
+ def loop (tp : Type ): Unit = {
428
+ val dealiased = tp.dealiasWiden
429
+ if (isFunctionTypeDirect(dealiased)) {
430
+ val typeArgs = dealiased.typeArgs
431
+ loop(typeArgs.last)
432
+ val args = new Array [Type ](typeArgs.length - 1 )
433
+ typeArgs.copyToArray(args)
434
+ result ::= args
435
+ } else {
436
+ ptFunctionResult = tp
437
+ }
438
+ }
439
+ loop(pt)
440
+ result
392
441
}
393
442
394
443
private val stableRunDefsForImport = currentRun.runDefinitions
@@ -423,8 +472,8 @@ trait Implicits {
423
472
} else isStrictlyMoreSpecific(info1.tpe, info2.tpe, info1.sym, info2.sym)
424
473
}
425
474
}
426
- def isPlausiblyCompatible (tp : Type , pt : Type ) = checkCompatibility(fast = true , tp , pt)
427
- def normSubType (tp : Type , pt : Type ) = checkCompatibility(fast = false , tp, pt)
475
+ def isPlausiblyCompatible (info : ImplicitInfo , pt : Type ) = checkCompatibilityFast(info, info.tpe , pt)
476
+ def normSubType (tp : Type , pt : Type ) = checkCompatibilitySlow( tp, pt)
428
477
429
478
/** Does type `dtor` dominate type `dted`?
430
479
* This is the case if the stripped cores `dtor1` and `dted1` of both types are
@@ -547,7 +596,7 @@ trait Implicits {
547
596
private def matchesPtView (tp : Type , ptarg : Type , ptres : Type , undet : List [Symbol ]): Boolean = tp match {
548
597
case MethodType (p :: _, restpe) if p.isImplicit => matchesPtView(restpe, ptarg, ptres, undet)
549
598
case MethodType (p :: Nil , restpe) => matchesArgRes(p.tpe, restpe, ptarg, ptres, undet)
550
- case ExistentialType (_, qtpe) => matchesPtView(normalize( qtpe) , ptarg, ptres, undet)
599
+ case ExistentialType (_, qtpe) => matchesPtView(qtpe, ptarg, ptres, undet)
551
600
case Function1 (arg1, res1) => matchesArgRes(arg1, res1, ptarg, ptres, undet)
552
601
case _ => false
553
602
}
@@ -569,7 +618,32 @@ trait Implicits {
569
618
* they are: perhaps someone more familiar with the intentional distinctions
570
619
* can examine the now much smaller concrete implementations below.
571
620
*/
572
- private def checkCompatibility (fast : Boolean , tp0 : Type , pt0 : Type ): Boolean = {
621
+ private def checkCompatibilityFast (info : ImplicitInfo , tp0 : Type , pt : Type ): Boolean = {
622
+ pt match {
623
+ case tr @ TypeRef (pre, sym, args) =>
624
+ if (sym.isAliasType) checkCompatibilityFast(info, tp0, pt.dealias)
625
+ else if (sym.isAbstractType) checkCompatibilityFast(info, tp0, pt.bounds.lo)
626
+ else {
627
+ if (info.paramTypeInfoss == Nil )
628
+ isPlausiblySubType(tp0, pt)
629
+ else {
630
+ val len = info.paramTypeInfoss.length
631
+ val (ptFunctionSigPrefix, ptFunctionSigSuffix) = ptFunctionSig.splitAt(len)
632
+ val paramssCompatible = info.paramTypeInfoss.corresponds(ptFunctionSigPrefix) {
633
+ (infos, ptArgs) =>
634
+ (infos.length == ptArgs.length) && infos.corresponds(ptArgs) { (info, ptArg) =>
635
+ isPlausiblySubType(ptArg, info)
636
+ }
637
+ }
638
+ val ptResidual = ptFunctionSigSuffix.foldRight(ptFunctionResult)((tps, res) => functionType(tps.toList, res))
639
+ paramssCompatible && isPlausiblySubType(info.resultType, ptResidual)
640
+ }
641
+ }
642
+ case _ => isPlausiblySubType(tp0, pt)
643
+ }
644
+ }
645
+
646
+ private def checkCompatibilitySlow (tp0 : Type , pt0 : Type ): Boolean = {
573
647
@ tailrec def loop (tp : Type , pt : Type ): Boolean = tp match {
574
648
case mt @ MethodType (params, restpe) =>
575
649
if (mt.isImplicit)
@@ -579,23 +653,15 @@ trait Implicits {
579
653
if (sym.isAliasType) loop(tp, pt.dealias)
580
654
else if (sym.isAbstractType) loop(tp, pt.bounds.lo)
581
655
else {
582
- ptFunctionArity > 0 && hasLength(params, ptFunctionArity ) && {
656
+ hasLength(args, params.length + 1 ) && {
583
657
var ps = params
584
658
var as = args
585
- if (fast) {
586
- while (ps.nonEmpty && as.nonEmpty) {
587
- if (! isPlausiblySubType(as.head, ps.head.tpe))
588
- return false
589
- ps = ps.tail
590
- as = as.tail
591
- }
592
- } else {
593
- while (ps.nonEmpty && as.nonEmpty) {
594
- if (! (as.head <:< ps.head.tpe))
595
- return false
596
- ps = ps.tail
597
- as = as.tail
598
- }
659
+ var i = 0
660
+ while (ps.nonEmpty && as.nonEmpty) {
661
+ if (! (as.head <:< ps.head.tpe))
662
+ return false
663
+ ps = ps.tail
664
+ as = as.tail
599
665
}
600
666
ps.isEmpty && as.nonEmpty && {
601
667
val lastArg = as.head
@@ -604,12 +670,12 @@ trait Implicits {
604
670
}
605
671
}
606
672
607
- case _ => if (fast) false else tp <:< pt
673
+ case _ => tp <:< pt
608
674
}
609
675
case NullaryMethodType (restpe) => loop(restpe, pt)
610
676
case PolyType (_, restpe) => loop(restpe, pt)
611
- case ExistentialType (_, qtpe) => if (fast) loop(qtpe, pt) else normalize(tp) <:< pt // is !fast case needed??
612
- case _ => if (fast) isPlausiblySubType(tp, pt) else tp <:< pt
677
+ case ExistentialType (_, qtpe) => tp <:< pt
678
+ case _ => tp <:< pt
613
679
}
614
680
loop(tp0, pt0)
615
681
}
@@ -876,7 +942,7 @@ trait Implicits {
876
942
*/
877
943
def survives (info : ImplicitInfo ) = (
878
944
! isIneligible(info) // cyclic, erroneous, shadowed, or specially excluded
879
- && isPlausiblyCompatible(info.tpe , wildPt) // optimization to avoid matchesPt
945
+ && isPlausiblyCompatible(info, wildPt) // optimization to avoid matchesPt
880
946
&& ! shadower.isShadowed(info.name) // OPT rare, only check for plausible candidates
881
947
&& matchesPt(info) // stable and matches expected type
882
948
)
0 commit comments