Skip to content

Commit 8ab7ebe

Browse files
authored
Fix use of class terms in match analysis (#21848)
2 parents aa60a39 + 4d79459 commit 8ab7ebe

File tree

4 files changed

+118
-62
lines changed

4 files changed

+118
-62
lines changed

Diff for: compiler/src/dotty/tools/dotc/core/TypeOps.scala

+69-62
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,67 @@ object TypeOps:
767767
* Otherwise, return NoType.
768768
*/
769769
private def instantiateToSubType(tp1: NamedType, tp2: Type, mixins: List[Type])(using Context): Type = trace(i"instantiateToSubType($tp1, $tp2, $mixins)", typr) {
770+
/** Gather GADT symbols and singletons found in `tp2`, ie. the scrutinee. */
771+
object TraverseTp2 extends TypeTraverser:
772+
val singletons = util.HashMap[Symbol, SingletonType]()
773+
val gadtSyms = new mutable.ListBuffer[Symbol]
774+
775+
def traverse(tp: Type) = try
776+
val tpd = tp.dealias
777+
if tpd ne tp then traverse(tpd)
778+
else tp match
779+
case tp: ThisType if !singletons.contains(tp.tref.symbol) && !tp.tref.symbol.isStaticOwner =>
780+
singletons(tp.tref.symbol) = tp
781+
traverseChildren(tp.tref)
782+
case tp: TermRef =>
783+
singletons(tp.typeSymbol) = tp
784+
traverseChildren(tp)
785+
case tp: TypeRef if !gadtSyms.contains(tp.symbol) && tp.symbol.isAbstractOrParamType =>
786+
gadtSyms += tp.symbol
787+
traverseChildren(tp)
788+
// traverse abstract type infos, to add any singletons
789+
// for example, i16451.CanForward.scala, add `Namer.this`, from the info of the type parameter `A1`
790+
// also, i19031.ci-reg2.scala, add `out`, from the info of the type parameter `A1` (from synthetic applyOrElse)
791+
traverseChildren(tp.info)
792+
case _ =>
793+
traverseChildren(tp)
794+
catch case ex: Throwable => handleRecursive("traverseTp2", tp.show, ex)
795+
TraverseTp2.traverse(tp2)
796+
val singletons = TraverseTp2.singletons
797+
val gadtSyms = TraverseTp2.gadtSyms.toList
798+
799+
// Prefix inference, given `p.C.this.Child`:
800+
// 1. return it as is, if `C.this` is found in `tp`, i.e. the scrutinee; or
801+
// 2. replace it with `X.Child` where `X <: p.C`, stripping ThisType in `p` recursively.
802+
//
803+
// See tests/patmat/i3938.scala, tests/pos/i15029.more.scala, tests/pos/i16785.scala
804+
class InferPrefixMap extends TypeMap {
805+
var prefixTVar: Type | Null = null
806+
def apply(tp: Type): Type = tp match {
807+
case tp: TermRef if singletons.contains(tp.symbol) =>
808+
prefixTVar = singletons(tp.symbol) // e.g. tests/pos/i19031.ci-reg2.scala, keep out
809+
prefixTVar.uncheckedNN
810+
case ThisType(tref) if !tref.symbol.isStaticOwner =>
811+
val symbol = tref.symbol
812+
if singletons.contains(symbol) then
813+
prefixTVar = singletons(symbol) // e.g. tests/pos/i16785.scala, keep Outer.this
814+
prefixTVar.uncheckedNN
815+
else if symbol.is(Module) then
816+
TermRef(this(tref.prefix), symbol.sourceModule)
817+
else if (prefixTVar != null)
818+
this(tref.applyIfParameterized(tref.typeParams.map(_ => WildcardType)))
819+
else {
820+
prefixTVar = WildcardType // prevent recursive call from assigning it
821+
// e.g. tests/pos/i15029.more.scala, create a TypeVar for `Instances`' B, so we can disregard `Ints`
822+
val tvars = tref.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds, DepParamName.fresh(tparam.paramName)) }
823+
val tref2 = this(tref.applyIfParameterized(tvars))
824+
prefixTVar = newTypeVar(TypeBounds.upper(tref2), DepParamName.fresh(tref.name))
825+
prefixTVar.uncheckedNN
826+
}
827+
case tp => mapOver(tp)
828+
}
829+
}
830+
770831
// In order for a child type S to qualify as a valid subtype of the parent
771832
// T, we need to test whether it is possible S <: T.
772833
//
@@ -788,8 +849,15 @@ object TypeOps:
788849
// then to avoid it failing the <:<
789850
// we'll approximate by widening to its bounds
790851

852+
case tp: TermRef if singletons.contains(tp.symbol) =>
853+
singletons(tp.symbol)
854+
791855
case ThisType(tref: TypeRef) if !tref.symbol.isStaticOwner =>
792-
tref
856+
val symbol = tref.symbol
857+
if singletons.contains(symbol) then
858+
singletons(symbol)
859+
else
860+
tref
793861

794862
case tp: TypeRef if !tp.symbol.isClass =>
795863
val lookup = boundTypeParams.lookup(tp)
@@ -840,67 +908,6 @@ object TypeOps:
840908
}
841909
}
842910

843-
/** Gather GADT symbols and singletons found in `tp2`, ie. the scrutinee. */
844-
object TraverseTp2 extends TypeTraverser:
845-
val singletons = util.HashMap[Symbol, SingletonType]()
846-
val gadtSyms = new mutable.ListBuffer[Symbol]
847-
848-
def traverse(tp: Type) = try
849-
val tpd = tp.dealias
850-
if tpd ne tp then traverse(tpd)
851-
else tp match
852-
case tp: ThisType if !singletons.contains(tp.tref.symbol) && !tp.tref.symbol.isStaticOwner =>
853-
singletons(tp.tref.symbol) = tp
854-
traverseChildren(tp.tref)
855-
case tp: TermRef if tp.symbol.is(Param) =>
856-
singletons(tp.typeSymbol) = tp
857-
traverseChildren(tp)
858-
case tp: TypeRef if !gadtSyms.contains(tp.symbol) && tp.symbol.isAbstractOrParamType =>
859-
gadtSyms += tp.symbol
860-
traverseChildren(tp)
861-
// traverse abstract type infos, to add any singletons
862-
// for example, i16451.CanForward.scala, add `Namer.this`, from the info of the type parameter `A1`
863-
// also, i19031.ci-reg2.scala, add `out`, from the info of the type parameter `A1` (from synthetic applyOrElse)
864-
traverseChildren(tp.info)
865-
case _ =>
866-
traverseChildren(tp)
867-
catch case ex: Throwable => handleRecursive("traverseTp2", tp.show, ex)
868-
TraverseTp2.traverse(tp2)
869-
val singletons = TraverseTp2.singletons
870-
val gadtSyms = TraverseTp2.gadtSyms.toList
871-
872-
// Prefix inference, given `p.C.this.Child`:
873-
// 1. return it as is, if `C.this` is found in `tp`, i.e. the scrutinee; or
874-
// 2. replace it with `X.Child` where `X <: p.C`, stripping ThisType in `p` recursively.
875-
//
876-
// See tests/patmat/i3938.scala, tests/pos/i15029.more.scala, tests/pos/i16785.scala
877-
class InferPrefixMap extends TypeMap {
878-
var prefixTVar: Type | Null = null
879-
def apply(tp: Type): Type = tp match {
880-
case tp: TermRef if singletons.contains(tp.symbol) =>
881-
prefixTVar = singletons(tp.symbol) // e.g. tests/pos/i19031.ci-reg2.scala, keep out
882-
prefixTVar.uncheckedNN
883-
case ThisType(tref) if !tref.symbol.isStaticOwner =>
884-
val symbol = tref.symbol
885-
if singletons.contains(symbol) then
886-
prefixTVar = singletons(symbol) // e.g. tests/pos/i16785.scala, keep Outer.this
887-
prefixTVar.uncheckedNN
888-
else if symbol.is(Module) then
889-
TermRef(this(tref.prefix), symbol.sourceModule)
890-
else if (prefixTVar != null)
891-
this(tref.applyIfParameterized(tref.typeParams.map(_ => WildcardType)))
892-
else {
893-
prefixTVar = WildcardType // prevent recursive call from assigning it
894-
// e.g. tests/pos/i15029.more.scala, create a TypeVar for `Instances`' B, so we can disregard `Ints`
895-
val tvars = tref.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds, DepParamName.fresh(tparam.paramName)) }
896-
val tref2 = this(tref.applyIfParameterized(tvars))
897-
prefixTVar = newTypeVar(TypeBounds.upper(tref2), DepParamName.fresh(tref.name))
898-
prefixTVar.uncheckedNN
899-
}
900-
case tp => mapOver(tp)
901-
}
902-
}
903-
904911
val inferThisMap = new InferPrefixMap
905912
val tvars = tp1.etaExpand match
906913
case eta: TypeLambda => constrained(eta)

Diff for: compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

+1
Original file line numberDiff line numberDiff line change
@@ -1125,6 +1125,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
11251125
recur(fn) ~ "(" ~ toTextGlobal(explicitArgs, ", ") ~ ")"
11261126
case TypeApply(fn, args) => recur(fn) ~ "[" ~ toTextGlobal(args, ", ") ~ "]"
11271127
case Select(qual, nme.CONSTRUCTOR) => recur(qual)
1128+
case id @ Ident(tpnme.BOUNDTYPE_ANNOT) => "@" ~ toText(id.symbol.name)
11281129
case New(tpt) => recur(tpt)
11291130
case _ =>
11301131
val annotSym = sym.orElse(tree.symbol.enclosingClass)

Diff for: tests/warn/i21845.orig.scala

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
trait Init[ScopeType]:
2+
sealed trait Initialize[A1]
3+
final class Bind[S, A1](val f: S => Initialize[A1], val in: Initialize[S])
4+
extends Initialize[A1]
5+
final class Value[A1](val value: () => A1) extends Initialize[A1]
6+
final class ValidationCapture[A1](val key: ScopedKey[A1], val selfRefOk: Boolean)
7+
extends Initialize[ScopedKey[A1]]
8+
final class TransformCapture(val f: [x] => Initialize[x] => Initialize[x])
9+
extends Initialize[[x] => Initialize[x] => Initialize[x]]
10+
final class Optional[S, A1](val a: Option[Initialize[S]], val f: Option[S] => A1)
11+
extends Initialize[A1]
12+
object StaticScopes extends Initialize[Set[ScopeType]]
13+
14+
sealed trait Keyed[S, A1] extends Initialize[A1]
15+
trait KeyedInitialize[A1] extends Keyed[A1, A1]
16+
sealed case class ScopedKey[A](scope: ScopeType, key: AttributeKey[A]) extends KeyedInitialize[A]
17+
sealed trait AttributeKey[A]
18+
19+
abstract class EvaluateSettings[ScopeType]:
20+
protected val init: Init[ScopeType]
21+
import init._
22+
23+
val transform: [A] => Initialize[A] => Unit = [A] =>
24+
(fa: Initialize[A]) =>
25+
fa match
26+
case k: Keyed[s, A] => ???
27+
case b: Bind[s, A] => ???
28+
case v: Value[A] => ???
29+
case v: ValidationCapture[a] => ??? // unrearchable warning
30+
case t: TransformCapture => ??? // unrearchable warning
31+
case o: Optional[s, A] => ??? // unrearchable warning
32+
case StaticScopes => ??? // unrearchable warning
33+

Diff for: tests/warn/i21845.scala

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
trait Outer[O1]:
2+
sealed trait Foo[A1]
3+
final class Bar[A2] extends Foo[A2]
4+
final class Baz[A4] extends Foo[Bar[A4]]
5+
final class Qux extends Foo[[a5] => Foo[a5] => Foo[a5]]
6+
7+
trait Test[O2]:
8+
val outer: Outer[O2]
9+
import outer.*
10+
11+
def test[X](fa: Foo[X]): Unit =
12+
fa match // was: inexhaustive: fail on _: (Outer[<?>] & (Test#outer : Outer[Test#O2]))#Qux
13+
case _: Bar[X] => ???
14+
case _: Baz[x] => ??? // was: unrearchable warning
15+
case _: Qux => ??? // was: unrearchable warning

0 commit comments

Comments
 (0)