Skip to content

Commit 3b4ef1a

Browse files
authored
Merge pull request #15760 from dotty-staging/backport-15675
Backport #15675: Survive TypeErrors in isMatchedBy
2 parents d669b1e + 633fc7d commit 3b4ef1a

File tree

3 files changed

+40
-19
lines changed

3 files changed

+40
-19
lines changed

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

+6-5
Original file line numberDiff line numberDiff line change
@@ -310,13 +310,13 @@ object Types {
310310
* ThisType of `symd`'s owner, or a reference to `symd`'s owner.'
311311
*/
312312
def isArgPrefixOf(symd: SymDenotation)(using Context): Boolean =
313-
symd.exists && !symd.owner.is(Package) && // Early exit if possible because the next check would force SymbolLoaders
314-
symd.isAllOf(ClassTypeParam) && {
315-
this match {
313+
symd.exists
314+
&& !symd.owner.is(Package) // Early exit if possible because the next check would force SymbolLoaders
315+
&& symd.isAllOf(ClassTypeParam)
316+
&& { this match
316317
case tp: ThisType => tp.cls ne symd.owner
317318
case tp: TypeRef => tp.symbol ne symd.owner
318319
case _ => true
319-
}
320320
}
321321

322322
/** Is this type a (possibly aliased) singleton type? */
@@ -2333,7 +2333,8 @@ object Types {
23332333
i"""bad parameter reference $this at ${ctx.phase}
23342334
|the parameter is ${param.showLocated} but the prefix $prefix
23352335
|does not define any corresponding arguments.
2336-
|idx = $idx, args = $args""")
2336+
|idx = $idx, args = $args%, %,
2337+
|constraint = ${ctx.typerState.constraint}""")
23372338
NoDenotation
23382339
}
23392340
}

compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala

+27-14
Original file line numberDiff line numberDiff line change
@@ -188,20 +188,33 @@ object ProtoTypes {
188188
case _ => false
189189

190190
override def isMatchedBy(tp1: Type, keepConstraint: Boolean)(using Context): Boolean =
191-
name == nme.WILDCARD || hasUnknownMembers(tp1) ||
192-
{
193-
val mbr = if (privateOK) tp1.member(name) else tp1.nonPrivateMember(name)
194-
def qualifies(m: SingleDenotation) =
195-
val isAccessible = !m.symbol.exists || m.symbol.isAccessibleFrom(tp1, superAccess = true)
196-
isAccessible
197-
&& (memberProto.isRef(defn.UnitClass)
198-
|| tp1.isValueType && compat.normalizedCompatible(NamedType(tp1, name, m), memberProto, keepConstraint))
199-
// Note: can't use `m.info` here because if `m` is a method, `m.info`
200-
// loses knowledge about `m`'s default arguments.
201-
mbr match { // hasAltWith inlined for performance
202-
case mbr: SingleDenotation => mbr.exists && qualifies(mbr)
203-
case _ => mbr hasAltWith qualifies
204-
}
191+
name == nme.WILDCARD
192+
|| hasUnknownMembers(tp1)
193+
|| {
194+
try
195+
val mbr = if privateOK then tp1.member(name) else tp1.nonPrivateMember(name)
196+
def qualifies(m: SingleDenotation) =
197+
val isAccessible = !m.symbol.exists || m.symbol.isAccessibleFrom(tp1, superAccess = true)
198+
isAccessible
199+
&& (memberProto.isRef(defn.UnitClass)
200+
|| tp1.isValueType && compat.normalizedCompatible(NamedType(tp1, name, m), memberProto, keepConstraint))
201+
// Note: can't use `m.info` here because if `m` is a method, `m.info`
202+
// loses knowledge about `m`'s default arguments.
203+
mbr match // hasAltWith inlined for performance
204+
case mbr: SingleDenotation => mbr.exists && qualifies(mbr)
205+
case _ => mbr hasAltWith qualifies
206+
catch case ex: TypeError =>
207+
// A scenario where this can happen is in pos/15673.scala:
208+
// We have a type `CC[A]#C` where `CC`'s upper bound is `[X] => Any`, but
209+
// the current constraint stipulates CC <: SeqOps[...], where `SeqOps` defines
210+
// the `C` parameter. We try to resolve this using `argDenot` but `argDenot`
211+
// consults the base type of `CC`, which is not `SeqOps`, so it does not
212+
// find a corresponding argument. In fact, `argDenot` is not allowed to
213+
// consult short-lived things like the current constraint, so it has no other
214+
// choice. The problem will be healed later, when normal selection fails
215+
// and we try to instantiate type variables to compensate. But we have to make
216+
// sure we do not issue a type error before we get there.
217+
false
205218
}
206219

207220
def underlying(using Context): Type = WildcardType

tests/pos/i15673.scala

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
trait SeqOps[+A, +CC[_], +C]: // scala.collection.SeqOps
2+
def reverse: C
3+
4+
extension[A, CC[B] <: SeqOps[B, CC, CC[B]]](ring: CC[A])
5+
def startAt(i: Int): CC[A] = ???
6+
def reflectAt(i: Int): CC[A] =
7+
startAt(i).reverse

0 commit comments

Comments
 (0)