@@ -362,7 +362,16 @@ abstract class FlowAnalysis<Node, Statement extends Node, Expression, Variable,
362362 void doStatement_end (Expression condition);
363363
364364 /// Call this method just after visiting a binary `==` or `!=` expression.
365- void equalityOp_end (Expression wholeExpression, Expression rightOperand,
365+ ///
366+ /// Return value indicates whether flow analysis believes that a successful
367+ /// equality check is reachable. If `false` is returned, the client should
368+ /// ensure that the `==` test behaves like `x == y && throw ...` .
369+ ///
370+ /// Note that if `notEqual` is `true` , then the return value describes the
371+ /// behavior of the underlying `==` test. So if `notEqual` is `true` and
372+ /// `false` is returned, the client should ensure that the `!=` test behaves
373+ /// like `!(x == y && throw ...)` .
374+ bool equalityOp_end (Expression wholeExpression, Expression rightOperand,
366375 Type rightOperandType,
367376 {bool notEqual = false });
368377
@@ -475,7 +484,13 @@ abstract class FlowAnalysis<Node, Statement extends Node, Expression, Variable,
475484
476485 /// Call this method after visiting the LHS of an if-null expression ("??")
477486 /// or if-null assignment ("??=").
478- void ifNullExpression_rightBegin (Expression leftHandSide);
487+ ///
488+ /// Return value indicates whether flow analysis believes that the right hand
489+ /// side is reachable. If `false` is returned, the client should ensure that
490+ /// `x ?? y` behaves like `x ?? throw ...` (or, correspondingly, that
491+ /// `x ??= y` behaves like `x ??= throw ...` ).
492+ bool ifNullExpression_rightBegin (
493+ Expression leftHandSide, Type leftHandSideType);
479494
480495 /// Call this method after visiting the "then" part of an if statement, and
481496 /// before visiting the "else" part.
@@ -511,7 +526,16 @@ abstract class FlowAnalysis<Node, Statement extends Node, Expression, Variable,
511526 /// be the expression to which the "is" check was applied. [isNot] should be
512527 /// a boolean indicating whether this is an "is" or an "is!" expression.
513528 /// [type] should be the type being checked.
514- void isExpression_end (
529+ ///
530+ /// Return value indicates whether flow analysis believes that a failure of
531+ /// the `is` test is reachable. If `false` is returned, the client should
532+ /// ensure that the `is` test behaves like `x is T || throw ...` .
533+ ///
534+ /// Note that if `isNot` is `true` , then the return value describes the
535+ /// behavior of the underlying `if` test. So if `isNot` is `true` and `false`
536+ /// is returned, the client should ensure that the `is!` test behaves like
537+ /// `!(x is T || throw ...)` .
538+ bool isExpression_end (
515539 Expression isExpression, Expression subExpression, bool isNot, Type type);
516540
517541 /// Return whether the [variable] is definitely unassigned in the current
@@ -558,12 +582,22 @@ abstract class FlowAnalysis<Node, Statement extends Node, Expression, Variable,
558582 /// [target] should be the expression just before the null-aware operator, or
559583 /// `null` if the null-aware access starts a cascade section.
560584 ///
585+ /// [targetType] should be the type of the expression just before the
586+ /// null-aware operator, and should be non-null even if the null-aware access
587+ /// starts a cascade section.
588+ ///
561589 /// Note that [nullAwareAccess_end] should be called after the conclusion
562590 /// of any null-shorting that is caused by the `?.` . So, for example, if the
563591 /// code being analyzed is `x?.y?.z(x)` , [nullAwareAccess_rightBegin] should
564592 /// be called once upon reaching each `?.` , but [nullAwareAccess_end] should
565593 /// not be called until after processing the method call to `z(x)` .
566- void nullAwareAccess_rightBegin (Expression target);
594+ ///
595+ /// Return value indicates whether flow analysis believes that a null target
596+ /// is reachable. If `false` is returned, the client should ensure that
597+ /// `x?.y` behaves like `x!.y` . (Note that this is necessary even if `y`
598+ /// exists on `Object` --see
599+ /// https://github.com/dart-lang/language/issues/1143#issuecomment-682096575.)
600+ bool nullAwareAccess_rightBegin (Expression target, Type targetType);
567601
568602 /// Call this method when encountering an expression that is a `null` literal.
569603 void nullLiteral (Expression expression);
@@ -811,15 +845,17 @@ class FlowAnalysisDebug<Node, Statement extends Node, Expression, Variable,
811845 }
812846
813847 @override
814- void equalityOp_end (Expression wholeExpression, Expression rightOperand,
848+ bool equalityOp_end (Expression wholeExpression, Expression rightOperand,
815849 Type rightOperandType,
816850 {bool notEqual = false }) {
817- _wrap (
851+ return _wrap (
818852 'equalityOp_end($wholeExpression , $rightOperand , $rightOperandType , '
819853 'notEqual: $notEqual )' ,
820854 () => _wrapped.equalityOp_end (
821855 wholeExpression, rightOperand, rightOperandType,
822- notEqual: notEqual));
856+ notEqual: notEqual),
857+ isQuery: true ,
858+ isPure: false );
823859 }
824860
825861 @override
@@ -902,9 +938,14 @@ class FlowAnalysisDebug<Node, Statement extends Node, Expression, Variable,
902938 }
903939
904940 @override
905- void ifNullExpression_rightBegin (Expression leftHandSide) {
906- return _wrap ('ifNullExpression_rightBegin($leftHandSide )' ,
907- () => _wrapped.ifNullExpression_rightBegin (leftHandSide));
941+ bool ifNullExpression_rightBegin (
942+ Expression leftHandSide, Type leftHandSideType) {
943+ return _wrap (
944+ 'ifNullExpression_rightBegin($leftHandSide , $leftHandSideType )' ,
945+ () => _wrapped.ifNullExpression_rightBegin (
946+ leftHandSide, leftHandSideType),
947+ isQuery: true ,
948+ isPure: false );
908949 }
909950
910951 @override
@@ -931,12 +972,14 @@ class FlowAnalysisDebug<Node, Statement extends Node, Expression, Variable,
931972 }
932973
933974 @override
934- void isExpression_end (Expression isExpression, Expression subExpression,
975+ bool isExpression_end (Expression isExpression, Expression subExpression,
935976 bool isNot, Type type) {
936- _wrap (
977+ return _wrap (
937978 'isExpression_end($isExpression , $subExpression , $isNot , $type )' ,
938- () => _wrapped.isExpression_end (
939- isExpression, subExpression, isNot, type));
979+ () =>
980+ _wrapped.isExpression_end (isExpression, subExpression, isNot, type),
981+ isQuery: true ,
982+ isPure: false );
940983 }
941984
942985 @override
@@ -991,9 +1034,10 @@ class FlowAnalysisDebug<Node, Statement extends Node, Expression, Variable,
9911034 }
9921035
9931036 @override
994- void nullAwareAccess_rightBegin (Expression target) {
995- _wrap ('nullAwareAccess_rightBegin($target )' ,
996- () => _wrapped.nullAwareAccess_rightBegin (target));
1037+ bool nullAwareAccess_rightBegin (Expression target, Type targetType) {
1038+ return _wrap ('nullAwareAccess_rightBegin($target , $targetType )' ,
1039+ () => _wrapped.nullAwareAccess_rightBegin (target, targetType),
1040+ isQuery: true , isPure: false );
9971041 }
9981042
9991043 @override
@@ -2456,7 +2500,7 @@ class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
24562500 }
24572501
24582502 @override
2459- void equalityOp_end (Expression wholeExpression, Expression rightOperand,
2503+ bool equalityOp_end (Expression wholeExpression, Expression rightOperand,
24602504 Type rightOperandType,
24612505 {bool notEqual = false }) {
24622506 _EqualityOpContext <Variable , Type > context =
@@ -2471,14 +2515,16 @@ class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
24712515 typeOperations.classifyType (rightOperandType);
24722516 if (leftOperandTypeClassification == TypeClassification .nullOrEquivalent &&
24732517 rightOperandTypeClassification == TypeClassification .nullOrEquivalent) {
2474- return booleanLiteral (wholeExpression, ! notEqual);
2518+ booleanLiteral (wholeExpression, ! notEqual);
2519+ return true ;
24752520 } else if ((leftOperandTypeClassification ==
24762521 TypeClassification .nullOrEquivalent &&
24772522 rightOperandTypeClassification == TypeClassification .nonNullable) ||
24782523 (rightOperandTypeClassification ==
24792524 TypeClassification .nullOrEquivalent &&
24802525 leftOperandTypeClassification == TypeClassification .nonNullable)) {
2481- return booleanLiteral (wholeExpression, notEqual);
2526+ booleanLiteral (wholeExpression, notEqual);
2527+ return false ;
24822528 } else if (lhsInfo is _NullInfo <Variable , Type > &&
24832529 rhsInfo is _VariableReadInfo <Variable , Type >) {
24842530 assert (
@@ -2490,10 +2536,11 @@ class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
24902536 equalityInfo =
24912537 _current.tryMarkNonNullable (typeOperations, lhsInfo._variable);
24922538 } else {
2493- return ;
2539+ return true ;
24942540 }
24952541 _storeExpressionInfo (wholeExpression,
24962542 notEqual ? equalityInfo : ExpressionInfo .invert (equalityInfo));
2543+ return equalityInfo.ifFalse.reachable;
24972544 }
24982545
24992546 @override
@@ -2619,7 +2666,8 @@ class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
26192666 }
26202667
26212668 @override
2622- void ifNullExpression_rightBegin (Expression leftHandSide) {
2669+ bool ifNullExpression_rightBegin (
2670+ Expression leftHandSide, Type leftHandSideType) {
26232671 ExpressionInfo <Variable , Type > lhsInfo = _getExpressionInfo (leftHandSide);
26242672 FlowModel <Variable , Type > promoted;
26252673 if (lhsInfo is _VariableReadInfo <Variable , Type >) {
@@ -2630,7 +2678,12 @@ class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
26302678 } else {
26312679 promoted = _current;
26322680 }
2681+ if (typeOperations.classifyType (leftHandSideType) ==
2682+ TypeClassification .nonNullable) {
2683+ _current = _current.setReachable (false );
2684+ }
26332685 _stack.add (new _SimpleContext <Variable , Type >(promoted));
2686+ return _current.reachable;
26342687 }
26352688
26362689 @override
@@ -2670,20 +2723,21 @@ class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
26702723 }
26712724
26722725 @override
2673- void isExpression_end (Expression isExpression, Expression subExpression,
2726+ bool isExpression_end (Expression isExpression, Expression subExpression,
26742727 bool isNot, Type type) {
26752728 ExpressionInfo <Variable , Type > subExpressionInfo =
26762729 _getExpressionInfo (subExpression);
26772730 Variable variable;
26782731 if (subExpressionInfo is _VariableReadInfo <Variable , Type >) {
26792732 variable = subExpressionInfo._variable;
26802733 } else {
2681- return ;
2734+ return true ;
26822735 }
26832736 ExpressionInfo <Variable , Type > expressionInfo =
26842737 _current.tryPromoteForTypeCheck (typeOperations, variable, type);
26852738 _storeExpressionInfo (isExpression,
26862739 isNot ? ExpressionInfo .invert (expressionInfo) : expressionInfo);
2740+ return expressionInfo.ifFalse.reachable;
26872741 }
26882742
26892743 @override
@@ -2760,8 +2814,16 @@ class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
27602814 }
27612815
27622816 @override
2763- void nullAwareAccess_rightBegin (Expression target) {
2764- _stack.add (new _SimpleContext <Variable , Type >(_current));
2817+ bool nullAwareAccess_rightBegin (Expression target, Type targetType) {
2818+ assert (targetType != null );
2819+ bool shortingIsReachable = true ;
2820+ FlowModel <Variable , Type > shortingModel = _current;
2821+ if (typeOperations.classifyType (targetType) ==
2822+ TypeClassification .nonNullable) {
2823+ shortingModel = shortingModel.setReachable (false );
2824+ shortingIsReachable = false ;
2825+ }
2826+ _stack.add (new _SimpleContext <Variable , Type >(shortingModel));
27652827 if (target != null ) {
27662828 ExpressionInfo <Variable , Type > targetInfo = _getExpressionInfo (target);
27672829 if (targetInfo is _VariableReadInfo <Variable , Type >) {
@@ -2770,6 +2832,7 @@ class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
27702832 .ifTrue;
27712833 }
27722834 }
2835+ return shortingIsReachable;
27732836 }
27742837
27752838 @override
0 commit comments