Skip to content

Commit

Permalink
Shared pattern analysis: add support for pattern variable assignment.
Browse files Browse the repository at this point in the history
Bug: #50585
Change-Id: I1939c6fd8fac205abeac5b0a9b3da9b3b4adca01
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/274604
Commit-Queue: Paul Berry <[email protected]>
Reviewed-by: Konstantin Shcheglov <[email protected]>
  • Loading branch information
stereotype441 authored and Commit Queue committed Dec 9, 2022
1 parent 9f2a622 commit 966aed6
Show file tree
Hide file tree
Showing 10 changed files with 574 additions and 202 deletions.
112 changes: 77 additions & 35 deletions pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,14 @@ abstract class FlowAnalysis<Node extends Object, Statement extends Node,
/// A function parameter is always initialized, so [initialized] is `true`.
void declare(Variable variable, bool initialized);

/// Call this method after visiting a variable pattern in a non-assignment
/// context (or a wildcard pattern).
///
/// [matchedType] should be the static type of the value being matched.
/// [staticType] should be the static type of the variable pattern itself.
void declaredVariablePattern(
{required Type matchedType, required Type staticType});

/// Call this method before visiting the body of a "do-while" statement.
/// [doStatement] should be the same node that was passed to
/// [AssignedVariables.endNode] for the do-while statement.
Expand Down Expand Up @@ -518,6 +526,15 @@ abstract class FlowAnalysis<Node extends Object, Statement extends Node,
void parenthesizedExpression(
Expression outerExpression, Expression innerExpression);

/// Call this method just after visiting the right hand side of a pattern
/// assignment expression, and before visiting the pattern.
///
/// [rhs] is the right hand side expression.
void patternAssignment_afterRhs(Expression rhs);

/// Call this method after visiting a pattern assignment expression.
void patternAssignment_end();

/// Call this method just after visiting the initializer of a pattern variable
/// declaration, and before visiting the pattern.
void patternVariableDeclaration_afterInitializer(Expression initializer);
Expand Down Expand Up @@ -746,12 +763,6 @@ abstract class FlowAnalysis<Node extends Object, Statement extends Node,
/// statement.
void tryFinallyStatement_finallyBegin(Node body);

/// Call this method after visiting a variable pattern.
///
/// [matchedType] should be the static type of the value being matched.
/// [staticType] should be the static type of the variable pattern itself.
void variablePattern({required Type matchedType, required Type staticType});

/// Call this method when encountering an expression that reads the value of
/// a variable.
///
Expand Down Expand Up @@ -950,6 +961,16 @@ class FlowAnalysisDebug<Node extends Object, Statement extends Node,
() => _wrapped.declare(variable, initialized));
}

@override
void declaredVariablePattern(
{required Type matchedType, required Type staticType}) {
_wrap(
'declaredVariablePattern(matchedType: $matchedType, '
'staticType: $staticType)',
() => _wrapped.declaredVariablePattern(
matchedType: matchedType, staticType: staticType));
}

@override
void doStatement_bodyBegin(Statement doStatement) {
return _wrap('doStatement_bodyBegin($doStatement)',
Expand Down Expand Up @@ -1243,6 +1264,17 @@ class FlowAnalysisDebug<Node extends Object, Statement extends Node,
_wrapped.parenthesizedExpression(outerExpression, innerExpression));
}

@override
void patternAssignment_afterRhs(Expression rhs) {
_wrap('patternAssignment_afterRhs($rhs)',
() => _wrapped.patternAssignment_afterRhs(rhs));
}

@override
void patternAssignment_end() {
_wrap('patternAssignment_end()', () => _wrapped.patternAssignment_end());
}

@override
void patternVariableDeclaration_afterInitializer(Expression initializer) {
_wrap(
Expand Down Expand Up @@ -1405,14 +1437,6 @@ class FlowAnalysisDebug<Node extends Object, Statement extends Node,
() => _wrapped.tryFinallyStatement_finallyBegin(body));
}

@override
void variablePattern({required Type matchedType, required Type staticType}) {
_wrap(
'variablePattern(matchedType: $matchedType, staticType: $staticType)',
() => _wrapped.variablePattern(
matchedType: matchedType, staticType: staticType));
}

@override
Type? variableRead(Expression expression, Variable variable) {
return _wrap('variableRead($expression, $variable)',
Expand Down Expand Up @@ -3371,6 +3395,25 @@ class _FlowAnalysisImpl<Node extends Object, Statement extends Node,
promotionKeyStore.keyForVariable(variable), initialized);
}

@override
void declaredVariablePattern(
{required Type matchedType, required Type staticType}) {
_PatternContext<Type> context = _stack.last as _PatternContext<Type>;
ReferenceWithType<Type>? scrutineeReference = context._scrutineeReference;
bool coversMatchedType =
typeOperations.isSubtypeOf(matchedType, staticType);
if (scrutineeReference != null) {
ExpressionInfo<Type> promotionInfo =
_current.tryPromoteForTypeCheck(this, scrutineeReference, staticType);
_current = promotionInfo.ifTrue;
if (!coversMatchedType) {
context._unmatched = _join(context._unmatched, promotionInfo.ifFalse);
}
} else if (!coversMatchedType) {
context._unmatched = _join(context._unmatched, _current);
}
}

@override
void doStatement_bodyBegin(Statement doStatement) {
AssignedVariablesNodeInfo info =
Expand Down Expand Up @@ -3848,6 +3891,16 @@ class _FlowAnalysisImpl<Node extends Object, Statement extends Node,
forwardExpression(outerExpression, innerExpression);
}

@override
void patternAssignment_afterRhs(Expression rhs) {
_pushPattern(_getExpressionReference(rhs));
}

@override
void patternAssignment_end() {
_popPattern(null);
}

@override
void patternVariableDeclaration_afterInitializer(Expression initializer) {
_pushPattern(_getExpressionReference(initializer));
Expand Down Expand Up @@ -4048,24 +4101,6 @@ class _FlowAnalysisImpl<Node extends Object, Statement extends Node,
context._beforeFinally = _current;
}

@override
void variablePattern({required Type matchedType, required Type staticType}) {
_PatternContext<Type> context = _stack.last as _PatternContext<Type>;
ReferenceWithType<Type>? scrutineeReference = context._scrutineeReference;
bool coversMatchedType =
typeOperations.isSubtypeOf(matchedType, staticType);
if (scrutineeReference != null) {
ExpressionInfo<Type> promotionInfo =
_current.tryPromoteForTypeCheck(this, scrutineeReference, staticType);
_current = promotionInfo.ifTrue;
if (!coversMatchedType) {
context._unmatched = _join(context._unmatched, promotionInfo.ifFalse);
}
} else if (!coversMatchedType) {
context._unmatched = _join(context._unmatched, _current);
}
}

@override
Type? variableRead(Expression expression, Variable variable) {
int variableKey = promotionKeyStore.keyForVariable(variable);
Expand Down Expand Up @@ -4510,6 +4545,10 @@ class _LegacyTypePromotion<Node extends Object, Statement extends Node,
@override
void declare(Variable variable, bool initialized) {}

@override
void declaredVariablePattern(
{required Type matchedType, required Type staticType}) {}

@override
void doStatement_bodyBegin(Statement doStatement) {}

Expand Down Expand Up @@ -4778,6 +4817,12 @@ class _LegacyTypePromotion<Node extends Object, Statement extends Node,
forwardExpression(outerExpression, innerExpression);
}

@override
void patternAssignment_afterRhs(Expression rhs) {}

@override
void patternAssignment_end() {}

@override
void patternVariableDeclaration_afterInitializer(Expression initializer) {}

Expand Down Expand Up @@ -4858,9 +4903,6 @@ class _LegacyTypePromotion<Node extends Object, Statement extends Node,
@override
void tryFinallyStatement_finallyBegin(Node body) {}

@override
void variablePattern({required Type matchedType, required Type staticType}) {}

@override
Type? variableRead(Expression expression, Variable variable) {
int variableKey = _promotionKeyStore.keyForVariable(variable);
Expand Down
Loading

0 comments on commit 966aed6

Please sign in to comment.