@@ -385,7 +385,7 @@ object Denotations {
385385 *
386386 * If there is no preferred accessible denotation, return a JointRefDenotation
387387 * 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)
389389 * of the infos of the operand denotations.
390390 */
391391 def & (that : Denotation , pre : Type , safeIntersection : Boolean = false )(implicit ctx : Context ): Denotation = {
@@ -412,18 +412,21 @@ object Denotations {
412412 val sym1 = denot1.symbol
413413 val sym2 = denot2.symbol
414414
415- val sym2Accessible = sym2.isAccessibleFrom(pre)
416-
417415 /** 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
427430
428431 /** Similar to SymDenotation#accessBoundary, but without the special cases. */
429432 def accessBoundary (sym : Symbol ) =
@@ -432,82 +435,49 @@ object Denotations {
432435 if (sym.is(Protected )) sym.owner.enclosingPackageClass
433436 else defn.RootClass )
434437
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
498443 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
504471 else
505- val sym = if preferSym(sym2, sym1) then sym2 else sym1
506472 val jointInfo = infoMeet(info1, info2, safeIntersection)
507473 if jointInfo.exists then
474+ val sym = if symScore > 0 then sym1 else sym2
508475 JointRefDenotation (sym, jointInfo, denot1.validFor & denot2.validFor, pre)
476+ else if symScore == 2 then denot1
477+ else if symScore == - 2 then denot2
509478 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)
511481 end mergeSingleDenot
512482
513483 if (this eq that) this
@@ -533,7 +503,7 @@ object Denotations {
533503 final def containsSym (sym : Symbol ): Boolean = hasUniqueSym && (symbol eq sym)
534504 }
535505
536- // ------ Info meets and joins ---------------------------------------------
506+ // ------ Info meets ------- ---------------------------------------------
537507
538508 /** Merge parameter names of lambda types. If names in corresponding positions match, keep them,
539509 * otherwise generate new synthetic names.
@@ -542,82 +512,55 @@ object Denotations {
542512 (for ((name1, name2, idx) <- tp1.paramNames.lazyZip(tp2.paramNames).lazyZip(tp1.paramNames.indices))
543513 yield if (name1 == name2) name1 else tp1.companion.syntheticParamName(idx)).toList
544514
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+ */
550520 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
553523 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
556526 case tp2 : ClassInfo => tp2
557527 case _ => NoType
558- }
559528 case tp1 : ClassInfo =>
560- tp2 match {
529+ tp2 match
561530 case tp2 : ClassInfo if tp1.cls eq tp2.cls => tp1.derivedClassInfo(tp1.prefix & tp2.prefix)
562531 case tp2 : TypeBounds => tp1
563532 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.
579533 case tp1 : MethodType =>
580- tp2 match {
534+ tp2 match
581535 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 =>
583539 val resType = infoMeet(tp1.resType, tp2.resType.subst(tp2, tp1), safeIntersection)
584540 if resType.exists then
585541 tp1.derivedLambdaType(mergeParamNames(tp1, tp2), tp1.paramInfos, resType)
586- else
587- NoType
588- case _ =>
589- NoType
590- }
542+ else NoType
543+ case _ => NoType
591544 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 ) =>
594547 val resType = infoMeet(tp1.resType, tp2.resType.subst(tp2, tp1), safeIntersection)
595548 if resType.exists then
596549 tp1.derivedLambdaType(
597550 mergeParamNames(tp1, tp2),
598551 tp1.paramInfos.zipWithConserve(tp2.paramInfos)( _ & _ ),
599552 resType)
600- else
601- NoType
602- case _ =>
603- NoType
604- }
553+ else NoType
554+ case _ => NoType
605555 case ExprType (rtp1) =>
606- tp2 match {
556+ tp2 match
607557 case ExprType (rtp2) => ExprType (rtp1 & rtp2)
608558 case _ => infoMeet(rtp1, tp2, safeIntersection)
609- }
610559 case _ =>
611560 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
621564
622565 /** A non-overloaded denotation */
623566 abstract class SingleDenotation (symbol : Symbol , initInfo : Type ) extends Denotation (symbol, initInfo) {
@@ -1193,7 +1136,7 @@ object Denotations {
11931136 if sd1.exists then
11941137 if sd2.exists then
11951138 throw TypeError (
1196- em """ Failure to disambiguate oberloaded reference with
1139+ em """ Failure to disambiguate overloaded reference with
11971140 | ${denot1.symbol.showLocated}: ${denot1.info} and
11981141 | ${denot2.symbol.showLocated}: ${denot2.info}""" )
11991142 else sd1
0 commit comments