Skip to content

Commit 4d0d591

Browse files
authored
Merge pull request #11549 from dotty-staging/fix-11545
Recursively check nonvariant arguments of base types for realizability
2 parents 6c375b5 + 60e3965 commit 4d0d591

File tree

2 files changed

+60
-10
lines changed

2 files changed

+60
-10
lines changed

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

+23-10
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ object CheckRealizable {
3232
class HasProblemBaseArg(typ: Type, argBounds: TypeBounds)(using Context)
3333
extends Realizability(i" has a base type $typ with possibly conflicting parameter bounds ${argBounds.lo} <: ... <: ${argBounds.hi}")
3434

35-
class HasProblemBase(base1: Type, base2: Type)(using Context)
36-
extends Realizability(i" has conflicting base types $base1 and $base2")
35+
class HasProblemBase(base1: Type, base2: Type, argStr: String)(using Context)
36+
extends Realizability(i" has conflicting base type${argStr}s $base1 and $base2")
3737

3838
class HasProblemField(fld: SingleDenotation, problem: Realizability)(using Context)
3939
extends Realizability(i" has a member $fld which is not a legal path\nsince ${fld.symbol.name}: ${fld.info}${problem.msg}")
@@ -167,17 +167,30 @@ class CheckRealizable(using Context) {
167167
new HasProblemBounds(name, mbr.info)
168168
}
169169

170-
def baseTypeProblems(base: Type) = base match {
171-
case AndType(base1, base2) =>
172-
new HasProblemBase(base1, base2) :: Nil
173-
case base =>
174-
base.argInfos.collect {
175-
case bounds @ TypeBounds(lo, hi) if !(lo <:< hi) =>
176-
new HasProblemBaseArg(base, bounds)
170+
def baseTypeProblems(base: Type, argStr: String): List[Realizability] = base match {
171+
case base: AndType =>
172+
def factors(tp: Type): List[Type] = tp match
173+
case AndType(tp1, tp2) => factors(tp1) ++ factors(tp2)
174+
case _ => tp :: Nil
175+
for case AndType(base1, base2) <-
176+
factors(base).groupBy(_.classSymbol).values.map(_.reduce(_ & _)).toList
177+
// try to merge factors with common class symbols
178+
// if we cannot, it's a conflict
179+
yield HasProblemBase(base1, base2, argStr)
180+
case base: AppliedType =>
181+
base.argInfos.lazyZip(base.tycon.typeParams).flatMap { (arg, tparam) =>
182+
arg match
183+
case bounds @ TypeBounds(lo, hi) if !(lo <:< hi) =>
184+
new HasProblemBaseArg(base, bounds) :: Nil
185+
case arg if tparam.paramVarianceSign == 0 =>
186+
baseTypeProblems(arg, " argument")
187+
case _ =>
188+
Nil
177189
}
190+
case _ => Nil
178191
}
179192
val baseProblems =
180-
tp.baseClasses.map(_.baseTypeOf(tp)).flatMap(baseTypeProblems)
193+
tp.baseClasses.map(_.baseTypeOf(tp)).flatMap(baseTypeProblems(_, ""))
181194

182195
baseProblems.foldLeft(
183196
refinementProblems.foldLeft(

tests/neg/i11545.scala

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
@main def test: Unit = {
2+
trait S[A]
3+
trait Inv[A]
4+
5+
locally {
6+
class P[X] extends S[Inv[X] & Inv[String]] // error: cannot be instantiated
7+
8+
def patmat[A, Y](s: S[Inv[A] & Y]): A = s match {
9+
case p: P[x] =>
10+
"Hello"
11+
}
12+
13+
val got: Int = patmat[Int, Inv[String]](new P)
14+
}
15+
16+
locally {
17+
class P[X] extends S[S[Inv[X] & Inv[String]]] // error: cannot be instantiated
18+
19+
def patmat[A, Y](s: S[S[Inv[A] & Y]]): A = s match {
20+
case p: P[x] =>
21+
"Hello"
22+
}
23+
24+
val got: Int = patmat[Int, Inv[String]](new P)
25+
}
26+
27+
locally {
28+
abstract class P[X] extends S[Inv[X] & Inv[String]]
29+
30+
def patmat[A, Y](s: S[Inv[A] & Y]): A = s match {
31+
case p: P[x] =>
32+
"Hello"
33+
}
34+
35+
val got: Int = patmat[Int, Inv[String]](new P {}) // error: cannot be instantiated
36+
}
37+
}

0 commit comments

Comments
 (0)