diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 801ba332c596..c9cb958bf8b0 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -823,7 +823,15 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling } val tp1norm = simplifyAndTypeWithFallback(tp11, tp12, tp1) if (tp1 ne tp1norm) recur(tp1norm, tp2) - else either(recur(tp11, tp2), recur(tp12, tp2)) + else + if useNecessaryEither && !frozenConstraint then + if tp11 frozen_<:< tp12 then recur(tp11, tp2) + else if tp12 frozen_<:< tp11 then recur(tp12, tp2) + else false + else + val saved = constraint + either(recur(tp11, tp2), recur(tp12, tp2)) + .showing(i"constraining andtype $tp11 & $tp12 <: $tp2 in $saved ----> $constraint", subtyping) case tp1: MatchType => def compareMatch = tp2 match { case tp2: MatchType => diff --git a/tests/pos/i12306.scala b/tests/pos/i12306.scala new file mode 100644 index 000000000000..4343fd10435b --- /dev/null +++ b/tests/pos/i12306.scala @@ -0,0 +1,22 @@ +class Record(elems: Map[String, Any]) extends Selectable: + val fields = elems.toMap + def selectDynamic(name: String): Any = fields(name) + +extension [A <: Record] (a:A) { + def join[B <: Record] (b:B): A & B = { + Record(a.fields ++ b.fields).asInstanceOf[A & B] + } +} + +type Person = Record { val name: String; val age: Int } +type Child = Record { val parent: String } +type PersonAndChild = Record { val name: String; val age: Int; val parent: String } + +@main def hello = { + val person = Record(Map("name" -> "Emma", "age" -> 42)).asInstanceOf[Person] + val child = Record(Map("parent" -> "Alice")).asInstanceOf[Child] + //val personAndChild = person.join(child) + + //val v1: PersonAndChild = personAndChild + val v2: PersonAndChild = person.join(child) +}