Skip to content

Commit 737c2bc

Browse files
Backport "Add special handling for comparisons with Singleton types" to LTS (#21126)
Backports #20474 to the LTS branch. PR submitted by the release tooling. [skip ci]
2 parents c25c8dd + 7f4e19c commit 737c2bc

File tree

3 files changed

+34
-5
lines changed

3 files changed

+34
-5
lines changed

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

+8-5
Original file line numberDiff line numberDiff line change
@@ -920,12 +920,15 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
920920
compareAppliedType1(tp1, tycon1, args1)
921921
case tp1: SingletonType =>
922922
def comparePaths = tp2 match
923-
case tp2: TermRef =>
923+
case tp2: (TermRef | ThisType) =>
924924
compareAtoms(tp1, tp2, knownSingletons = true).getOrElse(false)
925-
|| { // needed to make from-tasty work. test cases: pos/i1753.scala, pos/t839.scala
926-
tp2.info.widenExpr.dealias match
927-
case tp2i: SingletonType => recur(tp1, tp2i)
928-
case _ => false
925+
|| {
926+
// If tp2's underlying type tp2super is also effectively a singleton, compare
927+
// against that. The idea is that if tp1 <: tp2super and tp2 <: tp2super and
928+
// tp2super is also singleton, then tp1 and tp2 must be the same singleton.
929+
// Needed to make from-tasty work. test cases: pos/i1753.scala, pos/t839.scala
930+
val tp2super = tp2.superType.widenExpr
931+
tp2super.isEffectivelySingleton && recur(tp1, tp2super)
929932
}
930933
case _ => false
931934

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

+10
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,16 @@ object Types extends TypeUtils {
326326
/** Is this type a (possibly aliased) singleton type? */
327327
def isSingleton(using Context): Boolean = dealias.isInstanceOf[SingletonType]
328328

329+
/** Is this type a (possibly aliased) singleton type or a type proxy
330+
* or Or/And type known to be a singleton type?
331+
*/
332+
def isEffectivelySingleton(using Context): Boolean = dealias match
333+
case tp: SingletonType => true
334+
case tp: TypeProxy => tp.superType.isEffectivelySingleton
335+
case AndType(tpL, tpR) => tpL.isEffectivelySingleton || tpR.isEffectivelySingleton
336+
case OrType(tpL, tpR) => tpL.isEffectivelySingleton && tpR.isEffectivelySingleton
337+
case _ => false
338+
329339
/** Is this type of kind `AnyKind`? */
330340
def hasAnyKind(using Context): Boolean = {
331341
@tailrec def loop(tp: Type): Boolean = tp match {

tests/pos/i15030.scala

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
sealed trait Schema[A]
2+
3+
object Schema extends RecordInstances:
4+
case class Field[A]()
5+
6+
sealed trait RecordInstances:
7+
self: Schema.type =>
8+
9+
case class Record[A](field: Field[A]) extends Schema[A]
10+
11+
import Schema._
12+
13+
val field: Field[Int] = Field()
14+
15+
// Uh oh Found Playground.Schema.Field[Int] but Requried RecordInstances.this.Field[Int]
16+
val record = Record[Int](field)

0 commit comments

Comments
 (0)