Stop using linked nodes for constructors.

Change-Id: I4ea147e415f4d622db3209184f02c630b75d0ecf
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/200060
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov
2021-05-15 17:03:19 +00:00
committed by commit-bot@chromium.org
parent fc15991ba7
commit ca005159ac
5 changed files with 108 additions and 157 deletions
+12 -117
View File
@@ -509,32 +509,6 @@ class ClassElementImpl extends AbstractClassElementImpl
return _constructors;
}
if (linkedNode != null) {
var context = enclosingUnit.linkedContext!;
var containerRef = reference!.getChild('@constructor');
_constructors = context.getConstructors(linkedNode!).map((node) {
var name = node.name?.name ?? '';
var reference = containerRef.getChild(name);
var element = node.declaredElement;
element ??= ConstructorElementImpl.forLinkedNode(this, reference, node);
return element;
}).toList();
if (_constructors.isEmpty) {
return _constructors = [
ConstructorElementImpl.forLinkedNode(
this,
containerRef.getChild(''),
null,
)
..isSynthetic = true
..name = ''
..nameOffset = -1
.._constantInitializers = const [],
];
}
}
if (_constructors.isEmpty) {
var constructor = ConstructorElementImpl('', -1);
constructor.isSynthetic = true;
@@ -954,13 +928,17 @@ class ClassElementImpl extends AbstractClassElementImpl
// substituting type parameters as appropriate.
return constructorsToForward
.map((ConstructorElement superclassConstructor) {
var containerRef = reference!.getChild('@constructor');
var name = superclassConstructor.name;
var implicitConstructor = ConstructorElementImpl.forLinkedNode(
this, containerRef.getChild(name), null);
var implicitConstructor = ConstructorElementImpl(name, -1);
implicitConstructor.isSynthetic = true;
implicitConstructor.name = name;
implicitConstructor.nameOffset = -1;
var containerRef = reference!.getChild('@constructor');
var implicitReference = containerRef.getChild(name);
implicitConstructor.reference = implicitReference;
implicitReference.element = implicitConstructor;
var hasMixinWithInstanceVariables = mixins.any(typeHasInstanceVariables);
implicitConstructor.isConst =
superclassConstructor.isConst && !hasMixinWithInstanceVariables;
@@ -1639,15 +1617,13 @@ class ConstructorElementImpl extends ExecutableElementImpl
/// The initializers for this constructor (used for evaluating constant
/// instance creation expressions).
List<ConstructorInitializer> _constantInitializers =
_Sentinel.constructorInitializer;
List<ConstructorInitializer> _constantInitializers = const [];
/// The offset of the `.` before this constructor name or `null` if not named.
int? _periodOffset;
@override
int? periodOffset;
/// Return the offset of the character immediately following the last
/// character of this constructor's name, or `null` if not named.
int? _nameEnd;
@override
int? nameEnd;
/// For every constructor we initially set this flag to `true`, and then
/// set it to `false` during computing constant values if we detect that it
@@ -1661,26 +1637,10 @@ class ConstructorElementImpl extends ExecutableElementImpl
/// and [offset].
ConstructorElementImpl(String name, int offset) : super(name, offset);
ConstructorElementImpl.forLinkedNode(ClassElementImpl enclosingClass,
Reference reference, ConstructorDeclarationImpl? linkedNode)
: super.forLinkedNode(enclosingClass, reference, linkedNode) {
linkedNode?.declaredElement = this;
}
/// Return the constant initializers for this element, which will be empty if
/// there are no initializers, or `null` if there was an error in the source.
List<ConstructorInitializer> get constantInitializers {
linkedData?.read(this);
if (!identical(_constantInitializers, _Sentinel.constructorInitializer)) {
return _constantInitializers;
}
if (linkedNode != null) {
return _constantInitializers = linkedContext!.getConstructorInitializers(
linkedNode as ConstructorDeclaration,
);
}
return _constantInitializers;
}
@@ -1698,9 +1658,6 @@ class ConstructorElementImpl extends ExecutableElementImpl
return linkedData.reference.name;
}
if (linkedNode != null) {
return reference!.name;
}
return super.displayName;
}
@@ -1710,10 +1667,6 @@ class ConstructorElementImpl extends ExecutableElementImpl
@override
bool get isConst {
if (linkedNode != null) {
final linkedNode = this.linkedNode as ConstructorDeclaration;
return linkedNode.constKeyword != null;
}
return hasModifier(Modifier.CONST);
}
@@ -1734,10 +1687,6 @@ class ConstructorElementImpl extends ExecutableElementImpl
@override
bool get isFactory {
if (linkedNode != null) {
final linkedNode = this.linkedNode as ConstructorDeclaration;
return linkedNode.factoryKeyword != null;
}
return hasModifier(Modifier.FACTORY);
}
@@ -1752,61 +1701,9 @@ class ConstructorElementImpl extends ExecutableElementImpl
@override
ElementKind get kind => ElementKind.CONSTRUCTOR;
@override
int? get nameEnd {
if (linkedNode != null) {
var node = linkedNode as ConstructorDeclaration;
if (node.name != null) {
return node.name!.end;
} else {
return node.returnType.end;
}
}
return _nameEnd;
}
set nameEnd(int? nameEnd) {
_nameEnd = nameEnd;
}
@override
int? get periodOffset {
if (linkedNode != null) {
var node = linkedNode as ConstructorDeclaration;
return node.period?.offset;
}
return _periodOffset;
}
set periodOffset(int? periodOffset) {
_periodOffset = periodOffset;
}
@override
ConstructorElement? get redirectedConstructor {
linkedData?.read(this);
if (_redirectedConstructor != null) return _redirectedConstructor;
if (linkedNode != null) {
var context = enclosingUnit.linkedContext!;
if (isFactory) {
var node = context
.getConstructorRedirected(linkedNode as ConstructorDeclaration);
return _redirectedConstructor = node?.staticElement;
} else {
var initializers = context
.getConstructorInitializers(linkedNode as ConstructorDeclaration);
for (var initializer in initializers) {
if (initializer is RedirectingConstructorInvocation) {
return _redirectedConstructor = initializer.staticElement;
}
}
}
return null;
}
return _redirectedConstructor;
}
@@ -6821,8 +6718,6 @@ class _Sentinel {
static final List<ClassElement> classElement = List.unmodifiable([]);
static final List<ConstructorElement> constructorElement =
List.unmodifiable([]);
static final List<ConstructorInitializer> constructorInitializer =
List.unmodifiable([]);
static final List<ElementAnnotation> elementAnnotation =
List.unmodifiable([]);
static final List<ExportElement> exportElement = List.unmodifiable([]);
@@ -2,7 +2,7 @@
// 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/element/element.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/scope.dart';
@@ -14,47 +14,55 @@ class ConstructorInitializerResolver {
final Linker _linker;
final LibraryElementImpl _libraryElement;
late CompilationUnitElementImpl _unitElement;
late ClassElement _classElement;
late ConstructorElement _constructorElement;
late ConstructorDeclarationImpl _constructorNode;
late AstResolver _astResolver;
ConstructorInitializerResolver(this._linker, this._libraryElement);
void resolve() {
for (var unit in _libraryElement.units) {
_unitElement = unit as CompilationUnitElementImpl;
for (var classElement in unit.types) {
_classElement = classElement;
for (var unitElement in _libraryElement.units) {
var classElements = [...unitElement.mixins, ...unitElement.types];
for (var classElement in classElements) {
for (var constructorElement in classElement.constructors) {
_constructor(constructorElement as ConstructorElementImpl);
_constructor(
unitElement as CompilationUnitElementImpl,
classElement as ClassElementImpl,
constructorElement as ConstructorElementImpl,
);
}
}
}
}
void _constructor(ConstructorElementImpl constructorElement) {
if (constructorElement.isSynthetic) return;
void _constructor(
CompilationUnitElementImpl unitElement,
ClassElementImpl classElement,
ConstructorElementImpl element,
) {
if (element.isSynthetic) return;
_constructorElement = constructorElement;
_constructorNode =
constructorElement.linkedNode as ConstructorDeclarationImpl;
var node = _linker.getLinkingNode(element) as ConstructorDeclarationImpl;
var functionScope = LinkingNodeContext.get(_constructorNode).scope;
var functionScope = LinkingNodeContext.get(node).scope;
var initializerScope = ConstructorInitializerScope(
functionScope,
constructorElement,
element,
);
_astResolver = AstResolver(
_linker, _unitElement, initializerScope, _constructorNode,
enclosingClassElement: _classElement,
enclosingExecutableElement: _constructorElement);
var astResolver = AstResolver(_linker, unitElement, initializerScope, node,
enclosingClassElement: classElement,
enclosingExecutableElement: element);
var body = _constructorNode.body;
var body = node.body;
body.localVariableInfo = LocalVariableInfo();
_astResolver.resolveConstructorNode(_constructorNode);
astResolver.resolveConstructorNode(node);
if (node.factoryKeyword != null) {
element.redirectedConstructor = node.redirectedConstructor?.staticElement;
} else {
for (var initializer in node.initializers) {
if (initializer is RedirectingConstructorInvocation) {
element.redirectedConstructor = initializer.staticElement;
}
}
}
}
}
@@ -77,6 +77,33 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
_buildClassOrMixin(node);
}
@override
void visitConstructorDeclaration(
covariant ConstructorDeclarationImpl node,
) {
var nameNode = node.name;
var name = nameNode?.name ?? '';
var nameOffset = nameNode?.offset ?? -1;
var element = ConstructorElementImpl(name, nameOffset);
element.constantInitializers = node.initializers;
element.isConst = node.constKeyword != null;
element.isExternal = node.externalKeyword != null;
element.isFactory = node.factoryKeyword != null;
element.metadata = _buildAnnotations(node.metadata);
_setCodeRange(element, node);
node.declaredElement = element;
_linker.elementNodes[element] = node;
var reference = _enclosingContext.addConstructor(name, element);
_buildExecutableElementChildren(
reference: reference,
element: element,
formalParameters: node.parameters,
);
}
@override
void visitDefaultFormalParameter(DefaultFormalParameter node) {
node.parameter.accept(this);
@@ -186,18 +213,19 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
element = DefaultFieldFormalParameterElementImpl(name, nameOffset)
..constantInitializer = parent.defaultValue;
_linker.elementNodes[element] = parent;
_enclosingContext.addParameter(name, element);
} else {
element = FieldFormalParameterElementImpl(name, nameOffset);
_linker.elementNodes[element] = node;
_enclosingContext.addParameter(null, element);
}
element.hasImplicitType = node.type == null;
element.hasImplicitType = node.type == null && node.parameters == null;
element.isExplicitlyCovariant = node.covariantKeyword != null;
element.isFinal = node.isFinal;
element.metadata = _buildAnnotations(node.metadata);
element.parameterKind = node.kind;
_setCodeRange(element, node);
_enclosingContext.addParameter(element.name, element);
nameNode.staticElement = element;
var fakeReference = Reference.root();
@@ -445,11 +473,12 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
element = DefaultParameterElementImpl(name, nameOffset)
..constantInitializer = parent.defaultValue;
_linker.elementNodes[element] = parent;
_enclosingContext.addParameter(name, element);
} else {
element = ParameterElementImpl(name, nameOffset);
_linker.elementNodes[element] = node;
_enclosingContext.addParameter(null, element);
}
_enclosingContext.addParameter(element.name, element);
element.hasImplicitType = node.type == null;
element.isConst = node.isConst;
@@ -537,19 +566,14 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
}
_EnclosingContext _buildClassMembers(
ElementImpl element, List<ClassMember> members) {
ElementImpl element, NodeList<ClassMember> members) {
var hasConstConstructor = members.any((e) {
return e is ConstructorDeclaration && e.constKeyword != null;
});
var holder = _EnclosingContext(element.reference!, element,
hasConstConstructor: hasConstConstructor);
_withEnclosing(holder, () {
// TODO(scheglov) build all members
for (var member in members) {
if (member is FieldDeclaration || member is MethodDeclaration) {
member.accept(this);
}
}
members.accept(this);
});
return holder;
}
@@ -560,6 +584,27 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
element.accessors = holder.propertyAccessors;
element.fields = holder.properties.whereType<FieldElement>().toList();
element.methods = holder.methods;
var constructors = holder.constructors;
if (constructors.isEmpty) {
var containerRef = element.reference!.getChild('@constructor');
constructors = [
ConstructorElementImpl('', -1)
..isSynthetic = true
..reference = containerRef.getChild(''),
];
}
element.constructors = constructors;
// We have all fields and constructors.
// Now we can resolve field formal parameters.
for (var constructor in constructors) {
for (var parameter in constructor.parameters) {
if (parameter is FieldFormalParameterElementImpl) {
parameter.field = element.getField(parameter.name);
}
}
}
}
void _buildExecutableElementChildren({
@@ -766,6 +811,7 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
class _EnclosingContext {
final Reference reference;
final ElementImpl element;
final List<ConstructorElementImpl> constructors = [];
final List<EnumElementImpl> enums = [];
final List<FunctionElementImpl> functions = [];
final List<MethodElementImpl> methods = [];
@@ -781,6 +827,11 @@ class _EnclosingContext {
this.hasConstConstructor = false,
});
Reference addConstructor(String name, ConstructorElementImpl element) {
constructors.add(element);
return _bindReference('@constructor', name, element);
}
Reference addEnum(String name, EnumElementImpl element) {
enums.add(element);
return _bindReference('@enum', name, element);
@@ -140,9 +140,10 @@ class _ConstructorInferenceNode extends _InferenceNode {
this._constructor,
Map<String, FieldElement> fieldMap,
) {
// TODO(scheglov) Can we rewrite this to just elements?
for (var parameterElement in _constructor.parameters) {
if (parameterElement is FieldFormalParameterElement) {
var parameterNode = _getLinkedNode(parameterElement);
var parameterNode = _walker._linker.getLinkingNode(parameterElement);
if (parameterNode is DefaultFormalParameter) {
parameterNode = parameterNode.parameter;
}
@@ -4,7 +4,6 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
@@ -25,9 +24,6 @@ mixin M {
}
''', [
error(ParserErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 27, 1),
// TODO(srawlins): Don't report this from within a mixin.
error(
CompileTimeErrorCode.FIELD_INITIALIZING_FORMAL_NOT_ASSIGNABLE, 29, 6),
]);
var element = findElement.mixin('M');