From 10dd51ee4c8fc9116f7fa3b574cddc31f667edad Mon Sep 17 00:00:00 2001 From: Chloe Stefantsova Date: Tue, 19 May 2026 04:29:29 -0700 Subject: [PATCH] [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 Reviewed-by: Johnni Winther Commit-Queue: Chloe Stefantsova --- pkg/cfg/lib/front_end/ast_scopes.dart | 2 +- .../fragment/field/body_builder_context.dart | 1 - .../lib/src/kernel/internal_ast.dart | 2 +- .../lib/src/kernel/resolver_helpers.dart | 6 +- .../context_allocation_strategy.dart | 5 +- .../src/type_inference/inference_visitor.dart | 1 - .../inference_visitor_base.dart | 1 - .../lib/src/type_inference/type_inferrer.dart | 30 +++++ ...onstructor_initializers.dart.strong.expect | 1 + ...or_initializers.dart.strong.modular.expect | 1 + .../redirecting_factories.dart.strong.expect | 2 + ...cting_factories.dart.strong.modular.expect | 2 + ...per_initializing_formal.dart.strong.expect | 2 + ...ializing_formal.dart.strong.modular.expect | 2 + pkg/front_end/tool/ast_model.dart | 15 ++- pkg/kernel/lib/src/ast/statements.dart | 4 +- pkg/kernel/lib/src/ast/types.dart | 20 ++- pkg/kernel/lib/src/ast/variables.dart | 116 +++++++++++++++--- pkg/kernel/lib/src/equivalence.dart | 24 ++-- pkg/kernel/lib/verifier.dart | 47 +++++++ 20 files changed, 242 insertions(+), 42 deletions(-) diff --git a/pkg/cfg/lib/front_end/ast_scopes.dart b/pkg/cfg/lib/front_end/ast_scopes.dart index 7c185d5772a..6294f57eb05 100644 --- a/pkg/cfg/lib/front_end/ast_scopes.dart +++ b/pkg/cfg/lib/front_end/ast_scopes.dart @@ -56,7 +56,7 @@ final class AstScopes implements Scopes { @override Context getVariableContext(Variable variable) => - _mapping.mapContext(variable.context); + _mapping.mapContext(variable.context!); @override List getCapturedContexts( diff --git a/pkg/front_end/lib/src/fragment/field/body_builder_context.dart b/pkg/front_end/lib/src/fragment/field/body_builder_context.dart index dd239492ca6..1f61254047d 100644 --- a/pkg/front_end/lib/src/fragment/field/body_builder_context.dart +++ b/pkg/front_end/lib/src/fragment/field/body_builder_context.dart @@ -65,7 +65,6 @@ class FieldFragmentBodyBuilderContext extends BodyBuilderContext { } @override - // Coverage-ignore(suite): Not run. int get memberNameOffset => _nameOffset; @override diff --git a/pkg/front_end/lib/src/kernel/internal_ast.dart b/pkg/front_end/lib/src/kernel/internal_ast.dart index 451dd36a5eb..da3af2a5340 100644 --- a/pkg/front_end/lib/src/kernel/internal_ast.dart +++ b/pkg/front_end/lib/src/kernel/internal_ast.dart @@ -1750,7 +1750,7 @@ mixin DelegatingVariableMixin on InternalVariableMixin @override // Coverage-ignore(suite): Not run. - VariableContext get context => astVariable.context; + VariableContext? get context => astVariable.context; @override // Coverage-ignore(suite): Not run. diff --git a/pkg/front_end/lib/src/kernel/resolver_helpers.dart b/pkg/front_end/lib/src/kernel/resolver_helpers.dart index 478ab715f22..a8238d28e62 100644 --- a/pkg/front_end/lib/src/kernel/resolver_helpers.dart +++ b/pkg/front_end/lib/src/kernel/resolver_helpers.dart @@ -433,6 +433,7 @@ class _InitializerBuilder { libraryBuilder: libraryBuilder, typeInferrer: _typeInferrer, superParameterArguments: superParameterArguments, + parameters: parameters, internalThisVariable: internalThisVariable, scopeProviderInfo: scopeProviderInfo, contextAllocationStrategy: contextAllocationStrategy, @@ -628,6 +629,7 @@ class _InitializerBuilder { required SourceLibraryBuilder libraryBuilder, required TypeInferrer typeInferrer, required _SuperParameterArguments? superParameterArguments, + required List parameters, required ThisVariable? internalThisVariable, required ScopeProviderInfo? scopeProviderInfo, required ContextAllocationStrategy contextAllocationStrategy, @@ -825,11 +827,9 @@ class _InitializerBuilder { )..fileOffset = _bodyBuilderContext.memberNameOffset; } } - // The [parameters] and [internalThisVariable] won't be used in the implicit - // super initializer. return _inferInitializer( initializer, - parameters: [], + parameters: parameters, internalThisVariable: internalThisVariable, scopeProviderInfo: scopeProviderInfo, contextAllocationStrategy: contextAllocationStrategy, diff --git a/pkg/front_end/lib/src/type_inference/context_allocation_strategy.dart b/pkg/front_end/lib/src/type_inference/context_allocation_strategy.dart index 5e3b5f05b7f..d47851f867c 100644 --- a/pkg/front_end/lib/src/type_inference/context_allocation_strategy.dart +++ b/pkg/front_end/lib/src/type_inference/context_allocation_strategy.dart @@ -7,7 +7,8 @@ import '../util/local_stack.dart'; extension type ScopeProviderInfoStack( List _list -) implements LocalStack { +) + implements LocalStack { ScopeProviderInfo? topmostOfKind( Set scopeProviderInfoKinds, ) { @@ -159,7 +160,7 @@ abstract class ContextAllocationStrategy { List variables, ) { Set contexts = { - for (VariableBase variable in variables) variable.context, + for (VariableBase variable in variables) variable.context!, }; (node.capturedContexts ??= []).addAll(contexts); } diff --git a/pkg/front_end/lib/src/type_inference/inference_visitor.dart b/pkg/front_end/lib/src/type_inference/inference_visitor.dart index 962b50defbc..f0517f1c38d 100644 --- a/pkg/front_end/lib/src/type_inference/inference_visitor.dart +++ b/pkg/front_end/lib/src/type_inference/inference_visitor.dart @@ -667,7 +667,6 @@ class InferenceVisitorImpl extends InferenceVisitorBase } @override - // Coverage-ignore(suite): Not run. ExpressionInferenceResult visitInstanceInvocation( InstanceInvocation node, DartType typeContext, diff --git a/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart b/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart index add668f9f18..b622d8c2b4f 100644 --- a/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart +++ b/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart @@ -202,7 +202,6 @@ abstract class InferenceVisitorBase implements InferenceVisitor { DartType get bottomType => const NeverType.nonNullable(); - // Coverage-ignore(suite): Not run. StaticTypeContext get staticTypeContext => _inferrer.staticTypeContext; DartType computeGreatestClosure(DartType type) { diff --git a/pkg/front_end/lib/src/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/type_inference/type_inferrer.dart index 88a6b583a0a..eb6fbcf600f 100644 --- a/pkg/front_end/lib/src/type_inference/type_inferrer.dart +++ b/pkg/front_end/lib/src/type_inference/type_inferrer.dart @@ -335,6 +335,31 @@ class TypeInferrerImpl implements TypeInferrer { contextAllocationStrategy: InferenceVisitorBase.createContextAllocationStrategy(), ); + + ScopeProviderInfo? scopeProviderInfo; + if (isClosureContextLoweringEnabled) { + scopeProviderInfo = visitor.beginFunctionBodyInference( + [ + for (VariableDeclaration positionalParameter + in redirectingFactoryFunction.positionalParameters) + new InternalPositionalParameter( + astVariable: positionalParameter as PositionalParameter, + isImplicitlyTyped: false, + fileOffset: positionalParameter.fileOffset, + ), + for (VariableDeclaration namedParameter + in redirectingFactoryFunction.namedParameters) + new InternalNamedParameter( + astVariable: namedParameter as NamedParameter, + isImplicitlyTyped: false, + fileOffset: namedParameter.fileOffset, + ), + ], + internalThisVariable: null, + scopeProviderInfo: null, + ); + } + List arguments = []; int positionalCount = 0; for (VariableDeclaration parameter @@ -409,6 +434,11 @@ class TypeInferrerImpl implements TypeInferrer { staticTarget: target, ); visitor.checkCleanState(); + + if (scopeProviderInfo != null) { + visitor.endFunctionBodyInference(scopeProviderInfo); + } + DartType resultType = result.inferredType; if (resultType is TypeDeclarationType) { return resultType.typeArguments; diff --git a/pkg/front_end/testcases/closure_context_lowering/constructor_initializers.dart.strong.expect b/pkg/front_end/testcases/closure_context_lowering/constructor_initializers.dart.strong.expect index 76afdb3e729..e46f4f72aed 100644 --- a/pkg/front_end/testcases/closure_context_lowering/constructor_initializers.dart.strong.expect +++ b/pkg/front_end/testcases/closure_context_lowering/constructor_initializers.dart.strong.expect @@ -12,6 +12,7 @@ class A extends core::Object { ]), #ctx1: direct-captured VariableContext([ positional-parameter y; + positional-parameter y; ]), ] */ ; diff --git a/pkg/front_end/testcases/closure_context_lowering/constructor_initializers.dart.strong.modular.expect b/pkg/front_end/testcases/closure_context_lowering/constructor_initializers.dart.strong.modular.expect index 76afdb3e729..e46f4f72aed 100644 --- a/pkg/front_end/testcases/closure_context_lowering/constructor_initializers.dart.strong.modular.expect +++ b/pkg/front_end/testcases/closure_context_lowering/constructor_initializers.dart.strong.modular.expect @@ -12,6 +12,7 @@ class A extends core::Object { ]), #ctx1: direct-captured VariableContext([ positional-parameter y; + positional-parameter y; ]), ] */ ; diff --git a/pkg/front_end/testcases/closure_context_lowering/redirecting_factories.dart.strong.expect b/pkg/front_end/testcases/closure_context_lowering/redirecting_factories.dart.strong.expect index a907a944664..5e95e335598 100644 --- a/pkg/front_end/testcases/closure_context_lowering/redirecting_factories.dart.strong.expect +++ b/pkg/front_end/testcases/closure_context_lowering/redirecting_factories.dart.strong.expect @@ -18,6 +18,7 @@ class B extends self::A { : super self::A::•()/* scope=[ #ctx2: not-captured VariableContext([ this-variable final this-variable; + positional-parameter x; ]), ] */ ; @@ -38,6 +39,7 @@ class D extends self::C { : super self::C::•()/* scope=[ #ctx4: not-captured VariableContext([ this-variable final this-variable; + named-parameter required y; ]), ] */ ; diff --git a/pkg/front_end/testcases/closure_context_lowering/redirecting_factories.dart.strong.modular.expect b/pkg/front_end/testcases/closure_context_lowering/redirecting_factories.dart.strong.modular.expect index a907a944664..5e95e335598 100644 --- a/pkg/front_end/testcases/closure_context_lowering/redirecting_factories.dart.strong.modular.expect +++ b/pkg/front_end/testcases/closure_context_lowering/redirecting_factories.dart.strong.modular.expect @@ -18,6 +18,7 @@ class B extends self::A { : super self::A::•()/* scope=[ #ctx2: not-captured VariableContext([ this-variable final this-variable; + positional-parameter x; ]), ] */ ; @@ -38,6 +39,7 @@ class D extends self::C { : super self::C::•()/* scope=[ #ctx4: not-captured VariableContext([ this-variable final this-variable; + named-parameter required y; ]), ] */ ; diff --git a/pkg/front_end/testcases/closure_context_lowering/super_initializing_formal.dart.strong.expect b/pkg/front_end/testcases/closure_context_lowering/super_initializing_formal.dart.strong.expect index 0956bc3b764..19cc7aa643e 100644 --- a/pkg/front_end/testcases/closure_context_lowering/super_initializing_formal.dart.strong.expect +++ b/pkg/front_end/testcases/closure_context_lowering/super_initializing_formal.dart.strong.expect @@ -7,6 +7,7 @@ class A extends core::Object { : super core::Object::•()/* scope=[ #ctx1: not-captured VariableContext([ this-variable final this-variable; + positional-parameter x; ]), ] */ ; @@ -16,6 +17,7 @@ class B extends self::A { : super self::A::•(x)/* scope=[ #ctx2: not-captured VariableContext([ this-variable final this-variable; + positional-parameter x; ]), ] */ ; diff --git a/pkg/front_end/testcases/closure_context_lowering/super_initializing_formal.dart.strong.modular.expect b/pkg/front_end/testcases/closure_context_lowering/super_initializing_formal.dart.strong.modular.expect index 0956bc3b764..19cc7aa643e 100644 --- a/pkg/front_end/testcases/closure_context_lowering/super_initializing_formal.dart.strong.modular.expect +++ b/pkg/front_end/testcases/closure_context_lowering/super_initializing_formal.dart.strong.modular.expect @@ -7,6 +7,7 @@ class A extends core::Object { : super core::Object::•()/* scope=[ #ctx1: not-captured VariableContext([ this-variable final this-variable; + positional-parameter x; ]), ] */ ; @@ -16,6 +17,7 @@ class B extends self::A { : super self::A::•(x)/* scope=[ #ctx2: not-captured VariableContext([ this-variable final this-variable; + positional-parameter x; ]), ] */ ; diff --git a/pkg/front_end/tool/ast_model.dart b/pkg/front_end/tool/ast_model.dart index 664f7598893..22137998ec4 100644 --- a/pkg/front_end/tool/ast_model.dart +++ b/pkg/front_end/tool/ast_model.dart @@ -129,7 +129,14 @@ const Map> _fieldRuleMap = { 'VariableGet': {'variable': FieldRule(isDeclaration: false)}, 'VariableSet': {'variable': FieldRule(isDeclaration: false)}, 'LocalFunctionInvocation': {'variable': FieldRule(isDeclaration: false)}, - 'LocalVariable': {'variableInitialization': FieldRule(isDeclaration: false)}, + 'LocalVariable': { + 'variableInitialization': FieldRule(isDeclaration: false), + '_context': FieldRule(name: 'context'), + }, + 'CatchVariable': {'_context': FieldRule(name: 'context')}, + 'PositionalParameter': {'_context': FieldRule(name: 'context')}, + 'NamedParameter': {'_context': FieldRule(name: 'context')}, + 'ThisVariable': {'_context': FieldRule(name: 'context')}, 'BreakStatement': {'target': FieldRule(isDeclaration: false)}, 'ForStatement': {'variables': FieldRule(isDeclaration: true)}, 'ForInStatement': {'variable': FieldRule(isDeclaration: true)}, @@ -150,6 +157,7 @@ const Map> _fieldRuleMap = { 'StructuralParameterType': {'parameter': FieldRule(isDeclaration: false)}, 'SyntheticVariable': { 'variableInitialization': FieldRule(isDeclaration: false), + '_context': FieldRule(name: 'context'), }, 'LegacyVariable': {'_name': FieldRule(name: 'name')}, 'AssignedVariablePattern': {'variable': FieldRule(isDeclaration: false)}, @@ -158,7 +166,10 @@ const Map> _fieldRuleMap = { 'VariablePattern': {'variable': FieldRule(isDeclaration: true)}, 'PatternSwitchCase': {'jointVariables': FieldRule(isDeclaration: true)}, 'PatternSwitchStatement': {'cases': FieldRule(isDeclaration: true)}, - 'TypeVariable': {'parameter': FieldRule(isDeclaration: false)}, + 'TypeVariable': { + 'parameter': FieldRule(isDeclaration: false), + '_context': FieldRule(name: 'context'), + }, 'ClassTypeParameterType': { 'parameter': FieldRule(isDeclaration: false), 'thisVariable': FieldRule(isDeclaration: false), diff --git a/pkg/kernel/lib/src/ast/statements.dart b/pkg/kernel/lib/src/ast/statements.dart index e12626cc220..dbb1edbe0f3 100644 --- a/pkg/kernel/lib/src/ast/statements.dart +++ b/pkg/kernel/lib/src/ast/statements.dart @@ -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="); } diff --git a/pkg/kernel/lib/src/ast/types.dart b/pkg/kernel/lib/src/ast/types.dart index d956e201cfd..c7fd2f4de7f 100644 --- a/pkg/kernel/lib/src/ast/types.dart +++ b/pkg/kernel/lib/src/ast/types.dart @@ -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 annotations = const []; + 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) { diff --git a/pkg/kernel/lib/src/ast/variables.dart b/pkg/kernel/lib/src/ast/variables.dart index 382e3de9586..87e173ec9de 100644 --- a/pkg/kernel/lib/src/ast/variables.dart +++ b/pkg/kernel/lib/src/ast/variables.dart @@ -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 annotations = const []; - @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 annotations = const []; - @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 annotations = const []; - @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? get capturedContexts { @@ -1169,8 +1215,7 @@ class NamedParameter extends FunctionParameter { @override List annotations = const []; - @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? get capturedContexts { @@ -1319,11 +1379,25 @@ class ThisVariable extends VariableDeclaration { @override List annotations = const []; - @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 annotations = const []; - @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) { diff --git a/pkg/kernel/lib/src/equivalence.dart b/pkg/kernel/lib/src/equivalence.dart index 6ecaafd410e..d4882d5d660 100644 --- a/pkg/kernel/lib/src/equivalence.dart +++ b/pkg/kernel/lib/src/equivalence.dart @@ -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, diff --git a/pkg/kernel/lib/verifier.dart b/pkg/kernel/lib/verifier.dart index 8572cb936b4..137fb7e03a9 100644 --- a/pkg/kernel/lib/verifier.dart +++ b/pkg/kernel/lib/verifier.dart @@ -1179,6 +1179,53 @@ class VerifyingVisitor extends RecursiveResultVisitor { 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.