Skip to content

Commit

Permalink
Drop refinements in approxParent (refineUsingParent)
Browse files Browse the repository at this point in the history
This allows classes that can be refined (non-final, non-case) to be
considered subtypes of a refined type, and thus avoid being dropped as
SpaceEngine's decompose.
  • Loading branch information
dwijnand committed Oct 24, 2023
1 parent 2fa54e8 commit 9fa9147
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 1 deletion.
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/core/Flags.scala
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,7 @@ object Flags {
val DeferredOrTermParamOrAccessor: FlagSet = Deferred | ParamAccessor | TermParam // term symbols without right-hand sides
val DeferredOrTypeParam: FlagSet = Deferred | TypeParam // type symbols without right-hand sides
val EnumValue: FlagSet = Enum | StableRealizable // A Scala enum value
val FinalOrCase: FlagSet = Final | Case
val FinalOrInline: FlagSet = Final | Inline
val FinalOrModuleClass: FlagSet = Final | ModuleClass // A module class or a final class
val EffectivelyFinalFlags: FlagSet = Final | Private
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ trait PatternTypeConstrainer { self: TypeComparer =>
def constrainSimplePatternType(patternTp: Type, scrutineeTp: Type, forceInvariantRefinement: Boolean): Boolean = {
def refinementIsInvariant(tp: Type): Boolean = tp match {
case tp: SingletonType => true
case tp: ClassInfo => tp.cls.is(Final) || tp.cls.is(Case)
case tp: ClassInfo => tp.cls.isOneOf(FinalOrCase)
case tp: TypeProxy => refinementIsInvariant(tp.superType)
case _ => false
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/src/dotty/tools/dotc/core/TypeOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,7 @@ object TypeOps:
// 1. Replace type parameters in T with tvars
// 2. Replace `A.this.C` with `A#C` (see tests/patmat/i12681.scala)
// 3. Replace non-reducing MatchType with its bound
// 4. Drop type refinements unless tp1 if final or a case class (i18736)
//
val approximateParent = new TypeMap {
val boundTypeParams = util.HashMap[TypeRef, TypeVar]()
Expand All @@ -801,6 +802,9 @@ object TypeOps:
apply(lo) <:< tv // no assert, since bounds might conflict
tv

case RefinedType(parent, _, _) if !tp1.symbol.isOneOf(FinalOrCase) =>
apply(parent)

case tp @ AppliedType(tycon: TypeRef, _) if !tycon.dealias.typeSymbol.isClass && !tp.isMatchAlias =>

// In tests/patmat/i3645g.scala, we need to tell whether it's possible
Expand Down
12 changes: 12 additions & 0 deletions tests/warn/i18736.min.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
abstract sealed class ||[+A, +B] extends Product with Serializable
final case class LHS[+A, +B](value: A) extends (A || B)
final case class RHS[+A, +B](value: B) extends (A || B)

abstract sealed class A { type Self }
abstract class B extends A
final class C extends B { type Self = C }

class Test:
def t1[T <: A { type Self = T }](x: String || T): Unit = x match
case RHS(_) => ()
case LHS(_) => ()
11 changes: 11 additions & 0 deletions tests/warn/i18736.object.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
abstract sealed class ||[+A, +B] extends Product with Serializable
final case class LHS[+A, +B](value: A) extends (A || B)
final case class RHS[+A, +B](value: B) extends (A || B)

abstract sealed class A { type Self }
object B extends A

class Test:
def t1[T <: A { type Self = T }](x: String || T): Unit = x match
case RHS(_) => () // warn: unreachable
case LHS(_) => ()
16 changes: 16 additions & 0 deletions tests/warn/i18736.refined.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
abstract sealed class ||[+A, +B] extends Product with Serializable
final case class LHS[+A, +B](value: A) extends (A || B)
final case class RHS[+A, +B](value: B) extends (A || B)

abstract sealed class A { type Self }
abstract class B extends A
final class C extends B { type Self = C }

class Test:
def t2[T <: A { type Self = T; type I = A }](x: String || T): Unit = x match
case RHS(_) => ()
case LHS(_) => ()

def t3[T <: A { type I = A; type Self = T }](x: String || T): Unit = x match
case RHS(_) => ()
case LHS(_) => ()
24 changes: 24 additions & 0 deletions tests/warn/i18736.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
object ReachableUnreachableCase {

sealed trait SuperTrait {
type Self
}

trait SubTrait extends SuperTrait

case class Foo() extends SubTrait {
type Self = Foo
}

def printError[T <: SuperTrait { type Self = T }](x: Either[String, T]): Unit = {
x match {
case Right(_) => println("No error found")
case Left(message) => println(message)
}
}

@main def main(): Unit = {
printError(Right(Foo()))
printError(Left("Error!"))
}
}

0 comments on commit 9fa9147

Please sign in to comment.