@@ -385,7 +385,7 @@ object Denotations {
385
385
*
386
386
* If there is no preferred accessible denotation, return a JointRefDenotation
387
387
* with one of the operand symbols (unspecified which one), and an info which
388
- * is the intersection ( using `&` or `safe_&` if `safeIntersection` is true)
388
+ * is the intersection using `&` or `safe_&` if `safeIntersection` is true)
389
389
* of the infos of the operand denotations.
390
390
*/
391
391
def & (that : Denotation , pre : Type , safeIntersection : Boolean = false )(implicit ctx : Context ): Denotation = {
@@ -412,18 +412,21 @@ object Denotations {
412
412
val sym1 = denot1.symbol
413
413
val sym2 = denot2.symbol
414
414
415
- val sym2Accessible = sym2.isAccessibleFrom(pre)
416
-
417
415
/** Does `sym1` come before `sym2` in the linearization of `pre`? */
418
- def precedes (sym1 : Symbol , sym2 : Symbol ) = {
419
- def precedesIn (bcs : List [ClassSymbol ]): Boolean = bcs match
420
- case bc :: bcs1 => (sym1 eq bc) || ! (sym2 eq bc) && precedesIn(bcs1)
421
- case Nil => false
422
-
423
- (sym1 ne sym2) &&
424
- (sym1.derivesFrom(sym2) ||
425
- ! sym2.derivesFrom(sym1) && precedesIn(pre.baseClasses))
426
- }
416
+ def linearScore (owner1 : Symbol , owner2 : Symbol ): Int =
417
+
418
+ def searchBaseClasses (bcs : List [ClassSymbol ]): Int = bcs match
419
+ case bc :: bcs1 =>
420
+ if bc eq owner1 then 1
421
+ else if bc eq owner2 then - 1
422
+ else searchBaseClasses(bcs1)
423
+ case Nil => 0
424
+
425
+ if owner1 eq owner2 then 0
426
+ else if owner1.derivesFrom(owner2) then 1
427
+ else if owner2.derivesFrom(owner1) then - 1
428
+ else searchBaseClasses(pre.baseClasses)
429
+ end linearScore
427
430
428
431
/** Similar to SymDenotation#accessBoundary, but without the special cases. */
429
432
def accessBoundary (sym : Symbol ) =
@@ -432,82 +435,49 @@ object Denotations {
432
435
if (sym.is(Protected )) sym.owner.enclosingPackageClass
433
436
else defn.RootClass )
434
437
435
- /** Establish a partial order "preference" order between symbols.
436
- * Give preference to `sym1` over `sym2` if one of the following
437
- * conditions holds, in decreasing order of weight:
438
- * 1. sym2 doesn't exist
439
- * 2. sym1 is concrete and sym2 is abstract
440
- * 3. The owner of sym1 comes before the owner of sym2 in the linearization
441
- * of the type of the prefix `pre`.
442
- * 4. The access boundary of sym2 is properly contained in the access
443
- * boundary of sym1. For protected access, we count the enclosing
444
- * package as access boundary.
445
- * 5. sym1 is a method but sym2 is not.
446
- * The aim of these criteria is to give some disambiguation on access which
447
- * - does not depend on textual order or other arbitrary choices
448
- * - minimizes raising of doubleDef errors
449
- */
450
- def preferSym (sym1 : Symbol , sym2 : Symbol ) =
451
- sym1.eq(sym2)
452
- || sym1.exists
453
- && (! sym2.exists
454
- || sym1.isAsConcrete(sym2)
455
- && (! sym2.isAsConcrete(sym1)
456
- || precedes(sym1.owner, sym2.owner)
457
- || accessBoundary(sym2).isProperlyContainedIn(accessBoundary(sym1))
458
- || sym2.is(Bridge ) && ! sym1.is(Bridge )
459
- || sym1.is(Method ) && ! sym2.is(Method ))
460
- || sym1.info.isErroneous)
461
-
462
- /** Sym preference provided types also override */
463
- def prefer (sym1 : Symbol , sym2 : Symbol , info1 : Type , info2 : Type ) =
464
- preferSym(sym1, sym2) &&
465
- info1.overrides(info2, sym1.matchNullaryLoosely || sym2.matchNullaryLoosely, checkClassInfo = false )
466
-
467
- /** Handle conflict where we have either definitions coming from the same class
468
- * that have matching signatures as seen from the current prefix, or we have
469
- * definitions from different classes that have the same signature but
470
- * conflicting infos. In these cases, do a last minute disambiguation
471
- * by picking one alternative according to the ranking
472
- *
473
- * 1. Non-bridge methods
474
- * 2. non-methods
475
- * 3. bridges
476
- * 4. NoSymbol
477
- *
478
- * If that fails, return a MultiDenotation with both alternatives
479
- * and rely on overloading resolution to pick one of them.
480
- */
481
- def handleConflict : Denotation =
482
-
483
- def preferMethod (sym1 : Symbol , sym2 : Symbol ): Boolean =
484
- sym1.exists &&
485
- (! sym2.exists
486
- || sym2.is(Bridge ) && ! sym1.is(Bridge )
487
- || sym1.is(Method ) && ! sym2.is(Method )
488
- || sym1.info.isErroneous)
489
-
490
- if preferMethod(sym1, sym2) then denot1
491
- else if preferMethod(sym2, sym1) then denot2
492
- else
493
- overload.println(i " overloaded with same signature: ${sym1.showLocated}: $info1 / ${sym2.showLocated}: $info2" )
494
- MultiDenotation (denot1, denot2)
495
- end handleConflict
496
-
497
- if (sym2Accessible && prefer(sym2, sym1, info2, info1)) denot2
438
+ def isHidden (sym : Symbol ) = sym.exists && ! sym.isAccessibleFrom(pre)
439
+ val hidden1 = isHidden(sym1)
440
+ val hidden2 = isHidden(sym2)
441
+ if hidden1 && ! hidden2 then denot2
442
+ else if hidden2 && ! hidden1 then denot1
498
443
else
499
- val sym1Accessible = sym1.isAccessibleFrom(pre)
500
- if (sym1Accessible && prefer(sym1, sym2, info1, info2)) denot1
501
- else if (sym1Accessible && sym2.exists && ! sym2Accessible) denot1
502
- else if (sym2Accessible && sym1.exists && ! sym1Accessible) denot2
503
- else if isDoubleDef(sym1, sym2) then handleConflict
444
+ val symScore : Int =
445
+ if ! sym1.exists then - 2
446
+ else if ! sym2.exists then 2
447
+ else if ! sym1.isAsConcrete(sym2) then - 1
448
+ else if ! sym2.isAsConcrete(sym1) then 1
449
+ else
450
+ val linScore = linearScore(sym1.owner, sym2.owner)
451
+ if linScore != 0 then linScore
452
+ else
453
+ val boundary1 = accessBoundary(sym1)
454
+ val boundary2 = accessBoundary(sym2)
455
+ if boundary1.isProperlyContainedIn(boundary2) then - 1
456
+ else if boundary2.isProperlyContainedIn(boundary1) then 1
457
+ else if sym1.is(Bridge ) && ! sym2.is(Bridge ) then - 2
458
+ else if sym2.is(Bridge ) && ! sym1.is(Bridge ) then 2
459
+ else if sym2.is(Method ) && ! sym1.is(Method ) then - 2
460
+ else if sym1.is(Method ) && ! sym2.is(Method ) then 2
461
+ else 0
462
+
463
+ val matchLoosely = sym1.matchNullaryLoosely || sym2.matchNullaryLoosely
464
+
465
+ if info2.overrides(info1, matchLoosely, checkClassInfo = false )
466
+ && symScore <= 0
467
+ then denot2
468
+ else if info1.overrides(info2, matchLoosely, checkClassInfo = false )
469
+ && symScore >= 0
470
+ then denot1
504
471
else
505
- val sym = if preferSym(sym2, sym1) then sym2 else sym1
506
472
val jointInfo = infoMeet(info1, info2, safeIntersection)
507
473
if jointInfo.exists then
474
+ val sym = if symScore > 0 then sym1 else sym2
508
475
JointRefDenotation (sym, jointInfo, denot1.validFor & denot2.validFor, pre)
476
+ else if symScore == 2 then denot1
477
+ else if symScore == - 2 then denot2
509
478
else
510
- handleConflict
479
+ overload.println(i " overloaded with same signature: ${sym1.showLocated}: $info1 / ${sym2.showLocated}: $info2, info = ${info1.getClass}, ${info2.getClass}, $jointInfo" )
480
+ MultiDenotation (denot1, denot2)
511
481
end mergeSingleDenot
512
482
513
483
if (this eq that) this
@@ -533,7 +503,7 @@ object Denotations {
533
503
final def containsSym (sym : Symbol ): Boolean = hasUniqueSym && (symbol eq sym)
534
504
}
535
505
536
- // ------ Info meets and joins ---------------------------------------------
506
+ // ------ Info meets ------- ---------------------------------------------
537
507
538
508
/** Merge parameter names of lambda types. If names in corresponding positions match, keep them,
539
509
* otherwise generate new synthetic names.
@@ -542,82 +512,55 @@ object Denotations {
542
512
(for ((name1, name2, idx) <- tp1.paramNames.lazyZip(tp2.paramNames).lazyZip(tp1.paramNames.indices))
543
513
yield if (name1 == name2) name1 else tp1.companion.syntheticParamName(idx)).toList
544
514
545
- /** Normally, `tp1 & tp2`
546
- * Special cases for matching methods and classes, with
547
- * the possibility of returning NoType.
548
- * Special handling of ExprTypes, where mixed intersections widen the ExprType away.
549
- */
515
+ /** Normally, `tp1 & tp2`, with extra care taken to return `tp1` or `tp2` directly if that's
516
+ * a valid answer. Special cases for matching methods and classes, with
517
+ * the possibility of returning NoType. Special handling of ExprTypes, where mixed
518
+ * intersections widen the ExprType away.
519
+ */
550
520
def infoMeet (tp1 : Type , tp2 : Type , safeIntersection : Boolean )(implicit ctx : Context ): Type =
551
- if ( tp1 eq tp2) tp1
552
- else tp1 match {
521
+ if tp1 eq tp2 then tp1
522
+ else tp1 match
553
523
case tp1 : TypeBounds =>
554
- tp2 match {
555
- case tp2 : TypeBounds => if ( safeIntersection) tp1 safe_& tp2 else tp1 & tp2
524
+ tp2 match
525
+ case tp2 : TypeBounds => if safeIntersection then tp1 safe_& tp2 else tp1 & tp2
556
526
case tp2 : ClassInfo => tp2
557
527
case _ => NoType
558
- }
559
528
case tp1 : ClassInfo =>
560
- tp2 match {
529
+ tp2 match
561
530
case tp2 : ClassInfo if tp1.cls eq tp2.cls => tp1.derivedClassInfo(tp1.prefix & tp2.prefix)
562
531
case tp2 : TypeBounds => tp1
563
532
case _ => NoType
564
- }
565
-
566
- // Two remedial strategies:
567
- //
568
- // 1. Prefer method types over poly types. This is necessary to handle
569
- // overloaded definitions like the following
570
- //
571
- // def ++ [B >: A](xs: C[B]): D[B]
572
- // def ++ (xs: C[A]): D[A]
573
- //
574
- // (Code like this is found in the collection strawman)
575
- //
576
- // 2. In the case of two method types or two polytypes with matching
577
- // parameters and implicit status, merge corresponding parameter
578
- // and result types.
579
533
case tp1 : MethodType =>
580
- tp2 match {
534
+ tp2 match
581
535
case tp2 : MethodType
582
- if ctx.typeComparer.matchingMethodParams(tp1, tp2) && (tp1.companion eq tp2.companion) =>
536
+ if ctx.typeComparer.matchingMethodParams(tp1, tp2)
537
+ && (tp1.isImplicitMethod || tp1.isContextualMethod) == (tp2.isImplicitMethod || tp2.isContextualMethod)
538
+ && tp1.isErasedMethod == tp2.isErasedMethod =>
583
539
val resType = infoMeet(tp1.resType, tp2.resType.subst(tp2, tp1), safeIntersection)
584
540
if resType.exists then
585
541
tp1.derivedLambdaType(mergeParamNames(tp1, tp2), tp1.paramInfos, resType)
586
- else
587
- NoType
588
- case _ =>
589
- NoType
590
- }
542
+ else NoType
543
+ case _ => NoType
591
544
case tp1 : PolyType =>
592
- tp2 match {
593
- case tp2 : PolyType if ctx.typeComparer.matchingPolyParams (tp1, tp2) =>
545
+ tp2 match
546
+ case tp2 : PolyType if sameLength (tp1.paramNames , tp2.paramNames ) =>
594
547
val resType = infoMeet(tp1.resType, tp2.resType.subst(tp2, tp1), safeIntersection)
595
548
if resType.exists then
596
549
tp1.derivedLambdaType(
597
550
mergeParamNames(tp1, tp2),
598
551
tp1.paramInfos.zipWithConserve(tp2.paramInfos)( _ & _ ),
599
552
resType)
600
- else
601
- NoType
602
- case _ =>
603
- NoType
604
- }
553
+ else NoType
554
+ case _ => NoType
605
555
case ExprType (rtp1) =>
606
- tp2 match {
556
+ tp2 match
607
557
case ExprType (rtp2) => ExprType (rtp1 & rtp2)
608
558
case _ => infoMeet(rtp1, tp2, safeIntersection)
609
- }
610
559
case _ =>
611
560
tp2 match
612
- case _ : MethodType | _ : PolyType =>
613
- NoType
614
- case _ =>
615
- try tp1 & tp2.widenExpr
616
- catch
617
- case ex : Throwable =>
618
- println(i " error for meet: $tp1 &&& $tp2, ${tp1.getClass}, ${tp2.getClass}" )
619
- throw ex
620
- }
561
+ case _ : MethodType | _ : PolyType => NoType
562
+ case _ => tp1 & tp2.widenExpr
563
+ end infoMeet
621
564
622
565
/** A non-overloaded denotation */
623
566
abstract class SingleDenotation (symbol : Symbol , initInfo : Type ) extends Denotation (symbol, initInfo) {
@@ -1193,7 +1136,7 @@ object Denotations {
1193
1136
if sd1.exists then
1194
1137
if sd2.exists then
1195
1138
throw TypeError (
1196
- em """ Failure to disambiguate oberloaded reference with
1139
+ em """ Failure to disambiguate overloaded reference with
1197
1140
| ${denot1.symbol.showLocated}: ${denot1.info} and
1198
1141
| ${denot2.symbol.showLocated}: ${denot2.info}""" )
1199
1142
else sd1
0 commit comments