Skip to content

Commit ea842be

Browse files
committed
Tweak isSubInfo for capture checking
- Keep the shortcut for function types in compareRefined - Temper isSubInfo logic
1 parent c304f1a commit ea842be

File tree

1 file changed

+47
-38
lines changed

1 file changed

+47
-38
lines changed

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

Lines changed: 47 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,14 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
641641
def compareRefined: Boolean =
642642
val tp1w = tp1.widen
643643

644+
if ctx.phase == Phases.checkCapturesPhase then
645+
def compareInfo(info1: Type, info2: Type): Boolean =
646+
isSubInfo(info1, info2, NoType)
647+
if defn.isFunctionType(tp2) then
648+
tp1w.widenDealias match
649+
case tp1: RefinedType => return compareInfo(tp1.refinedInfo, tp2.refinedInfo)
650+
case _ =>
651+
644652
val skipped2 = skipMatching(tp1w, tp2)
645653
if (skipped2 eq tp2) || !Config.fastPathForRefinedSubtype then
646654
if containsAnd(tp1) then
@@ -1917,6 +1925,40 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
19171925
case _ =>
19181926
refines.map(RefinedType(tp, _, _): Type).reduce(AndType(_, _))
19191927

1928+
// A relaxed version of isSubType, which compares method types
1929+
// under the standard arrow rule which is contravariant in the parameter types,
1930+
// but under the condition that signatures might have to match (see sigsOK)
1931+
// This relaxed version is needed to correctly compare dependent function types.
1932+
// See pos/i12211.scala.
1933+
def isSubInfo(info1: Type, info2: Type, symInfo1: Type, sigsOK: ((Type, Type) => Boolean) | Null = null, fallbackFn: ((Type, Type) => Boolean) | Null = null): Boolean = trace(i"isSubInfo $info1 <:< $info2"):
1934+
def fallback =
1935+
if fallbackFn != null then fallbackFn(info1, info2)
1936+
else isSubType(info1, info2)
1937+
val isCCPhase = ctx.phase == Phases.checkCapturesPhase
1938+
1939+
(info1, info2) match
1940+
case (info1: PolyType, info2: PolyType) if ccEnabled => // See TODO about `ccEnabled` in `sigsOK`, this should also go under `relaxedSubtyping`.
1941+
comparingTypeLambdas(info1, info2):
1942+
info1.paramNames.hasSameLengthAs(info2.paramNames)
1943+
&& isSubInfo(info1.resultType, info2.resultType.subst(info2, info1), symInfo1.resultType, sigsOK, fallbackFn)
1944+
// Signature checks are never necessary because polymorphic
1945+
// refinements are only allowed for the `apply` method of a
1946+
// PolyFunction.
1947+
case (info1: MethodType, info2: MethodType) =>
1948+
matchingMethodParams(info1, info2, precise = false)
1949+
&& isSubInfo(info1.resultType, info2.resultType.subst(info2, info1), symInfo1.resultType, sigsOK, fallbackFn)
1950+
&& (if sigsOK != null then sigsOK(symInfo1, info2) else true)
1951+
case _ => (info1.widenDealias, info2) match
1952+
case (CapturingType(parent1, _), info2: Type) if isCCPhase =>
1953+
val refs1 = info1.captureSet
1954+
subCaptures(refs1, info2.captureSet, frozenConstraint).isOK && sameBoxed(info1, info2, refs1)
1955+
&& isSubInfo(parent1, info2, symInfo1, sigsOK, fallbackFn)
1956+
case (info1: Type, CapturingType(parent2, refs2)) if isCCPhase =>
1957+
val refs1 = info1.captureSet
1958+
(refs1.isAlwaysEmpty || subCaptures(refs1, refs2, frozenConstraint).isOK) && sameBoxed(info1, info2, refs1)
1959+
&& isSubInfo(info1, parent2, symInfo1, sigsOK, fallbackFn)
1960+
case _ => fallback
1961+
19201962
/** Can comparing this type on the left lead to an either? This is the case if
19211963
* the type is and AndType or contains embedded occurrences of AndTypes
19221964
*/
@@ -1984,43 +2026,10 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
19842026
|| symInfo.isInstanceOf[MethodType]
19852027
&& symInfo.signature.consistentParams(info2.signature)
19862028

1987-
def tp1IsSingleton: Boolean = tp1.isInstanceOf[SingletonType]
1988-
1989-
// A relaxed version of isSubType, which compares method types
1990-
// under the standard arrow rule which is contravariant in the parameter types,
1991-
// but under the condition that signatures might have to match (see sigsOK)
1992-
// This relaxed version is needed to correctly compare dependent function types.
1993-
// See pos/i12211.scala.
1994-
def isSubInfo(info1: Type, info2: Type, symInfo1: Type): Boolean =
1995-
def fallback = inFrozenGadtIf(tp1IsSingleton) { isSubType(info1, info2) }
1996-
info2 match
1997-
case info2: PolyType if ccEnabled => // See TODO about `ccEnabled` in `sigsOK`, this should also go under `relaxedSubtyping`.
1998-
info1 match
1999-
case info1: PolyType =>
2000-
comparingTypeLambdas(info1, info2):
2001-
info1.paramNames.hasSameLengthAs(info2.paramNames)
2002-
&& isSubInfo(info1.resultType, info2.resultType.subst(info2, info1), symInfo1.resultType)
2003-
// Signature checks are never necessary because polymorphic
2004-
// refinements are only allowed for the `apply` method of a
2005-
// PolyFunction.
2006-
case _ => fallback
2007-
case info2: MethodType =>
2008-
info1 match
2009-
case info1: MethodType =>
2010-
matchingMethodParams(info1, info2, precise = false)
2011-
&& isSubInfo(info1.resultType, info2.resultType.subst(info2, info1), symInfo1.resultType)
2012-
&& sigsOK(symInfo1, info2)
2013-
case _ => fallback
2014-
case info2 @ CapturingType(parent2, refs2) if ctx.phase == Phases.checkCapturesPhase =>
2015-
val refs1 = info1.captureSet
2016-
(refs1.isAlwaysEmpty || subCaptures(refs1, refs2, frozenConstraint).isOK) && sameBoxed(info1, info2, refs1)
2017-
&& isSubInfo(info1, parent2, symInfo1)
2018-
case _ =>
2019-
info1 match
2020-
case info1 @ CapturingType(parent1, refs1) if ctx.phase == Phases.checkCapturesPhase =>
2021-
subCaptures(refs1, info2.captureSet, frozenConstraint).isOK && sameBoxed(info1, info2, refs1)
2022-
&& isSubInfo(parent1, info2, symInfo1)
2023-
case _ => fallback
2029+
def fallback = (info1: Type, info2: Type) =>
2030+
def tp1IsSingleton: Boolean = tp1.isInstanceOf[SingletonType]
2031+
inFrozenGadtIf(tp1IsSingleton):
2032+
isSubType(info1, info2)
20242033

20252034
def qualifies(m: SingleDenotation): Boolean =
20262035
val info2 = tp2.refinedInfo
@@ -2035,7 +2044,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
20352044
// OK{ { def x(): T } <: { def x: T} // if x is Java defined
20362045
ExprType(info1.resType)
20372046
case info1 => info1
2038-
isSubInfo(info1, info2, m.symbol.info.orElse(info1))
2047+
isSubInfo(info1, info2, m.symbol.info.orElse(info1), sigsOK, fallback)
20392048
|| matchAbstractTypeMember(m.info)
20402049
|| (tp1.isStable && m.symbol.isStableMember && isSubType(TermRef(tp1, m.symbol), tp2.refinedInfo))
20412050

0 commit comments

Comments
 (0)