@@ -3,9 +3,7 @@ package dotc
33package transform
44package 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 .*
97import ast .* , tpd .*
108import config .Printers .*
119import 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}
0 commit comments