Version 2.15.0-1.0.dev
Merge commit 'b266aeebc3ffa25d9a7774513cb99eb206e39766' into 'dev'
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index c8caff3..a568624 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -682,7 +682,7 @@
),
);
- unit.accept(VariableResolverVisitor(
+ unit.accept(ScopeResolverVisitor(
_libraryElement, source, _typeProvider, errorListener,
nameScope: _libraryElement.scope));
diff --git a/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart b/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
index 930340a..a723a79 100644
--- a/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
@@ -693,7 +693,7 @@
),
);
- unit.accept(VariableResolverVisitor(
+ unit.accept(ScopeResolverVisitor(
_libraryElement, source, _typeProvider, errorListener,
nameScope: _libraryElement.scope));
diff --git a/pkg/analyzer/lib/src/dart/resolver/lexical_lookup.dart b/pkg/analyzer/lib/src/dart/resolver/lexical_lookup.dart
index 542fd5e..f0735d6 100644
--- a/pkg/analyzer/lib/src/dart/resolver/lexical_lookup.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/lexical_lookup.dart
@@ -2,94 +2,55 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/scope.dart';
import 'package:analyzer/src/dart/element/extensions.dart';
-import 'package:analyzer/src/generated/resolver.dart';
+/// Class containing static methods for performing lexical resolution of
+/// identifiers.
class LexicalLookup {
- final ResolverVisitor _resolver;
+ /// Do not construct
+ LexicalLookup._() {
+ assert(false, 'Do not construct instances of LexicalLookup');
+ }
- LexicalLookup(this._resolver);
+ /// Interprets the result of a scope lookup, assuming we are trying to look up
+ /// a getter. If a matching element is found, a [LexicalLookupResult] is
+ /// returned. Otherwise `null` is returned.
+ static LexicalLookupResult? resolveGetter(ScopeLookupResult scopeResult) {
+ var scopeGetter = scopeResult.getter;
+ var scopeSetter = scopeResult.setter;
+ if (scopeGetter != null || scopeSetter != null) {
+ if (scopeGetter != null) {
+ return LexicalLookupResult(requested: scopeGetter);
+ }
+ if (scopeSetter != null && !scopeSetter.isInstanceMember) {
+ return LexicalLookupResult(recovery: scopeSetter);
+ }
+ }
- LexicalLookupResult perform({
- required SimpleIdentifier node,
- required bool setter,
- }) {
- var id = node.name;
- var scopeResult = _resolver.nameScope.lookup(id);
+ return null;
+ }
+
+ /// Interprets the result of a scope lookup, assuming we are trying to look up
+ /// a setter. If a matching element is found, a [LexicalLookupResult] is
+ /// returned. Otherwise `null` is returned.
+ static LexicalLookupResult? resolveSetter(ScopeLookupResult scopeResult) {
var scopeGetter = scopeResult.getter;
var scopeSetter = scopeResult.setter;
if (scopeGetter != null || scopeSetter != null) {
if (scopeGetter is VariableElement) {
return LexicalLookupResult(requested: scopeGetter);
}
- if (setter) {
- if (scopeSetter != null) {
- return LexicalLookupResult(
- requested: _resolver.toLegacyElement(scopeSetter),
- );
- }
- if (scopeGetter != null && !scopeGetter.isInstanceMember) {
- return LexicalLookupResult(
- recovery: _resolver.toLegacyElement(scopeGetter),
- );
- }
- } else {
- if (scopeGetter != null) {
- return LexicalLookupResult(
- requested: _resolver.toLegacyElement(scopeGetter),
- );
- }
- if (scopeSetter != null && !scopeSetter.isInstanceMember) {
- return LexicalLookupResult(
- recovery: _resolver.toLegacyElement(scopeSetter),
- );
- }
+ if (scopeSetter != null) {
+ return LexicalLookupResult(requested: scopeSetter);
+ }
+ if (scopeGetter != null && !scopeGetter.isInstanceMember) {
+ return LexicalLookupResult(recovery: scopeGetter);
}
}
- var thisType = _resolver.thisType;
- if (thisType == null) {
- var recoveryElement = setter ? scopeGetter : scopeGetter;
- return LexicalLookupResult(
- recovery: _resolver.toLegacyElement(recoveryElement),
- );
- }
-
- var propertyResult = _resolver.typePropertyResolver.resolve(
- receiver: null,
- receiverType: thisType,
- name: id,
- propertyErrorEntity: node,
- nameErrorEntity: node,
- );
-
- if (setter) {
- var setterElement = propertyResult.setter;
- if (setterElement != null) {
- return LexicalLookupResult(
- requested: _resolver.toLegacyElement(setterElement),
- );
- } else {
- var recoveryElement = scopeGetter ?? propertyResult.getter;
- return LexicalLookupResult(
- recovery: _resolver.toLegacyElement(recoveryElement),
- );
- }
- } else {
- var getterElement = propertyResult.getter;
- if (getterElement != null) {
- return LexicalLookupResult(
- requested: _resolver.toLegacyElement(getterElement),
- );
- } else {
- var recoveryElement = scopeSetter ?? propertyResult.setter;
- return LexicalLookupResult(
- recovery: _resolver.toLegacyElement(recoveryElement),
- );
- }
- }
+ return null;
}
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
index 10c9f96..31a3d2c 100644
--- a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
@@ -12,6 +12,7 @@
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/dart/resolver/extension_member_resolver.dart';
+import 'package:analyzer/src/dart/resolver/lexical_lookup.dart';
import 'package:analyzer/src/dart/resolver/resolution_result.dart';
import 'package:analyzer/src/error/assignment_verifier.dart';
import 'package:analyzer/src/error/codes.dart';
@@ -198,8 +199,10 @@
Element? readElementRequested;
Element? readElementRecovery;
if (hasRead) {
- var readLookup = _resolver.lexicalLookup(node: node, setter: false);
- readElementRequested = readLookup.requested;
+ var readLookup =
+ LexicalLookup.resolveGetter(_resolver.nameScope.lookup(node.name)) ??
+ _resolver.thisLookupGetter(node);
+ readElementRequested = _resolver.toLegacyElement(readLookup?.requested);
if (readElementRequested is PropertyAccessorElement &&
!readElementRequested.isStatic) {
_resolver.flowAnalysis?.flow?.thisOrSuperPropertyGet(node, node.name,
@@ -211,9 +214,11 @@
Element? writeElementRequested;
Element? writeElementRecovery;
if (hasWrite) {
- var writeLookup = _resolver.lexicalLookup(node: node, setter: true);
- writeElementRequested = writeLookup.requested;
- writeElementRecovery = writeLookup.recovery;
+ var writeLookup =
+ LexicalLookup.resolveSetter(_resolver.nameScope.lookup(node.name)) ??
+ _resolver.thisLookupSetter(node);
+ writeElementRequested = _resolver.toLegacyElement(writeLookup?.requested);
+ writeElementRecovery = _resolver.toLegacyElement(writeLookup?.recovery);
AssignmentVerifier(_resolver.definingLibrary, _errorReporter).verify(
node: node,
diff --git a/pkg/analyzer/lib/src/dart/resolver/this_lookup.dart b/pkg/analyzer/lib/src/dart/resolver/this_lookup.dart
new file mode 100644
index 0000000..d274eb8
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/resolver/this_lookup.dart
@@ -0,0 +1,70 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/resolver/lexical_lookup.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+
+/// Class containing static methods for resolving identifiers as implicit
+/// property gets/sets on the type of `this`.
+class ThisLookup {
+ /// Do not construct
+ ThisLookup._() {
+ assert(false, 'Do not construct instances of LexicalLookup');
+ }
+
+ /// Attempts to resolve an identifier with name [id] via implicit `this.`,
+ /// assuming we are trying to look up a getter. If a matching element is
+ /// found, a [LexicalLookupResult] is returned. Otherwise `null` is returned.
+ static LexicalLookupResult? lookupGetter(
+ ResolverVisitor resolver, SimpleIdentifier node) {
+ var id = node.name;
+ var thisType = resolver.thisType;
+ if (thisType == null) {
+ return null;
+ }
+
+ var propertyResult = resolver.typePropertyResolver.resolve(
+ receiver: null,
+ receiverType: thisType,
+ name: id,
+ propertyErrorEntity: node,
+ nameErrorEntity: node,
+ );
+
+ var getterElement = propertyResult.getter;
+ if (getterElement != null) {
+ return LexicalLookupResult(requested: getterElement);
+ } else {
+ return LexicalLookupResult(recovery: propertyResult.setter);
+ }
+ }
+
+ /// Attempts to resolve an identifier with name [id] via implicit `this.`,
+ /// assuming we are trying to look up a setter. If a matching element is
+ /// found, a [LexicalLookupResult] is returned. Otherwise `null` is returned.
+ static LexicalLookupResult? lookupSetter(
+ ResolverVisitor resolver, SimpleIdentifier node) {
+ var id = node.name;
+ var thisType = resolver.thisType;
+ if (thisType == null) {
+ return null;
+ }
+
+ var propertyResult = resolver.typePropertyResolver.resolve(
+ receiver: null,
+ receiverType: thisType,
+ name: id,
+ propertyErrorEntity: node,
+ nameErrorEntity: node,
+ );
+
+ var setterElement = propertyResult.setter;
+ if (setterElement != null) {
+ return LexicalLookupResult(requested: setterElement);
+ } else {
+ return LexicalLookupResult(recovery: propertyResult.getter);
+ }
+ }
+}
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 2a378e11..e19c9e5 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -115,11 +115,6 @@
TypeProviderImpl get _typeProvider => _resolver.typeProvider;
@override
- void visitBreakStatement(covariant BreakStatementImpl node) {
- node.target = _lookupBreakOrContinueTarget(node, node.label, false);
- }
-
- @override
void visitClassDeclaration(ClassDeclaration node) {
_resolveAnnotations(node.metadata);
}
@@ -276,11 +271,6 @@
}
@override
- void visitContinueStatement(covariant ContinueStatementImpl node) {
- node.target = _lookupBreakOrContinueTarget(node, node.label, true);
- }
-
- @override
void visitDeclaredIdentifier(DeclaredIdentifier node) {
_resolveAnnotations(node.metadata);
}
@@ -537,46 +527,6 @@
_resolveAnnotations(node.metadata);
}
- /// Return the target of a break or continue statement, and update the static
- /// element of its label (if any). The [parentNode] is the AST node of the
- /// break or continue statement. The [labelNode] is the label contained in
- /// that statement (if any). The flag [isContinue] is `true` if the node being
- /// visited is a continue statement.
- AstNode? _lookupBreakOrContinueTarget(
- AstNode parentNode, SimpleIdentifierImpl? labelNode, bool isContinue) {
- if (labelNode == null) {
- return _resolver.implicitLabelScope.getTarget(isContinue);
- } else {
- var labelScope = _resolver.labelScope;
- if (labelScope == null) {
- // There are no labels in scope, so by definition the label is
- // undefined.
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.LABEL_UNDEFINED, labelNode, [labelNode.name]);
- return null;
- }
- var definingScope = labelScope.lookup(labelNode.name);
- if (definingScope == null) {
- // No definition of the given label name could be found in any
- // enclosing scope.
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.LABEL_UNDEFINED, labelNode, [labelNode.name]);
- return null;
- }
- // The target has been found.
- labelNode.staticElement = definingScope.element;
- ExecutableElement? labelContainer =
- definingScope.element.thisOrAncestorOfType();
- if (!identical(labelContainer, _resolver.enclosingFunction)) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.LABEL_IN_OUTER_SCOPE,
- labelNode,
- [labelNode.name]);
- }
- return definingScope.node;
- }
- }
-
/// Given an [argumentList] and the [executableElement] that will be invoked
/// using those argument, compute the list of parameters that correspond to
/// the list of arguments. An error will be reported if any of the arguments
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 158edb0..bd08b70 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -48,6 +48,7 @@
import 'package:analyzer/src/dart/resolver/property_element_resolver.dart';
import 'package:analyzer/src/dart/resolver/scope.dart';
import 'package:analyzer/src/dart/resolver/simple_identifier_resolver.dart';
+import 'package:analyzer/src/dart/resolver/this_lookup.dart';
import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
import 'package:analyzer/src/dart/resolver/typed_literal_resolver.dart';
import 'package:analyzer/src/dart/resolver/variable_declaration_resolver.dart';
@@ -160,6 +161,18 @@
/// Instances of the class `ResolverVisitor` are used to resolve the nodes
/// within a single compilation unit.
class ResolverVisitor extends ScopedVisitor with ErrorDetectionHelpers {
+ /// The class containing the AST nodes being visited,
+ /// or `null` if we are not in the scope of a class.
+ ClassElement? enclosingClass;
+
+ /// The element representing the extension containing the AST nodes being
+ /// visited, or `null` if we are not in the scope of an extension.
+ ExtensionElement? enclosingExtension;
+
+ /// The element representing the function containing the current node, or
+ /// `null` if the current node is not contained in a function.
+ ExecutableElement? _enclosingFunction;
+
/// The manager for the inheritance mappings.
final InheritanceManager3 inheritance;
@@ -378,6 +391,12 @@
FunctionReferenceResolver(this, _isNonNullableByDefault);
}
+ /// Return the element representing the function containing the current node,
+ /// or `null` if the current node is not contained in a function.
+ ///
+ /// @return the element representing the function containing the current node
+ ExecutableElement? get enclosingFunction => _enclosingFunction;
+
bool get isConstructorTearoffsEnabled =>
_featureSet.isEnabled(Feature.constructor_tearoffs);
@@ -580,16 +599,6 @@
return null;
}
- /// Return the result of lexical lookup for the [node], not `null`.
- ///
- /// Implements `16.35 Lexical Lookup` from the language specification.
- LexicalLookupResult lexicalLookup({
- required SimpleIdentifier node,
- required bool setter,
- }) {
- return LexicalLookup(this).perform(node: node, setter: setter);
- }
-
/// If we reached a null-shorting termination, and the [node] has null
/// shorting, make the type of the [node] nullable.
void nullShortingTermination(ExpressionImpl node,
@@ -847,6 +856,18 @@
}
}
+ /// Returns the result of an implicit `this.` lookup for the identifier string
+ /// [id] in a getter context, or `null` if no match was found.
+ LexicalLookupResult? thisLookupGetter(SimpleIdentifier node) {
+ return ThisLookup.lookupGetter(this, node);
+ }
+
+ /// Returns the result of an implicit `this.` lookup for the identifier string
+ /// [id] in a setter context, or `null` if no match was found.
+ LexicalLookupResult? thisLookupSetter(SimpleIdentifier node) {
+ return ThisLookup.lookupSetter(this, node);
+ }
+
/// If in a legacy library, return the legacy view on the [element].
/// Otherwise, return the original element.
T toLegacyElement<T extends Element?>(T element) {
@@ -1066,6 +1087,7 @@
// Continue the class resolution.
//
var outerType = enclosingClass;
+ enclosingClass = node.declaredElement;
try {
super.visitClassDeclaration(node);
node.accept(elementResolver);
@@ -1171,7 +1193,13 @@
var returnType = node.declaredElement!.type.returnType;
InferenceContext.setType(node.body, returnType);
- super.visitConstructorDeclaration(node);
+ var outerFunction = _enclosingFunction;
+ try {
+ _enclosingFunction = node.declaredElement;
+ super.visitConstructorDeclaration(node);
+ } finally {
+ _enclosingFunction = outerFunction;
+ }
if (node.factoryKeyword != null) {
var bodyContext = BodyInferenceContext.of(node.body);
@@ -1336,11 +1364,14 @@
@override
void visitExtensionDeclaration(ExtensionDeclaration node) {
+ var outerExtension = enclosingExtension;
try {
+ enclosingExtension = node.declaredElement!;
super.visitExtensionDeclaration(node);
node.accept(elementResolver);
node.accept(typeAnalyzer);
} finally {
+ enclosingExtension = outerExtension;
_thisType = null;
}
}
@@ -1405,7 +1436,13 @@
var functionType = node.declaredElement!.type;
InferenceContext.setType(node.functionExpression, functionType);
- super.visitFunctionDeclaration(node);
+ var outerFunction = _enclosingFunction;
+ try {
+ _enclosingFunction = node.declaredElement;
+ super.visitFunctionDeclaration(node);
+ } finally {
+ _enclosingFunction = outerFunction;
+ }
// TODO(scheglov) encapsulate
var bodyContext = BodyInferenceContext.of(
@@ -1434,8 +1471,6 @@
@override
void visitFunctionExpression(covariant FunctionExpressionImpl node) {
- // Note: we have to update _enclosingFunction because we don't make use of
- // super.visitFunctionExpression.
var outerFunction = _enclosingFunction;
_enclosingFunction = node.declaredElement;
@@ -1639,7 +1674,13 @@
DartType returnType = node.declaredElement!.returnType;
InferenceContext.setType(node.body, returnType);
- super.visitMethodDeclaration(node);
+ var outerFunction = _enclosingFunction;
+ try {
+ _enclosingFunction = node.declaredElement;
+ super.visitMethodDeclaration(node);
+ } finally {
+ _enclosingFunction = outerFunction;
+ }
// TODO(scheglov) encapsulate
var bodyContext = BodyInferenceContext.of(node.body);
@@ -1700,6 +1741,7 @@
//
var outerType = enclosingClass;
try {
+ enclosingClass = node.declaredElement!;
super.visitMixinDeclaration(node);
node.accept(elementResolver);
node.accept(typeAnalyzer);
@@ -2327,18 +2369,6 @@
/// `null` if no labels have been defined in the current context.
LabelScope? labelScope;
- /// The class containing the AST nodes being visited,
- /// or `null` if we are not in the scope of a class.
- ClassElement? enclosingClass;
-
- /// The element representing the extension containing the AST nodes being
- /// visited, or `null` if we are not in the scope of an extension.
- ExtensionElement? enclosingExtension;
-
- /// The element representing the function containing the current node, or
- /// `null` if the current node is not contained in a function.
- ExecutableElement? _enclosingFunction;
-
/// Initialize a newly created visitor to resolve the nodes in a compilation
/// unit.
///
@@ -2363,12 +2393,6 @@
),
nameScope = nameScope ?? LibraryScope(definingLibrary);
- /// Return the element representing the function containing the current node,
- /// or `null` if the current node is not contained in a function.
- ///
- /// @return the element representing the function containing the current node
- ExecutableElement? get enclosingFunction => _enclosingFunction;
-
/// Return the implicit label scope in which the current node is being
/// resolved.
ImplicitLabelScope get implicitLabelScope => _implicitLabelScope;
@@ -2432,10 +2456,8 @@
@override
void visitClassDeclaration(ClassDeclaration node) {
Scope outerScope = nameScope;
- var outerClass = enclosingClass;
try {
ClassElement element = node.declaredElement!;
- enclosingClass = node.declaredElement;
node.metadata.accept(this);
nameScope = TypeParameterScope(
@@ -2448,7 +2470,6 @@
nameScope = ClassScope(nameScope, element);
visitClassMembersInScope(node);
} finally {
- enclosingClass = outerClass;
nameScope = outerScope;
}
}
@@ -2503,8 +2524,6 @@
@override
void visitConstructorDeclaration(ConstructorDeclaration node) {
- var outerFunction = _enclosingFunction;
- _enclosingFunction = node.declaredElement;
Scope outerScope = nameScope;
try {
ConstructorElement element = node.declaredElement!;
@@ -2533,7 +2552,6 @@
visitConstructorDeclarationInScope(node);
} finally {
nameScope = outerScope;
- _enclosingFunction = outerFunction;
}
}
@@ -2567,16 +2585,13 @@
@override
void visitEnumDeclaration(EnumDeclaration node) {
Scope outerScope = nameScope;
- var outerClass = enclosingClass;
try {
ClassElement element = node.declaredElement!;
- enclosingClass = node.declaredElement;
node.metadata.accept(this);
nameScope = ClassScope(nameScope, element);
visitEnumMembersInScope(node);
} finally {
- enclosingClass = outerClass;
nameScope = outerScope;
}
}
@@ -2595,10 +2610,8 @@
@override
void visitExtensionDeclaration(ExtensionDeclaration node) {
Scope outerScope = nameScope;
- var outerExtension = enclosingExtension;
try {
ExtensionElement element = node.declaredElement!;
- enclosingExtension = element;
node.metadata.accept(this);
nameScope = TypeParameterScope(
@@ -2611,7 +2624,6 @@
nameScope = ExtensionScope(nameScope, element);
visitExtensionMembersInScope(node);
} finally {
- enclosingExtension = outerExtension;
nameScope = outerScope;
}
}
@@ -2714,9 +2726,6 @@
@override
void visitFunctionDeclaration(FunctionDeclaration node) {
- var outerFunction = _enclosingFunction;
- _enclosingFunction = node.declaredElement;
-
node.metadata.accept(this);
Scope outerScope = nameScope;
try {
@@ -2729,7 +2738,6 @@
visitFunctionDeclarationInScope(node);
} finally {
nameScope = outerScope;
- _enclosingFunction = outerFunction;
}
}
@@ -2751,8 +2759,6 @@
return;
}
- var outerFunction = _enclosingFunction;
- _enclosingFunction = node.declaredElement;
Scope outerScope = nameScope;
try {
ExecutableElement element = node.declaredElement!;
@@ -2763,7 +2769,6 @@
super.visitFunctionExpression(node);
} finally {
nameScope = outerScope;
- _enclosingFunction = outerFunction;
}
}
@@ -2893,9 +2898,6 @@
@override
void visitMethodDeclaration(MethodDeclaration node) {
- var outerFunction = _enclosingFunction;
- _enclosingFunction = node.declaredElement;
-
node.metadata.accept(this);
Scope outerScope = nameScope;
try {
@@ -2908,7 +2910,6 @@
visitMethodDeclarationInScope(node);
} finally {
nameScope = outerScope;
- _enclosingFunction = outerFunction;
}
}
@@ -2928,10 +2929,8 @@
@override
void visitMixinDeclaration(MixinDeclaration node) {
Scope outerScope = nameScope;
- var outerClass = enclosingClass;
try {
ClassElement element = node.declaredElement!;
- enclosingClass = element;
node.metadata.accept(this);
nameScope = TypeParameterScope(nameScope, element.typeParameters);
@@ -2942,7 +2941,6 @@
visitMixinMembersInScope(node);
} finally {
nameScope = outerScope;
- enclosingClass = outerClass;
}
}
@@ -3094,12 +3092,20 @@
}
}
-/// Instances of the class `VariableResolverVisitor` are used to resolve
-/// [SimpleIdentifier]s to local variables and formal parameters.
-class VariableResolverVisitor extends ScopedVisitor {
+/// Instances of the class `ScopeResolverVisitor` are used to resolve
+/// [SimpleIdentifier]s to declarations using scoping rules.
+///
+/// TODO(paulberry): migrate the responsibility for all scope resolution into
+/// this visitor.
+class ScopeResolverVisitor extends ScopedVisitor {
/// The container with information about local variables.
final LocalVariableInfo _localVariableInfo = LocalVariableInfo();
+ /// If the current function is contained within a closure (a local function or
+ /// function expression inside another executable declaration), the element
+ /// representing the closure; otherwise `null`.
+ ExecutableElement? _enclosingClosure;
+
/// Initialize a newly created visitor to resolve the nodes in an AST node.
///
/// [definingLibrary] is the element for the library containing the node being
@@ -3113,7 +3119,7 @@
/// [nameScope] is the scope used to resolve identifiers in the node that will
/// first be visited. If `null` or unspecified, a new [LibraryScope] will be
/// created based on [definingLibrary] and [typeProvider].
- VariableResolverVisitor(LibraryElementImpl definingLibrary, Source source,
+ ScopeResolverVisitor(LibraryElementImpl definingLibrary, Source source,
TypeProvider typeProvider, AnalysisErrorListener errorListener,
{Scope? nameScope})
: super(definingLibrary, source, typeProvider as TypeProviderImpl,
@@ -3121,26 +3127,50 @@
nameScope: nameScope);
@override
+ void visitBreakStatement(covariant BreakStatementImpl node) {
+ node.target = _lookupBreakOrContinueTarget(node, node.label, false);
+ }
+
+ @override
void visitConstructorDeclaration(ConstructorDeclaration node) {
(node.body as FunctionBodyImpl).localVariableInfo = _localVariableInfo;
super.visitConstructorDeclaration(node);
}
@override
+ void visitContinueStatement(covariant ContinueStatementImpl node) {
+ node.target = _lookupBreakOrContinueTarget(node, node.label, true);
+ }
+
+ @override
void visitExportDirective(ExportDirective node) {}
@override
void visitFunctionDeclaration(FunctionDeclaration node) {
(node.functionExpression.body as FunctionBodyImpl).localVariableInfo =
_localVariableInfo;
- super.visitFunctionDeclaration(node);
+ var outerClosure = _enclosingClosure;
+ try {
+ _enclosingClosure = node.parent is FunctionDeclarationStatement
+ ? node.declaredElement
+ : null;
+ super.visitFunctionDeclaration(node);
+ } finally {
+ _enclosingClosure = outerClosure;
+ }
}
@override
void visitFunctionExpression(FunctionExpression node) {
if (node.parent is! FunctionDeclaration) {
(node.body as FunctionBodyImpl).localVariableInfo = _localVariableInfo;
- super.visitFunctionExpression(node);
+ var outerClosure = _enclosingClosure;
+ try {
+ _enclosingClosure = node.declaredElement;
+ super.visitFunctionExpression(node);
+ } finally {
+ _enclosingClosure = outerClosure;
+ }
} else {
super.visitFunctionExpression(node);
}
@@ -3200,7 +3230,8 @@
node.staticElement = element;
if (node.inSetterContext()) {
_localVariableInfo.potentiallyMutatedInScope.add(element);
- if (element.enclosingElement != _enclosingFunction) {
+ if (_enclosingClosure != null &&
+ element.enclosingElement != _enclosingClosure) {
_localVariableInfo.potentiallyMutatedInClosure.add(element);
}
}
@@ -3209,6 +3240,47 @@
@override
void visitTypeName(TypeName node) {}
+
+ /// Return the target of a break or continue statement, and update the static
+ /// element of its label (if any). The [parentNode] is the AST node of the
+ /// break or continue statement. The [labelNode] is the label contained in
+ /// that statement (if any). The flag [isContinue] is `true` if the node being
+ /// visited is a continue statement.
+ AstNode? _lookupBreakOrContinueTarget(
+ AstNode parentNode, SimpleIdentifierImpl? labelNode, bool isContinue) {
+ if (labelNode == null) {
+ return implicitLabelScope.getTarget(isContinue);
+ } else {
+ var labelScope = this.labelScope;
+ if (labelScope == null) {
+ // There are no labels in scope, so by definition the label is
+ // undefined.
+ errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.LABEL_UNDEFINED, labelNode, [labelNode.name]);
+ return null;
+ }
+ var definingScope = labelScope.lookup(labelNode.name);
+ if (definingScope == null) {
+ // No definition of the given label name could be found in any
+ // enclosing scope.
+ errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.LABEL_UNDEFINED, labelNode, [labelNode.name]);
+ return null;
+ }
+ // The target has been found.
+ labelNode.staticElement = definingScope.element;
+ ExecutableElement? labelContainer =
+ definingScope.element.thisOrAncestorOfType();
+ if (_enclosingClosure != null &&
+ !identical(labelContainer, _enclosingClosure)) {
+ errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.LABEL_IN_OUTER_SCOPE,
+ labelNode,
+ [labelNode.name]);
+ }
+ return definingScope.node;
+ }
+ }
}
/// Tracker for whether a `switch` statement has `default` or is on an
diff --git a/pkg/analyzer/lib/src/summary2/ast_resolver.dart b/pkg/analyzer/lib/src/summary2/ast_resolver.dart
index 0c63950..df4c79f 100644
--- a/pkg/analyzer/lib/src/summary2/ast_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_resolver.dart
@@ -31,7 +31,7 @@
nameScope: _nameScope,
errorListener: _errorListener,
);
- late final _variableResolverVisitor = VariableResolverVisitor(
+ late final _scopeResolverVisitor = ScopeResolverVisitor(
_unitElement.library,
_unitElement.source,
_unitElement.library.typeProvider,
@@ -58,7 +58,7 @@
void resolveAnnotation(AnnotationImpl node) {
_resolverVisitor.shouldCloneAnnotations = false;
node.accept(_resolutionVisitor);
- node.accept(_variableResolverVisitor);
+ node.accept(_scopeResolverVisitor);
_prepareEnclosingDeclarations();
_flowAnalysis.topLevelDeclaration_enter(node, null);
node.accept(_resolverVisitor);
@@ -75,7 +75,7 @@
}
visit(_resolutionVisitor);
- visit(_variableResolverVisitor);
+ visit(_scopeResolverVisitor);
_prepareEnclosingDeclarations();
_flowAnalysis.topLevelDeclaration_enter(node, node.parameters,
@@ -94,7 +94,7 @@
if (contextType != null) {
InferenceContext.setType(node, contextType);
}
- node.accept(_variableResolverVisitor);
+ node.accept(_scopeResolverVisitor);
}
_prepareEnclosingDeclarations();
_flowAnalysis.topLevelDeclaration_enter(node.parent!, null);
diff --git a/sdk/lib/core/bool.dart b/sdk/lib/core/bool.dart
index 5f4d6d1..491ce16 100644
--- a/sdk/lib/core/bool.dart
+++ b/sdk/lib/core/bool.dart
@@ -41,6 +41,11 @@
/// must be consistent across all calls to [String.fromEnvironment],
/// [int.fromEnvironment], `bool.fromEnvironment` and [bool.hasEnvironment]
/// in a single program.
+ ///
+ /// This constructor is only guaranteed to work when invoked as `const`.
+ /// It may work as a non-constant invocation on some platforms which
+ /// have access to compiler options at run-time, but most ahead-of-time
+ /// compiled platforms will not have this information.
// The .fromEnvironment() constructors are special in that we do not want
// users to call them using "new". We prohibit that by giving them bodies
// that throw, even though const constructors are not allowed to have bodies.
@@ -76,6 +81,11 @@
/// must be consistent across all calls to [String.fromEnvironment],
/// [int.fromEnvironment], [bool.fromEnvironment] and `bool.hasEnvironment`
/// in a single program.
+ ///
+ /// This constructor is only guaranteed to work when invoked as `const`.
+ /// It may work as a non-constant invocation on some platforms which
+ /// have access to compiler options at run-time, but most ahead-of-time
+ /// compiled platforms will not have this information.
// The .hasEnvironment() constructor is special in that we do not want
// users to call them using "new". We prohibit that by giving them bodies
// that throw, even though const constructors are not allowed to have bodies.
diff --git a/sdk/lib/core/int.dart b/sdk/lib/core/int.dart
index 3e5bb4b..9bf2671 100644
--- a/sdk/lib/core/int.dart
+++ b/sdk/lib/core/int.dart
@@ -37,6 +37,11 @@
/// must be consistent across all calls to [String.fromEnvironment],
/// `int.fromEnvironment`, [bool.fromEnvironment] and [bool.hasEnvironment]
/// in a single program.
+ ///
+ /// This constructor is only guaranteed to work when invoked as `const`.
+ /// It may work as a non-constant invocation on some platforms which
+ /// have access to compiler options at run-time, but most ahead-of-time
+ /// compiled platforms will not have this information.
// The .fromEnvironment() constructors are special in that we do not want
// users to call them using "new". We prohibit that by giving them bodies
// that throw, even though const constructors are not allowed to have bodies.
diff --git a/sdk/lib/core/string.dart b/sdk/lib/core/string.dart
index fbe6a4b..d856ac2 100644
--- a/sdk/lib/core/string.dart
+++ b/sdk/lib/core/string.dart
@@ -151,6 +151,11 @@
/// must be consistent across all calls to `String.fromEnvironment`,
/// [int.fromEnvironment], [bool.fromEnvironment] and [bool.hasEnvironment]
/// in a single program.
+ ///
+ /// This constructor is only guaranteed to work when invoked as `const`.
+ /// It may work as a non-constant invocation on some platforms which
+ /// have access to compiler options at run-time, but most ahead-of-time
+ /// compiled platforms will not have this information.
// The .fromEnvironment() constructors are special in that we do not want
// users to call them using "new". We prohibit that by giving them bodies
// that throw, even though const constructors are not allowed to have bodies.
diff --git a/tools/VERSION b/tools/VERSION
index 5d2c02e..369f442 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 15
PATCH 0
-PRERELEASE 0
+PRERELEASE 1
PRERELEASE_PATCH 0
\ No newline at end of file