Skip to content

Commit ca8eec3

Browse files
committed
Redo infoMeet so that it returns one of its operands where possible
1 parent 162f3fa commit ca8eec3

File tree

1 file changed

+42
-54
lines changed

1 file changed

+42
-54
lines changed

compiler/src/dotty/tools/dotc/core/Denotations.scala

Lines changed: 42 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -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 = {
@@ -542,82 +542,70 @@ object Denotations {
542542
(for ((name1, name2, idx) <- tp1.paramNames.lazyZip(tp2.paramNames).lazyZip(tp1.paramNames.indices))
543543
yield if (name1 == name2) name1 else tp1.companion.syntheticParamName(idx)).toList
544544

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-
*/
545+
/** Normally, `tp1 & tp2`, with extra care taken to return `tp1` or `tp2` directly if that's
546+
* a valid answer. Special cases for matching methods and classes, with
547+
* the possibility of returning NoType. Special handling of ExprTypes, where mixed
548+
* intersections widen the ExprType away.
549+
*/
550550
def infoMeet(tp1: Type, tp2: Type, safeIntersection: Boolean)(implicit ctx: Context): Type =
551-
if (tp1 eq tp2) tp1
552-
else tp1 match {
551+
if tp1 eq tp2 then tp1
552+
else tp1 match
553553
case tp1: TypeBounds =>
554-
tp2 match {
555-
case tp2: TypeBounds => if (safeIntersection) tp1 safe_& tp2 else tp1 & tp2
554+
tp2 match
555+
case tp2: TypeBounds => if safeIntersection then tp1 safe_& tp2 else tp1 & tp2
556556
case tp2: ClassInfo => tp2
557557
case _ => NoType
558-
}
559558
case tp1: ClassInfo =>
560-
tp2 match {
559+
tp2 match
561560
case tp2: ClassInfo if tp1.cls eq tp2.cls => tp1.derivedClassInfo(tp1.prefix & tp2.prefix)
562561
case tp2: TypeBounds => tp1
563562
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.
579563
case tp1: MethodType =>
580-
tp2 match {
564+
tp2 match
581565
case tp2: MethodType
582566
if ctx.typeComparer.matchingMethodParams(tp1, tp2) && (tp1.companion eq tp2.companion) =>
583-
val resType = infoMeet(tp1.resType, tp2.resType.subst(tp2, tp1), safeIntersection)
584-
if resType.exists then
585-
tp1.derivedLambdaType(mergeParamNames(tp1, tp2), tp1.paramInfos, resType)
586-
else
587-
NoType
567+
val resType1 = tp1.resType
568+
val resType2 = tp2.resType.subst(tp2, tp1)
569+
val resType = infoMeet(resType1, resType2, safeIntersection)
570+
if resType eq resType1 then tp1
571+
else if resType eq resType2 then tp2
572+
else if !resType.exists then NoType
573+
else tp1.derivedLambdaType(mergeParamNames(tp1, tp2), tp1.paramInfos, resType)
588574
case _ =>
589575
NoType
590-
}
591576
case tp1: PolyType =>
592-
tp2 match {
593-
case tp2: PolyType if ctx.typeComparer.matchingPolyParams(tp1, tp2) =>
594-
val resType = infoMeet(tp1.resType, tp2.resType.subst(tp2, tp1), safeIntersection)
595-
if resType.exists then
577+
tp2 match
578+
case tp2: PolyType if sameLength(tp1.paramNames, tp2.paramNames) =>
579+
val resType1 = tp1.resType
580+
val resType2 = tp2.resType.subst(tp2, tp1)
581+
val resType = infoMeet(resType1, resType2, safeIntersection)
582+
if (resType eq resType1) && ctx.typeComparer.matchingPolyParams(tp1, tp2) then
583+
tp1
584+
else if (resType eq resType2) && ctx.typeComparer.matchingPolyParams(tp2, tp1) then
585+
tp2
586+
else if !resType.exists then
587+
NoType
588+
else
596589
tp1.derivedLambdaType(
597590
mergeParamNames(tp1, tp2),
598591
tp1.paramInfos.zipWithConserve(tp2.paramInfos)( _ & _ ),
599592
resType)
600-
else
601-
NoType
602593
case _ =>
603594
NoType
604-
}
605595
case ExprType(rtp1) =>
606-
tp2 match {
607-
case ExprType(rtp2) => ExprType(rtp1 & rtp2)
608-
case _ => infoMeet(rtp1, tp2, safeIntersection)
609-
}
610-
case _ =>
611596
tp2 match
612-
case _: MethodType | _: PolyType =>
613-
NoType
597+
case ExprType(rtp2) =>
598+
val resType = rtp1 & rtp2
599+
if resType eq rtp1 then tp1
600+
else if resType eq rtp2 then tp2
601+
else ExprType(resType)
614602
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-
}
603+
infoMeet(rtp1, tp2, safeIntersection)
604+
case _ =>
605+
tp2 match
606+
case _: MethodType | _: PolyType => NoType
607+
case _ => tp1 & tp2.widenExpr
608+
end infoMeet
621609

622610
/** A non-overloaded denotation */
623611
abstract class SingleDenotation(symbol: Symbol, initInfo: Type) extends Denotation(symbol, initInfo) {

0 commit comments

Comments
 (0)