Skip to content

Commit 9466aa2

Browse files
committed
Survive TypeErrors in isMatchedBy
Fixes #15673
1 parent 79d9a6f commit 9466aa2

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
@@ -299,13 +299,13 @@ object Types {
299299
* ThisType of `symd`'s owner, or a reference to `symd`'s owner.'
300300
*/
301301
def isArgPrefixOf(symd: SymDenotation)(using Context): Boolean =
302-
symd.exists && !symd.owner.is(Package) && // Early exit if possible because the next check would force SymbolLoaders
303-
symd.isAllOf(ClassTypeParam) && {
304-
this match {
302+
symd.exists
303+
&& !symd.owner.is(Package) // Early exit if possible because the next check would force SymbolLoaders
304+
&& symd.isAllOf(ClassTypeParam)
305+
&& { this match
305306
case tp: ThisType => tp.cls ne symd.owner
306307
case tp: TypeRef => tp.symbol ne symd.owner
307308
case _ => true
308-
}
309309
}
310310

311311
/** Is this type a (possibly aliased) singleton type? */
@@ -2337,7 +2337,8 @@ object Types {
23372337
i"""bad parameter reference $this at ${ctx.phase}
23382338
|the parameter is ${param.showLocated} but the prefix $prefix
23392339
|does not define any corresponding arguments.
2340-
|idx = $idx, args = $args""")
2340+
|idx = $idx, args = $args%, %,
2341+
|constraint = ${ctx.typerState.constraint}""")
23412342
NoDenotation
23422343
}
23432344
}

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

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

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

208221
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)