@@ -232,37 +232,61 @@ private Expr getQualifier(QualifiableExpr e) {
232232 result = e .getChildExpr ( - 1 )
233233}
234234
235+ pragma [ noinline]
236+ private predicate typePatternMustHaveMatchingCompletion (
237+ TypePatternExpr tpe , Type t , Type strippedType
238+ ) {
239+ exists ( Expr e , Expr stripped | mustHaveMatchingCompletion ( e , tpe ) |
240+ stripped = e .stripCasts ( ) and
241+ t = tpe .getCheckedType ( ) and
242+ strippedType = stripped .getType ( ) and
243+ not t .containsTypeParameters ( ) and
244+ not strippedType .containsTypeParameters ( )
245+ )
246+ }
247+
248+ pragma [ noinline]
249+ private Type typePatternCommonSubTypeLeft ( Type t ) {
250+ typePatternMustHaveMatchingCompletion ( _, t , _) and
251+ result .isImplicitlyConvertibleTo ( t ) and
252+ not result instanceof DynamicType
253+ }
254+
255+ pragma [ noinline]
256+ private Type typePatternCommonSubTypeRight ( Type strippedType ) {
257+ typePatternMustHaveMatchingCompletion ( _, _, strippedType ) and
258+ result .isImplicitlyConvertibleTo ( strippedType ) and
259+ not result instanceof DynamicType
260+ }
261+
262+ pragma [ noinline]
263+ private predicate typePatternCommonSubType ( Type t , Type strippedType ) {
264+ typePatternCommonSubTypeLeft ( t ) = typePatternCommonSubTypeRight ( strippedType )
265+ }
266+
235267/**
236- * Holds if expression `e ` constantly matches (`value = true`) or constantly
237- * non-matches (`value = false`).
268+ * Holds if pattern expression `pe ` constantly matches (`value = true`) or
269+ * constantly non-matches (`value = false`).
238270 */
239- private predicate isMatchingConstant ( Expr e , boolean value ) {
240- exists ( Switch s | mustHaveMatchingCompletion ( s , e ) |
241- exists ( Expr stripped | stripped = s .getExpr ( ) .stripCasts ( ) |
242- exists ( Case c , string strippedValue |
243- c = s .getACase ( ) and
244- e = c .getPattern ( ) and
245- strippedValue = stripped .getValue ( )
246- |
247- if strippedValue = e .getValue ( ) then value = true else value = false
248- )
249- or
250- exists ( Case c , TypePatternExpr tpe , Type t , Type strippedType | c = s .getACase ( ) |
251- tpe = c .getPattern ( ) and
252- e = tpe and
253- t = tpe .getCheckedType ( ) and
254- strippedType = stripped .getType ( ) and
255- not t .isImplicitlyConvertibleTo ( strippedType ) and
256- not t instanceof Interface and
257- not t .containsTypeParameters ( ) and
258- not strippedType .containsTypeParameters ( ) and
259- value = false
271+ private predicate isMatchingConstant ( PatternExpr pe , boolean value ) {
272+ exists ( Expr e | mustHaveMatchingCompletion ( e , pe ) |
273+ exists ( Expr stripped | stripped = e .stripCasts ( ) |
274+ exists ( string strippedValue , string patternValue |
275+ strippedValue = stripped .getValue ( ) and
276+ patternValue = pe .getValue ( ) and
277+ if strippedValue = patternValue then value = true else value = false
260278 )
261279 )
262280 or
263- e instanceof DiscardPatternExpr and
281+ pe instanceof DiscardPatternExpr and
264282 value = true
265283 )
284+ or
285+ exists ( Type t , Type strippedType |
286+ typePatternMustHaveMatchingCompletion ( pe , t , strippedType ) and
287+ not typePatternCommonSubType ( t , strippedType ) and
288+ value = false
289+ )
266290}
267291
268292private class Overflowable extends UnaryOperation {
@@ -518,7 +542,20 @@ predicate switchMatching(Switch s, Case c, PatternExpr pe) {
518542 pe = c .getPattern ( )
519543}
520544
521- private predicate mustHaveMatchingCompletion ( Switch s , PatternExpr pe ) { switchMatching ( s , _, pe ) }
545+ /**
546+ * Holds if `pe` must have a matching completion, and `e` is the expression
547+ * that is being matched.
548+ */
549+ private predicate mustHaveMatchingCompletion ( Expr e , PatternExpr pe ) {
550+ exists ( Switch s |
551+ switchMatching ( s , _, pe ) and
552+ e = s .getExpr ( )
553+ )
554+ or
555+ pe = any ( IsExpr ie | inBooleanContext ( ie ) and e = ie .getExpr ( ) ) .getPattern ( )
556+ or
557+ pe = any ( UnaryPatternExpr upe | mustHaveMatchingCompletion ( e , upe ) ) .getPattern ( )
558+ }
522559
523560/**
524561 * Holds if a normal completion of `cfe` must be a matching completion. Thats is,
@@ -565,7 +602,13 @@ class SimpleCompletion extends NonNestedNormalCompletion, TSimpleCompletion {
565602 * completion (`NullnessCompletion`), a matching completion (`MatchingCompletion`),
566603 * or an emptiness completion (`EmptinessCompletion`).
567604 */
568- abstract class ConditionalCompletion extends NonNestedNormalCompletion { }
605+ abstract class ConditionalCompletion extends NonNestedNormalCompletion {
606+ /** Gets the Boolean value of this completion. */
607+ abstract boolean getValue ( ) ;
608+
609+ /** Gets the dual completion. */
610+ abstract ConditionalCompletion getDual ( ) ;
611+ }
569612
570613/**
571614 * A completion that represents evaluation of an expression
@@ -576,10 +619,9 @@ class BooleanCompletion extends ConditionalCompletion {
576619
577620 BooleanCompletion ( ) { this = TBooleanCompletion ( value ) }
578621
579- /** Gets the Boolean value of this completion. */
580- boolean getValue ( ) { result = value }
622+ override boolean getValue ( ) { result = value }
581623
582- BooleanCompletion getDual ( ) { result = TBooleanCompletion ( value .booleanNot ( ) ) }
624+ override BooleanCompletion getDual ( ) { result = TBooleanCompletion ( value .booleanNot ( ) ) }
583625
584626 override BooleanSuccessor getAMatchingSuccessorType ( ) { result .getValue ( ) = value }
585627
@@ -611,6 +653,10 @@ class NullnessCompletion extends ConditionalCompletion, TNullnessCompletion {
611653 /** Holds if the last sub expression of this expression evaluates to a non-`null` value. */
612654 predicate isNonNull ( ) { value = false }
613655
656+ override boolean getValue ( ) { result = value }
657+
658+ override NullnessCompletion getDual ( ) { result = TNullnessCompletion ( value .booleanNot ( ) ) }
659+
614660 override NullnessSuccessor getAMatchingSuccessorType ( ) { result .getValue ( ) = value }
615661
616662 override string toString ( ) { if this .isNull ( ) then result = "null" else result = "non-null" }
@@ -631,6 +677,10 @@ class MatchingCompletion extends ConditionalCompletion, TMatchingCompletion {
631677 /** Holds if there is not a match. */
632678 predicate isNonMatch ( ) { value = false }
633679
680+ override boolean getValue ( ) { result = value }
681+
682+ override MatchingCompletion getDual ( ) { result = TMatchingCompletion ( value .booleanNot ( ) ) }
683+
634684 override MatchingSuccessor getAMatchingSuccessorType ( ) { result .getValue ( ) = value }
635685
636686 override string toString ( ) { if this .isMatch ( ) then result = "match" else result = "no-match" }
@@ -648,6 +698,10 @@ class EmptinessCompletion extends ConditionalCompletion, TEmptinessCompletion {
648698 /** Holds if the emptiness test evaluates to `true`. */
649699 predicate isEmpty ( ) { value = true }
650700
701+ override boolean getValue ( ) { result = value }
702+
703+ override EmptinessCompletion getDual ( ) { result = TEmptinessCompletion ( value .booleanNot ( ) ) }
704+
651705 override EmptinessSuccessor getAMatchingSuccessorType ( ) { result .getValue ( ) = value }
652706
653707 override string toString ( ) { if this .isEmpty ( ) then result = "empty" else result = "non-empty" }
0 commit comments