diff --git a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala index a8c8ec8ce1d8..05116c9e03d9 100644 --- a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala +++ b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala @@ -144,26 +144,30 @@ object TypeTestsCasts { case _ => recur(defn.AnyType, tpT) } case tpe @ AppliedType(tycon, targs) if !trustTypeApplication => - X.widenDealias match { - case OrType(tp1, tp2) => - // This case is required to retrofit type inference, - // which cut constraints in the following two cases: - // - T1 <:< T2 | T3 - // - T1 & T2 <:< T3 - // See TypeComparer#either - recur(tp1, P) && recur(tp2, P) - case tpX: FlexibleType => - recur(tpX.underlying, P) - case x => - // always false test warnings are emitted elsewhere - // provablyDisjoint wants fully applied types as input; because we're in the middle of erasure, we sometimes get raw types here - val xApplied = - val tparams = x.typeParams - if tparams.isEmpty then x else x.appliedTo(tparams.map(_ => WildcardType)) - TypeComparer.provablyDisjoint(xApplied, tpe.derivedAppliedType(tycon, targs.map(_ => WildcardType))) - || typeArgsDeterminable(X, tpe) - ||| i"its type arguments can't be determined from $X" - } + val abstractArgs = targs.filter(arg => isAbstract(arg) && !arg.isInstanceOf[WildcardType] ) + if abstractArgs.nonEmpty && !tycon.classSymbol.is(Final) then + i"type arguments $abstractArgs refer to abstract types," + else + X.widenDealias match { + case OrType(tp1, tp2) => + // This case is required to retrofit type inference, + // which cut constraints in the following two cases: + // - T1 <:< T2 | T3 + // - T1 & T2 <:< T3 + // See TypeComparer#either + recur(tp1, P) && recur(tp2, P) + case tpX: FlexibleType => + recur(tpX.underlying, P) + case x => + // always false test warnings are emitted elsewhere + // provablyDisjoint wants fully applied types as input; because we're in the middle of erasure, we sometimes get raw types here + val xApplied = + val tparams = x.typeParams + if tparams.isEmpty then x else x.appliedTo(tparams.map(_ => WildcardType)) + TypeComparer.provablyDisjoint(xApplied, tpe.derivedAppliedType(tycon, targs.map(_ => WildcardType))) + || typeArgsDeterminable(X, tpe) + ||| i"its type arguments can't be determined from $X" + } case AndType(tp1, tp2) => recur(X, tp1) && recur(X, tp2) case OrType(tp1, tp2) => recur(X, tp1) && recur(X, tp2) case AnnotatedType(t, _) => recur(X, t) diff --git a/tests/neg/i24322.scala b/tests/neg/i24322.scala new file mode 100644 index 000000000000..61566bc114df --- /dev/null +++ b/tests/neg/i24322.scala @@ -0,0 +1,13 @@ +trait A[+T]: + def x: T +trait B[+T] extends A[T]: + def y: T + +object Troll extends A[Int] with B[Any]: + def x: Int = 0 + def y: Any = "" + +def f[T](a: A[T]): T = a match { + case b: B[T] => b.y // error + case _ => a.x +} diff --git a/tests/pos/i24322.scala b/tests/pos/i24322.scala new file mode 100644 index 000000000000..fa91cd2adac5 --- /dev/null +++ b/tests/pos/i24322.scala @@ -0,0 +1,10 @@ +trait A[+T]: + def x: T +final class B[+T] extends A[T]: + def x: T = ??? + def y: T = ??? + +def f[T](a: A[T]): T = a match { + case b: B[T] => b.y // compiles without warning + case _ => a.x +}