Flow analysis: add assertions to AssignedVariables.declare.

These assertions verify that the client doesn't try to call `declare`
more than once on the same variable.  They should help avoid bugs as I
work on integrating the logic for variable patterns more deeply with
flow analyis.

Change-Id: Ic7ffec8bd5f542cef0067a5308d86de6e48ec8ea
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/274521
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Paul Berry 2022-12-12 17:05:23 +00:00 committed by Commit Queue
parent 3e8b72cfbf
commit 1495d298f4
3 changed files with 24 additions and 9 deletions

View file

@ -75,11 +75,19 @@ class AssignedVariables<Node extends Object, Variable extends Object> {
///
/// It is not required for the declaration to be seen prior to its use (this
/// is to allow for error recovery in the analyzer).
void declare(Variable variable) {
///
/// By default, this method contains assertions to make sure the client
/// doesn't call [declare] more than once on the same variable. However,
/// there are some situations where it is difficult for the client to avoid
/// this, so the check can be disabled by passing `true` for
/// [ignoreDuplicates].
void declare(Variable variable, {bool ignoreDuplicates = false}) {
assert(!_isFinished);
int variableKey = promotionKeyStore.keyForVariable(variable);
_stack.last.declared.add(variableKey);
anywhere.declared.add(variableKey);
bool newlyDeclared = _stack.last.declared.add(variableKey);
assert(ignoreDuplicates || newlyDeclared);
newlyDeclared = anywhere.declared.add(variableKey);
assert(ignoreDuplicates || newlyDeclared);
}
/// This method may be called during pre-traversal, to mark the end of a
@ -171,8 +179,11 @@ class AssignedVariables<Node extends Object, Variable extends Object> {
assert(_stack.length == 1, "Unexpected stack: $_stack");
AssignedVariablesNodeInfo last = _stack.last;
Set<int> undeclaredReads = last.read.difference(last.declared);
assert(undeclaredReads.isEmpty,
'Variables read from but not declared: $undeclaredReads');
List<Variable?> undeclaredReadVars = [
for (int key in undeclaredReads) promotionKeyStore.variableForKey(key)
];
assert(undeclaredReadVars.isEmpty,
'Variables read from but not declared: $undeclaredReadVars');
Set<int> undeclaredWrites = last.written.difference(last.declared);
assert(undeclaredWrites.isEmpty,
'Variables written to but not declared: $undeclaredWrites');

View file

@ -694,16 +694,18 @@ class _AssignedVariablesVisitor extends RecursiveAstVisitor<void> {
member.expression.accept(this);
} else if (member is SwitchPatternCaseImpl) {
var guardedPattern = member.guardedPattern;
assignedVariables.beginNode();
guardedPattern.pattern.accept(this);
for (var variable in guardedPattern.variables.values) {
assignedVariables.declare(variable);
}
guardedPattern.whenClause?.accept(this);
assignedVariables.endNode(node);
}
}
for (var variable in group.variables.values) {
assignedVariables.declare(variable);
// We pass `ignoreDuplicates: true` because this variable might be the
// same as one of the variables declared earlier under a specific switch
// case.
assignedVariables.declare(variable, ignoreDuplicates: true);
}
group.statements.accept(this);
}

View file

@ -5071,7 +5071,9 @@ class BodyBuilder extends StackListenerImpl
}
}
push(parameter);
typeInferrer.assignedVariables.declare(variable);
// We pass `ignoreDuplicates: true` because the variable might have been
// previously passed to `declare` in the `BodyBuilder` constructor.
typeInferrer.assignedVariables.declare(variable, ignoreDuplicates: true);
}
@override