[cfe] Verify new variables have contexts
Part of https://github.com/dart-lang/sdk/issues/61572 Change-Id: I01295904c8fd5f76574e8979eb40e4cd174f9e09 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/504202 Reviewed-by: Alexander Markov <alexmarkov@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
This commit is contained in:
committed by
dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent
52cfd29cbb
commit
10dd51ee4c
@@ -1900,11 +1900,13 @@ class LegacyVariable extends TreeNode
|
||||
}
|
||||
|
||||
@override
|
||||
VariableContext get context {
|
||||
// TODO(62620): Conforming to [VariableDeclaration] interface. Remove this.
|
||||
VariableContext? get context {
|
||||
throw new UnsupportedError("${this.runtimeType}.context");
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO(62620): Conforming to [VariableDeclaration] interface. Remove this.
|
||||
void set context(VariableContext value) {
|
||||
throw new UnsupportedError("${this.runtimeType}.context=");
|
||||
}
|
||||
|
||||
@@ -2446,17 +2446,31 @@ class TypeVariable extends VariableBase {
|
||||
@override
|
||||
String? cosmeticName;
|
||||
|
||||
@override
|
||||
late VariableContext context;
|
||||
|
||||
/// Function type parameter this [TypeVariable] is associated with.
|
||||
final TypeParameter parameter;
|
||||
|
||||
@override
|
||||
List<Expression> annotations = const <Expression>[];
|
||||
|
||||
VariableContext? _context;
|
||||
|
||||
TypeVariable({this.cosmeticName, required this.parameter});
|
||||
|
||||
@override
|
||||
VariableContext? get context {
|
||||
assert(
|
||||
_context != null,
|
||||
"The context of a '${runtimeType}' variable with cosmetic name "
|
||||
"'${cosmeticName}' is accessed, but hasn't been set yet.",
|
||||
);
|
||||
return _context;
|
||||
}
|
||||
|
||||
@override
|
||||
void set context(VariableContext value) {
|
||||
_context = value;
|
||||
}
|
||||
|
||||
@override
|
||||
void addAnnotation(Expression annotation) {
|
||||
if (annotations.isEmpty) {
|
||||
|
||||
@@ -6,7 +6,9 @@ part of '../../ast.dart';
|
||||
|
||||
/// Generalized notion of a variable.
|
||||
sealed class VariableBase extends TreeNode implements Annotatable {
|
||||
abstract VariableContext context;
|
||||
VariableContext? get context;
|
||||
|
||||
void set context(VariableContext value);
|
||||
|
||||
/// The cosmetic name of the variable from the source code, if exists.
|
||||
String? get cosmeticName;
|
||||
@@ -30,7 +32,6 @@ abstract interface class IVariable implements TreeNode {
|
||||
abstract String? cosmeticName;
|
||||
abstract VariableInitialization? variableInitialization;
|
||||
abstract Expression? initializer;
|
||||
abstract VariableContext context;
|
||||
abstract bool isFinal;
|
||||
abstract bool isConst;
|
||||
abstract bool isLate;
|
||||
@@ -54,6 +55,9 @@ abstract interface class IVariable implements TreeNode {
|
||||
abstract VariableDeclaration variable;
|
||||
void clearAnnotations();
|
||||
|
||||
VariableContext? get context;
|
||||
void set context(VariableContext value);
|
||||
|
||||
bool get isAssignable;
|
||||
bool get hasIsFinal;
|
||||
bool get hasIsConst;
|
||||
@@ -213,8 +217,7 @@ class LocalVariable extends VariableDeclaration {
|
||||
@override
|
||||
List<Expression> annotations = const <Expression>[];
|
||||
|
||||
@override
|
||||
late VariableContext context;
|
||||
VariableContext? _context;
|
||||
|
||||
LocalVariable({
|
||||
this.cosmeticName,
|
||||
@@ -231,6 +234,21 @@ class LocalVariable extends VariableDeclaration {
|
||||
this.isWildcard = isWildcard;
|
||||
}
|
||||
|
||||
@override
|
||||
VariableContext? get context {
|
||||
assert(
|
||||
_context != null,
|
||||
"The context of a '${runtimeType}' variable with cosmetic name "
|
||||
"'${cosmeticName}' is accessed, but hasn't been set yet.",
|
||||
);
|
||||
return _context;
|
||||
}
|
||||
|
||||
@override
|
||||
void set context(VariableContext value) {
|
||||
_context = value;
|
||||
}
|
||||
|
||||
@override
|
||||
void addAnnotation(Expression annotation) {
|
||||
if (annotations.isEmpty) {
|
||||
@@ -521,8 +539,7 @@ class CatchVariable extends VariableDeclaration {
|
||||
@override
|
||||
List<Expression> annotations = const <Expression>[];
|
||||
|
||||
@override
|
||||
late VariableContext context;
|
||||
VariableContext? _context;
|
||||
|
||||
CatchVariable({
|
||||
required String name,
|
||||
@@ -534,6 +551,21 @@ class CatchVariable extends VariableDeclaration {
|
||||
this.isWildcard = isWildcard;
|
||||
}
|
||||
|
||||
@override
|
||||
VariableContext? get context {
|
||||
assert(
|
||||
_context != null,
|
||||
"The context of a '${runtimeType}' variable with cosmetic name "
|
||||
"'${cosmeticName}' is accessed, but hasn't been set yet.",
|
||||
);
|
||||
return _context;
|
||||
}
|
||||
|
||||
@override
|
||||
void set context(VariableContext value) {
|
||||
_context = value;
|
||||
}
|
||||
|
||||
@override
|
||||
String? get cosmeticName => catchVariableName;
|
||||
|
||||
@@ -1022,8 +1054,7 @@ class PositionalParameter extends FunctionParameter {
|
||||
@override
|
||||
List<Expression> annotations = const <Expression>[];
|
||||
|
||||
@override
|
||||
late VariableContext context;
|
||||
VariableContext? _context;
|
||||
|
||||
PositionalParameter({
|
||||
this.cosmeticName,
|
||||
@@ -1040,6 +1071,21 @@ class PositionalParameter extends FunctionParameter {
|
||||
super.isWildcard = false,
|
||||
});
|
||||
|
||||
@override
|
||||
VariableContext? get context {
|
||||
assert(
|
||||
_context != null,
|
||||
"The context of a '${runtimeType}' variable with cosmetic name "
|
||||
"'${cosmeticName}' is accessed, but hasn't been set yet.",
|
||||
);
|
||||
return _context;
|
||||
}
|
||||
|
||||
@override
|
||||
void set context(VariableContext value) {
|
||||
_context = value;
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO(62620): Conforming to [VariableDeclaration] interface. Remove this.
|
||||
List<VariableContext>? get capturedContexts {
|
||||
@@ -1169,8 +1215,7 @@ class NamedParameter extends FunctionParameter {
|
||||
@override
|
||||
List<Expression> annotations = const <Expression>[];
|
||||
|
||||
@override
|
||||
late VariableContext context;
|
||||
VariableContext? _context;
|
||||
|
||||
NamedParameter({
|
||||
required this.parameterName,
|
||||
@@ -1187,6 +1232,21 @@ class NamedParameter extends FunctionParameter {
|
||||
super.isWildcard = false,
|
||||
});
|
||||
|
||||
@override
|
||||
VariableContext? get context {
|
||||
assert(
|
||||
_context != null,
|
||||
"The context of a '${runtimeType}' variable with cosmetic name "
|
||||
"'${cosmeticName}' is accessed, but hasn't been set yet.",
|
||||
);
|
||||
return _context;
|
||||
}
|
||||
|
||||
@override
|
||||
void set context(VariableContext value) {
|
||||
_context = value;
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO(62620): Conforming to [VariableDeclaration] interface. Remove this.
|
||||
List<VariableContext>? get capturedContexts {
|
||||
@@ -1319,11 +1379,25 @@ class ThisVariable extends VariableDeclaration {
|
||||
@override
|
||||
List<Expression> annotations = const <Expression>[];
|
||||
|
||||
@override
|
||||
late VariableContext context;
|
||||
VariableContext? _context;
|
||||
|
||||
ThisVariable({required this.type}) : super.empty();
|
||||
|
||||
@override
|
||||
VariableContext? get context {
|
||||
assert(
|
||||
_context != null,
|
||||
"The context of a '${runtimeType}' variable with cosmetic name "
|
||||
"'${cosmeticName}' is accessed, but hasn't been set yet.",
|
||||
);
|
||||
return _context;
|
||||
}
|
||||
|
||||
@override
|
||||
void set context(VariableContext value) {
|
||||
_context = value;
|
||||
}
|
||||
|
||||
// TODO(cstefantsova): Consider a throwing implementation instead.
|
||||
@override
|
||||
void addAnnotation(Expression annotation) {
|
||||
@@ -1597,11 +1671,25 @@ class SyntheticVariable extends VariableDeclaration {
|
||||
@override
|
||||
List<Expression> annotations = const <Expression>[];
|
||||
|
||||
@override
|
||||
late VariableContext context;
|
||||
VariableContext? _context;
|
||||
|
||||
SyntheticVariable({this.cosmeticName, required this.type}) : super.empty();
|
||||
|
||||
@override
|
||||
VariableContext? get context {
|
||||
assert(
|
||||
_context != null,
|
||||
"The context of a '${runtimeType}' variable with cosmetic name "
|
||||
"'${cosmeticName}' is accessed, but hasn't been set yet.",
|
||||
);
|
||||
return _context;
|
||||
}
|
||||
|
||||
@override
|
||||
void set context(VariableContext value) {
|
||||
_context = value;
|
||||
}
|
||||
|
||||
// TODO(cstefantsova): Consider a throwing implementation instead.
|
||||
@override
|
||||
void addAnnotation(Expression annotation) {
|
||||
|
||||
@@ -6326,15 +6326,15 @@ class EquivalenceStrategy {
|
||||
if (!checkTypeVariable_cosmeticName(visitor, node, other)) {
|
||||
result = visitor.resultOnInequivalence;
|
||||
}
|
||||
if (!checkTypeVariable_context(visitor, node, other)) {
|
||||
result = visitor.resultOnInequivalence;
|
||||
}
|
||||
if (!checkTypeVariable_parameter(visitor, node, other)) {
|
||||
result = visitor.resultOnInequivalence;
|
||||
}
|
||||
if (!checkTypeVariable_annotations(visitor, node, other)) {
|
||||
result = visitor.resultOnInequivalence;
|
||||
}
|
||||
if (!checkTypeVariable_context(visitor, node, other)) {
|
||||
result = visitor.resultOnInequivalence;
|
||||
}
|
||||
if (!checkTypeVariable_flags(visitor, node, other)) {
|
||||
result = visitor.resultOnInequivalence;
|
||||
}
|
||||
@@ -14120,15 +14120,6 @@ class EquivalenceStrategy {
|
||||
);
|
||||
}
|
||||
|
||||
bool checkTypeVariable_context(
|
||||
EquivalenceVisitor visitor,
|
||||
TypeVariable node,
|
||||
TypeVariable other,
|
||||
) {
|
||||
'context';
|
||||
return checkVariableContext(visitor, node.context, other.context);
|
||||
}
|
||||
|
||||
bool checkTypeVariable_parameter(
|
||||
EquivalenceVisitor visitor,
|
||||
TypeVariable node,
|
||||
@@ -14154,6 +14145,15 @@ class EquivalenceStrategy {
|
||||
);
|
||||
}
|
||||
|
||||
bool checkTypeVariable_context(
|
||||
EquivalenceVisitor visitor,
|
||||
TypeVariable node,
|
||||
TypeVariable other,
|
||||
) {
|
||||
'context';
|
||||
return checkVariableContext(visitor, node.context, other.context);
|
||||
}
|
||||
|
||||
bool checkTypeVariable_flags(
|
||||
EquivalenceVisitor visitor,
|
||||
TypeVariable node,
|
||||
|
||||
@@ -1179,6 +1179,53 @@ class VerifyingVisitor extends RecursiveResultVisitor<void> {
|
||||
exitTreeNode(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitCatchVariable(CatchVariable node) {
|
||||
_verifyVariable(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitLocalVariable(LocalVariable node) {
|
||||
_verifyVariable(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitPositionalParameter(PositionalParameter node) {
|
||||
_verifyVariable(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitNamedParameter(NamedParameter node) {
|
||||
_verifyVariable(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitSyntheticVariable(SyntheticVariable node) {
|
||||
_verifyVariable(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitThisVariable(ThisVariable node) {
|
||||
_verifyVariable(node);
|
||||
}
|
||||
|
||||
void _verifyVariable(VariableDeclaration node) {
|
||||
enterTreeNode(node);
|
||||
TreeNode? oldParent = enterParent(node);
|
||||
_visitAnnotations(node.annotations);
|
||||
exitParent(oldParent);
|
||||
declareVariable(node);
|
||||
exitTreeNode(node);
|
||||
|
||||
if (!isOutline && node.context == null) {
|
||||
problem(
|
||||
node,
|
||||
"A '${node.runtimeType}' variable with cosmetic name "
|
||||
"'${node.cosmeticName}' doesn't have its context set.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void visitVariableGet(VariableGet node) {
|
||||
// TODO(cstefantsova): Support new variable model.
|
||||
|
||||
Reference in New Issue
Block a user