Skip to content

Commit 8d3b319

Browse files
committed
Revert Backport "Fix a bundle of patmat issues" to 3.3.4
1 parent 179371b commit 8d3b319

16 files changed

+30
-224
lines changed

compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala

+12-2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ class PatternMatcher extends MiniPhase {
3535

3636
override def runsAfter: Set[String] = Set(ElimRepeated.name)
3737

38+
private val InInlinedCode = new util.Property.Key[Boolean]
39+
private def inInlinedCode(using Context) = ctx.property(InInlinedCode).getOrElse(false)
40+
41+
override def prepareForInlined(tree: Inlined)(using Context): Context =
42+
if inInlinedCode then ctx
43+
else ctx.fresh.setProperty(InInlinedCode, true)
44+
3845
override def transformMatch(tree: Match)(using Context): Tree =
3946
if (tree.isInstanceOf[InlineMatch]) tree
4047
else {
@@ -46,10 +53,13 @@ class PatternMatcher extends MiniPhase {
4653
case rt => tree.tpe
4754
val translated = new Translator(matchType, this).translateMatch(tree)
4855

49-
// Skip analysis on inlined code (eg pos/i19157)
50-
if !tpd.enclosingInlineds.nonEmpty then
56+
if !inInlinedCode then
5157
// check exhaustivity and unreachability
5258
SpaceEngine.checkMatch(tree)
59+
else
60+
// only check exhaustivity, as inlining may generate unreachable code
61+
// like in i19157.scala
62+
SpaceEngine.checkMatchExhaustivityOnly(tree)
5363

5464
translated.ensureConforms(matchType)
5565
}

compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

+18-60
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ package dotc
33
package transform
44
package patmat
55

6-
import core.*
7-
import Constants.*, Contexts.*, Decorators.*, Flags.*, NullOpsDecorator.*, Symbols.*, Types.*
8-
import Names.*, NameOps.*, StdNames.*
6+
import core.*, Constants.*, Contexts.*, Decorators.*, Flags.*, Names.*, NameOps.*, StdNames.*, Symbols.*, Types.*
97
import ast.*, tpd.*
108
import config.Printers.*
119
import printing.{ Printer, * }, Texts.*
@@ -361,7 +359,7 @@ object SpaceEngine {
361359
val funRef = fun1.tpe.asInstanceOf[TermRef]
362360
if (fun.symbol.name == nme.unapplySeq)
363361
val (arity, elemTp, resultTp) = unapplySeqInfo(fun.tpe.widen.finalResultType, fun.srcPos)
364-
if fun.symbol.owner == defn.SeqFactoryClass && pat.tpe.hasClassSymbol(defn.ListClass) then
362+
if (fun.symbol.owner == defn.SeqFactoryClass && defn.ListType.appliedTo(elemTp) <:< pat.tpe)
365363
// The exhaustivity and reachability logic already handles decomposing sum types (into its subclasses)
366364
// and product types (into its components). To get better counter-examples for patterns that are of type
367365
// List (or a super-type of list, like LinearSeq) we project them into spaces that use `::` and Nil.
@@ -533,26 +531,14 @@ object SpaceEngine {
533531
val mt: MethodType = unapp.widen match {
534532
case mt: MethodType => mt
535533
case pt: PolyType =>
536-
val locked = ctx.typerState.ownedVars
537534
val tvars = constrained(pt)
538535
val mt = pt.instantiate(tvars).asInstanceOf[MethodType]
539536
scrutineeTp <:< mt.paramInfos(0)
540537
// force type inference to infer a narrower type: could be singleton
541538
// see tests/patmat/i4227.scala
542539
mt.paramInfos(0) <:< scrutineeTp
543-
maximizeType(mt.paramInfos(0), Spans.NoSpan)
544-
if !(ctx.typerState.ownedVars -- locked).isEmpty then
545-
// constraining can create type vars out of wildcard types
546-
// (in legalBound, by using a LevelAvoidMap)
547-
// maximise will only do one pass at maximising the type vars in the target type
548-
// which means we can maximise to types that include other type vars
549-
// this fails TreeChecker's "non-empty constraint at end of $fusedPhase" check
550-
// e.g. run-macros/string-context-implicits
551-
// I can't prove that a second call won't also create type vars,
552-
// but I'd rather have an unassigned new-new type var, than an infinite loop.
553-
// After all, there's nothing strictly "wrong" with unassigned type vars,
554-
// it just fails TreeChecker's linting.
555-
maximizeType(mt.paramInfos(0), Spans.NoSpan)
540+
instantiateSelected(mt, tvars)
541+
isFullyDefined(mt, ForceDegree.all)
556542
mt
557543
}
558544

@@ -566,7 +552,7 @@ object SpaceEngine {
566552
// Case unapplySeq:
567553
// 1. return the type `List[T]` where `T` is the element type of the unapplySeq return type `Seq[T]`
568554

569-
val resTp = wildApprox(ctx.typeAssigner.safeSubstMethodParams(mt, scrutineeTp :: Nil).finalResultType)
555+
val resTp = ctx.typeAssigner.safeSubstMethodParams(mt, scrutineeTp :: Nil).finalResultType
570556

571557
val sig =
572558
if (resTp.isRef(defn.BooleanClass))
@@ -587,14 +573,14 @@ object SpaceEngine {
587573
if (arity > 0)
588574
productSelectorTypes(resTp, unappSym.srcPos)
589575
else {
590-
val getTp = extractorMemberType(resTp, nme.get, unappSym.srcPos)
576+
val getTp = resTp.select(nme.get).finalResultType.widenTermRefExpr
591577
if (argLen == 1) getTp :: Nil
592578
else productSelectorTypes(getTp, unappSym.srcPos)
593579
}
594580
}
595581
}
596582

597-
sig.map { case tp: WildcardType => tp.bounds.hi case tp => tp }
583+
sig.map(_.annotatedToRepeated)
598584
}
599585

600586
/** Whether the extractor covers the given type */
@@ -632,36 +618,14 @@ object SpaceEngine {
632618
case tp if tp.classSymbol.isAllOf(JavaEnumTrait) => tp.classSymbol.children.map(_.termRef)
633619
// the class of a java enum value is the enum class, so this must follow SingletonType to not loop infinitely
634620

635-
case Childless(tp @ AppliedType(Parts(parts), targs)) =>
621+
case tp @ AppliedType(Parts(parts), targs) if tp.classSymbol.children.isEmpty =>
636622
// It might not obvious that it's OK to apply the type arguments of a parent type to child types.
637623
// But this is guarded by `tp.classSymbol.children.isEmpty`,
638624
// meaning we'll decompose to the same class, just not the same type.
639625
// For instance, from i15029, `decompose((X | Y).Field[T]) = [X.Field[T], Y.Field[T]]`.
640626
parts.map(tp.derivedAppliedType(_, targs))
641627

642-
case tpOriginal if tpOriginal.isDecomposableToChildren =>
643-
// isDecomposableToChildren uses .classSymbol.is(Sealed)
644-
// But that classSymbol could be from an AppliedType
645-
// where the type constructor is a non-class type
646-
// E.g. t11620 where `?1.AA[X]` returns as "sealed"
647-
// but using that we're not going to infer A1[X] and A2[X]
648-
// but end up with A1[<?>] and A2[<?>].
649-
// So we widen (like AppliedType superType does) away
650-
// non-class type constructors.
651-
//
652-
// Can't use `tpOriginal.baseType(cls)` because it causes
653-
// i15893 to return exhaustivity warnings, because instead of:
654-
// <== refineUsingParent(N, class Succ, []) = Succ[<? <: NatT>]
655-
// <== isSub(Succ[<? <: NatT>] <:< Succ[Succ[<?>]]) = true
656-
// we get
657-
// <== refineUsingParent(NatT, class Succ, []) = Succ[NatT]
658-
// <== isSub(Succ[NatT] <:< Succ[Succ[<?>]]) = false
659-
def getAppliedClass(tp: Type): Type = tp match
660-
case tp @ AppliedType(_: HKTypeLambda, _) => tp
661-
case tp @ AppliedType(tycon: TypeRef, _) if tycon.symbol.isClass => tp
662-
case tp @ AppliedType(tycon: TypeProxy, _) => getAppliedClass(tycon.superType.applyIfParameterized(tp.args))
663-
case tp => tp
664-
val tp = getAppliedClass(tpOriginal)
628+
case tp if tp.isDecomposableToChildren =>
665629
def getChildren(sym: Symbol): List[Symbol] =
666630
sym.children.flatMap { child =>
667631
if child eq sym then List(sym) // i3145: sealed trait Baz, val x = new Baz {}, Baz.children returns Baz...
@@ -714,12 +678,6 @@ object SpaceEngine {
714678
final class PartsExtractor(val get: List[Type]) extends AnyVal:
715679
def isEmpty: Boolean = get == ListOfNoType
716680

717-
object Childless:
718-
def unapply(tp: Type)(using Context): Result =
719-
Result(if tp.classSymbol.children.isEmpty then tp else NoType)
720-
class Result(val get: Type) extends AnyVal:
721-
def isEmpty: Boolean = !get.exists
722-
723681
/** Show friendly type name with current scope in mind
724682
*
725683
* E.g. C.this.B --> B if current owner is C
@@ -816,15 +774,12 @@ object SpaceEngine {
816774
doShow(s)
817775
}
818776

819-
extension (self: Type) private def stripUnsafeNulls()(using Context): Type =
820-
if Nullables.unsafeNullsEnabled then self.stripNull else self
821-
822-
private def exhaustivityCheckable(sel: Tree)(using Context): Boolean = trace(i"exhaustivityCheckable($sel ${sel.className})") {
777+
private def exhaustivityCheckable(sel: Tree)(using Context): Boolean = {
823778
val seen = collection.mutable.Set.empty[Symbol]
824779

825780
// Possible to check everything, but be compatible with scalac by default
826-
def isCheckable(tp: Type): Boolean = trace(i"isCheckable($tp ${tp.className})"):
827-
val tpw = tp.widen.dealias.stripUnsafeNulls()
781+
def isCheckable(tp: Type): Boolean =
782+
val tpw = tp.widen.dealias
828783
val classSym = tpw.classSymbol
829784
classSym.is(Sealed) && !tpw.isLargeGenericTuple || // exclude large generic tuples from exhaustivity
830785
// requires an unknown number of changes to make work
@@ -859,7 +814,7 @@ object SpaceEngine {
859814
/** Return the underlying type of non-module, non-constant, non-enum case singleton types.
860815
* Also widen ExprType to its result type, and rewrap any annotation wrappers.
861816
* For example, with `val opt = None`, widen `opt.type` to `None.type`. */
862-
def toUnderlying(tp: Type)(using Context): Type = trace(i"toUnderlying($tp ${tp.className})")(tp match {
817+
def toUnderlying(tp: Type)(using Context): Type = trace(i"toUnderlying($tp)")(tp match {
863818
case _: ConstantType => tp
864819
case tp: TermRef if tp.symbol.is(Module) => tp
865820
case tp: TermRef if tp.symbol.isAllOf(EnumCase) => tp
@@ -870,7 +825,7 @@ object SpaceEngine {
870825
})
871826

872827
def checkExhaustivity(m: Match)(using Context): Unit = trace(i"checkExhaustivity($m)") {
873-
val selTyp = toUnderlying(m.selector.tpe.stripUnsafeNulls()).dealias
828+
val selTyp = toUnderlying(m.selector.tpe).dealias
874829
val targetSpace = trace(i"targetSpace($selTyp)")(project(selTyp))
875830

876831
val patternSpace = Or(m.cases.foldLeft(List.empty[Space]) { (acc, x) =>
@@ -948,6 +903,9 @@ object SpaceEngine {
948903
}
949904

950905
def checkMatch(m: Match)(using Context): Unit =
951-
if exhaustivityCheckable(m.selector) then checkExhaustivity(m)
906+
checkMatchExhaustivityOnly(m)
952907
if reachabilityCheckable(m.selector) then checkReachability(m)
908+
909+
def checkMatchExhaustivityOnly(m: Match)(using Context): Unit =
910+
if exhaustivityCheckable(m.selector) then checkExhaustivity(m)
953911
}

tests/warn/i15893.min.scala

-13
This file was deleted.

tests/warn/i20121.scala

-13
This file was deleted.

tests/warn/i20122.scala

-17
This file was deleted.

tests/warn/i20123.scala

-16
This file was deleted.

tests/warn/i20128.scala

-9
This file was deleted.

tests/warn/i20129.scala

-14
This file was deleted.

tests/warn/i20130.scala

-11
This file was deleted.

tests/warn/i20131.scala

-17
This file was deleted.

tests/warn/i20132.alt.scala

-8
This file was deleted.

tests/warn/i20132.list-Seq.scala

-10
This file was deleted.

tests/warn/i20132.scala

-8
This file was deleted.

tests/warn/i20132.wo.scala

-8
This file was deleted.

tests/warn/i5422.scala

-9
This file was deleted.

tests/warn/t11620.scala

-9
This file was deleted.

0 commit comments

Comments
 (0)