Add LocalVariableElement/PropertyInducingElement.hasInitializer, ParameterElement.hasDefaultValue, deprecate VariableElement.initializer

Change-Id: I02ba37b4f6f1ce79ffddf40613646b99ecbedc9d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/159582
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Konstantin Shcheglov 2020-08-21 18:20:30 +00:00 committed by commit-bot@chromium.org
parent 42dec58c01
commit 085076337b
16 changed files with 107 additions and 149 deletions

View file

@ -1,3 +1,7 @@
## 0.40.1-dev
* Added `LocalVariableElement.hasInitializer`,
`PropertyInducingElement.hasInitializer`, `ParameterElement.hasDefaultValue`.
## 0.40.0
* Added `LibraryElement.featureSet`.
* Removed deprecated `EmbedderSdk` and related classes.

View file

@ -1388,7 +1388,10 @@ abstract class LocalElement implements Element {}
/// A local variable.
///
/// Clients may not extend, implement or mix-in this class.
abstract class LocalVariableElement implements PromotableElement {}
abstract class LocalVariableElement implements PromotableElement {
/// Return `true` if this variable has an initializer at declaration.
bool get hasInitializer;
}
/// An element that represents a method defined within a class.
///
@ -1440,6 +1443,9 @@ abstract class ParameterElement
/// Return the Dart code of the default value, or `null` if no default value.
String get defaultValueCode;
/// Return `true` if this parameter has a default value.
bool get hasDefaultValue;
/// Return `true` if this parameter is covariant, meaning it is allowed to
/// have a narrower type in an override.
bool get isCovariant;
@ -1598,6 +1604,9 @@ abstract class PropertyInducingElement implements VariableElement {
/// will be synthetic.
PropertyAccessorElement get getter;
/// Return `true` if this variable has an initializer at declaration.
bool get hasInitializer;
/// Return the setter associated with this variable, or `null` if the variable
/// is effectively `final` and therefore does not have a setter associated
/// with it. (This can happen either because the variable is explicitly
@ -1728,6 +1737,7 @@ abstract class VariableElement implements Element, ConstantEvaluationTarget {
/// `null` if this variable does not have an initializer. The function will
/// have no parameters. The return type of the function will be the
/// compile-time type of the initialization expression.
@deprecated
FunctionElement get initializer;
/// Return `true` if this variable was declared with the 'const' modifier.

View file

@ -369,7 +369,7 @@ class ConstantEvaluationEngine {
// that we won't be confused by incorrect code.
if ((field.isFinal || field.isConst) &&
!field.isStatic &&
field.initializer != null) {
field.hasInitializer) {
callback(field);
}
}

View file

@ -1783,6 +1783,9 @@ class ConstFieldElementImpl_EnumValue extends ConstFieldElementImpl_ofEnum {
return _evaluationResult;
}
@override
bool get hasInitializer => false;
@override
String get name {
if (linkedNode != null) {
@ -5615,6 +5618,9 @@ class LibraryElementImpl extends ElementImpl implements LibraryElement {
/// A concrete implementation of a [LocalVariableElement].
class LocalVariableElementImpl extends NonParameterVariableElementImpl
implements LocalVariableElement {
@override
bool hasInitializer;
/// Initialize a newly created method element to have the given [name] and
/// [offset].
LocalVariableElementImpl(String name, int offset) : super(name, offset);
@ -6218,24 +6224,26 @@ abstract class NonParameterVariableElementImpl extends VariableElementImpl {
super.hasImplicitType = hasImplicitType;
}
bool get hasInitializer {
return linkedNode != null && linkedContext.hasInitializer(linkedNode);
}
@deprecated
@override
FunctionElement get initializer {
if (_initializer == null) {
if (linkedNode != null) {
if (linkedContext.hasInitializer(linkedNode)) {
_initializer = FunctionElementImpl('', -1)
..isSynthetic = true
.._type = FunctionTypeImpl(
typeFormals: const [],
parameters: const [],
returnType: type,
nullabilitySuffix: NullabilitySuffix.star,
)
..enclosingElement = this;
}
}
if (hasInitializer) {
return FunctionElementImpl('', -1)
..enclosingElement = this
..isSynthetic = true
..returnType = type
.._type = FunctionTypeImpl(
typeFormals: const [],
parameters: const [],
returnType: type,
nullabilitySuffix: NullabilitySuffix.star,
);
}
return super.initializer;
return null;
}
@override
@ -6278,19 +6286,16 @@ abstract class NonParameterVariableElementImpl extends VariableElementImpl {
return null;
}
bool get _hasInitializer {
return linkedNode != null && linkedContext.hasInitializer(linkedNode);
}
/// Return `true` if this variable needs the setter.
bool get _hasSetter {
if (isConst) {
return false;
}
// TODO(scheglov) is this right?
if (isLate) {
if (isFinal) {
return !_hasInitializer;
return !hasInitializer;
}
return true;
}
@ -6388,6 +6393,11 @@ class ParameterElementImpl extends VariableElementImpl
_defaultValueCode = StringUtilities.intern(defaultValueCode);
}
@override
bool get hasDefaultValue {
return defaultValueCode != null;
}
@override
bool get hasImplicitType {
if (linkedNode != null) {
@ -6420,28 +6430,6 @@ class ParameterElementImpl extends VariableElementImpl
_inheritsCovariant = value;
}
@override
FunctionElement get initializer {
if (_initializer != null) return _initializer;
if (linkedNode != null) {
if (linkedContext.hasDefaultValue(linkedNode)) {
_initializer = FunctionElementImpl('', -1)
..enclosingElement = this
..isSynthetic = true;
}
}
return super.initializer;
}
/// Set the function representing this variable's initializer to the given
/// [function].
@override
set initializer(FunctionElement function) {
super.initializer = function;
}
@override
bool get isCovariant {
if (isExplicitlyCovariant || inheritsCovariant) {
@ -7112,6 +7100,10 @@ abstract class PropertyInducingElementImpl
@override
PropertyAccessorElement setter;
/// This field is set during linking, and performs type inference for
/// this property. After linking this field is always `null`.
PropertyInducingElementTypeInference typeInference;
/// Initialize a newly created synthetic element to have the given [name] and
/// [offset].
PropertyInducingElementImpl(String name, int offset) : super(name, offset);
@ -7156,6 +7148,12 @@ abstract class PropertyInducingElementImpl
}
}
/// Instances of this class are set for fields and top-level variables
/// to perform top-level type inference during linking.
abstract class PropertyInducingElementTypeInference {
void perform();
}
/// A concrete implementation of a [ShowElementCombinator].
class ShowElementCombinatorImpl implements ShowElementCombinator {
final LinkedUnitContext linkedContext;
@ -7557,10 +7555,6 @@ abstract class VariableElementImpl extends ElementImpl
/// The type of this variable.
DartType _type;
/// A synthetic function representing this variable's initializer, or `null
///` if this variable does not have an initializer.
FunctionElement _initializer;
/// Initialize a newly created variable element to have the given [name] and
/// [offset].
VariableElementImpl(String name, int offset) : super(name, offset);
@ -7613,17 +7607,9 @@ abstract class VariableElementImpl extends ElementImpl
setModifier(Modifier.IMPLICIT_TYPE, hasImplicitType);
}
@deprecated
@override
FunctionElement get initializer => _initializer;
/// Set the function representing this variable's initializer to the given
/// [function].
set initializer(FunctionElement function) {
if (function != null) {
(function as FunctionElementImpl).enclosingElement = this;
}
_initializer = function;
}
FunctionElement get initializer => null;
@override
bool get isConst {
@ -7684,6 +7670,7 @@ abstract class VariableElementImpl extends ElementImpl
@override
void visitChildren(ElementVisitor visitor) {
super.visitChildren(visitor);
_initializer?.accept(visitor);
// ignore: deprecated_member_use_from_same_package
initializer?.accept(visitor);
}
}

View file

@ -211,8 +211,6 @@ abstract class ExecutableMember extends Member implements ExecutableElement {
@override
void visitChildren(ElementVisitor visitor) {
// TODO(brianwilkerson) We need to finish implementing the accessors used
// below so that we can safely invoke them.
super.visitChildren(visitor);
safelyVisitChildren(parameters, visitor);
}
@ -295,6 +293,9 @@ class FieldFormalParameterMember extends ParameterMember
return FieldMember(field, _substitution, isLegacy);
}
@override
bool get hasDefaultValue => declaration.hasDefaultValue;
@override
bool get isCovariant => declaration.isCovariant;
@ -333,6 +334,9 @@ class FieldMember extends VariableMember implements FieldElement {
return PropertyAccessorMember(baseGetter, _substitution, isLegacy);
}
@override
bool get hasInitializer => declaration.hasInitializer;
@override
bool get isAbstract => declaration.isAbstract;
@ -771,6 +775,9 @@ class ParameterMember extends VariableMember
@override
Element get enclosingElement => declaration.enclosingElement;
@override
bool get hasDefaultValue => declaration.hasDefaultValue;
@override
int get hashCode => declaration.hashCode;
@ -950,6 +957,9 @@ class TopLevelVariableMember extends VariableMember
return PropertyAccessorMember(baseGetter, _substitution, isLegacy);
}
@override
bool get hasInitializer => declaration.hasInitializer;
@override
bool get isExternal => declaration.isExternal;
@ -1039,9 +1049,8 @@ abstract class VariableMember extends Member implements VariableElement {
@override
void visitChildren(ElementVisitor visitor) {
// TODO(brianwilkerson) We need to finish implementing the accessors used
// below so that we can safely invoke them.
super.visitChildren(visitor);
// ignore: deprecated_member_use_from_same_package
declaration.initializer?.accept(visitor);
}
}

View file

@ -344,7 +344,7 @@ class TypeSystemTypeOperations
bool isLocalVariableWithoutDeclaredType(PromotableElement variable) {
return variable is LocalVariableElement &&
variable.hasImplicitType &&
variable.initializer == null;
!variable.hasInitializer;
}
@override

View file

@ -369,14 +369,7 @@ class ResolutionVisitor extends RecursiveAstVisitor<void> {
var defaultValue = node.defaultValue;
if (defaultValue != null) {
_withElementWalker(null, () {
var offset = defaultValue.offset;
var initializer = FunctionElementImpl.forOffset(offset);
element.initializer = initializer;
initializer.hasImplicitReturnType = true;
initializer.isSynthetic = true;
_withElementHolder(ElementHolder(initializer), () {
_withElementHolder(ElementHolder(element), () {
defaultValue.accept(this);
});
});
@ -962,19 +955,13 @@ class ResolutionVisitor extends RecursiveAstVisitor<void> {
VariableDeclarationList varList = node.parent;
localElement.hasImplicitType = varList.type == null;
localElement.hasInitializer = initializerNode != null;
localElement.type = varList.type?.type ?? _dynamicType;
}
if (initializerNode != null) {
_withElementWalker(null, () {
var offset = initializerNode.offset;
var initializer = FunctionElementImpl.forOffset(offset);
element.initializer = initializer;
initializer.hasImplicitReturnType = true;
initializer.isSynthetic = true;
_withElementHolder(ElementHolder(initializer), () {
_withElementHolder(ElementHolder(element), () {
initializerNode.accept(this);
});
});

View file

@ -61,11 +61,6 @@ class VariableDeclarationResolver {
_setInferredType(element, initializer.staticType);
}
if (element.initializer != null) {
var initializerFunction = element.initializer as FunctionElementImpl;
initializerFunction.returnType = initializer.staticType;
}
if (isTopLevel) {
_flowAnalysis?.topLevelDeclaration_exit();
}

View file

@ -98,9 +98,9 @@ class ConstructorFieldsVerifier {
_initialFieldMap = <FieldElement, _InitState>{};
for (var field in element.fields) {
if (!field.isSynthetic) {
_initialFieldMap[field] = field.initializer == null
? _InitState.notInit
: _InitState.initInDeclaration;
_initialFieldMap[field] = field.hasInitializer
? _InitState.initInDeclaration
: _InitState.notInit;
}
}
}

View file

@ -422,13 +422,13 @@ class _ClassVerifier {
var derivedElement = derivedOptionalElements[i];
if (_isNonNullableByDefault &&
derivedIsAbstract &&
derivedElement.initializer == null) {
!derivedElement.hasDefaultValue) {
continue;
}
var name = derivedElement.name;
for (var j = 0; j < baseOptionalElements.length; j++) {
var baseParameter = baseOptionalElements[j];
if (name == baseParameter.name && baseParameter.initializer != null) {
if (name == baseParameter.name && baseParameter.hasDefaultValue) {
var baseValue = baseParameter.computeConstantValue();
var derivedResult = derivedElement.evaluationResult;
if (!_constantValuesEqual(derivedResult.value, baseValue)) {
@ -453,11 +453,11 @@ class _ClassVerifier {
var derivedElement = derivedOptionalElements[i];
if (_isNonNullableByDefault &&
derivedIsAbstract &&
derivedElement.initializer == null) {
!derivedElement.hasDefaultValue) {
continue;
}
var baseElement = baseOptionalElements[i];
if (baseElement.initializer != null) {
if (baseElement.hasDefaultValue) {
var baseValue = baseElement.computeConstantValue();
var derivedResult = derivedElement.evaluationResult;
if (!_constantValuesEqual(derivedResult.value, baseValue)) {

View file

@ -1003,10 +1003,6 @@ class ResolverVisitor extends ScopedVisitor {
super.visitDefaultFormalParameter(node);
ParameterElement element = node.declaredElement;
if (element.initializer != null && node.defaultValue != null) {
(element.initializer as FunctionElementImpl).returnType =
node.defaultValue.staticType;
}
// Clone the ASTs for default formal parameters, so that we can use them
// during constant evaluation.
if (element is ConstVariableElement &&

View file

@ -11,7 +11,6 @@ import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_demotion.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/generated/element_type_provider.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/idl.dart';
@ -197,31 +196,6 @@ class _ConstructorInferenceNode extends _InferenceNode {
}
}
class _FunctionElementForLink_Initializer
implements FunctionElementImpl, ElementImplWithFunctionType {
final _VariableInferenceNode _node;
@override
Element enclosingElement;
_FunctionElementForLink_Initializer(this._node);
@override
DartType get returnType =>
ElementTypeProvider.current.getExecutableReturnType(this);
@override
DartType get returnTypeInternal {
if (!_node.isEvaluated) {
_node._walker.walk(_node);
}
return LazyAst.getType(_node._node);
}
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class _InferenceDependenciesCollector extends RecursiveAstVisitor<void> {
final Set<Element> _set = Set.identity();
@ -356,14 +330,28 @@ class _InitializerInference {
var inferenceNode =
_VariableInferenceNode(_walker, _unitElement, _scope, node);
_walker._nodes[element] = inferenceNode;
(element as PropertyInducingElementImpl).initializer =
_FunctionElementForLink_Initializer(inferenceNode);
(element as PropertyInducingElementImpl).typeInference =
_PropertyInducingElementTypeInference(inferenceNode);
} else {
LazyAst.setType(node, DynamicTypeImpl.instance);
}
}
}
class _PropertyInducingElementTypeInference
implements PropertyInducingElementTypeInference {
final _VariableInferenceNode _node;
_PropertyInducingElementTypeInference(this._node);
@override
void perform() {
if (!_node.isEvaluated) {
_node._walker.walk(_node);
}
}
}
class _VariableInferenceNode extends _InferenceNode {
final _InferenceWalker _walker;
final CompilationUnitElement _unitElement;

View file

@ -292,15 +292,7 @@ class InstanceMemberInferrer {
// Otherwise, declarations of static variables and fields that omit a
// type will be inferred from their initializer if present.
var initializer = field.initializer;
if (initializer != null) {
var initializerType = initializer.returnType;
if (initializerType == null || initializerType.isDartCoreNull) {
initializerType = _dynamicType;
}
field.type = initializerType;
return;
}
field.typeInference?.perform();
return;
}

View file

@ -1,5 +1,5 @@
name: analyzer
version: 0.40.0
version: 0.40.1-dev
description: This package provides a library that performs static analysis of Dart code.
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer

View file

@ -1056,12 +1056,11 @@ class C {
ClassDeclaration c = unit.declarations[0];
FieldDeclaration declaration = c.members[0];
VariableDeclaration field = declaration.fields.variables[0];
FunctionElement fieldInitializer = field.declaredElement.initializer;
FunctionExpressionInvocation invocation = field.initializer;
FunctionExpression closure = invocation.function.unParenthesized;
FunctionElementImpl closureElement = closure.declaredElement;
expect(closureElement.enclosingElement, same(fieldInitializer));
expect(closureElement, isNotNull);
}
test_closure_inTopLevelVariable() async {
@ -1073,13 +1072,11 @@ var v = (() => 42)();
TopLevelVariableDeclaration declaration = unit.declarations[0];
VariableDeclaration variable = declaration.variables.variables[0];
TopLevelVariableElement variableElement = variable.declaredElement;
FunctionElement variableInitializer = variableElement.initializer;
FunctionExpressionInvocation invocation = variable.initializer;
FunctionExpression closure = invocation.function.unParenthesized;
FunctionElementImpl closureElement = closure.declaredElement;
expect(closureElement.enclosingElement, same(variableInitializer));
expect(closureElement, isNotNull);
}
test_conditionalExpression() async {

View file

@ -354,26 +354,19 @@ main() {
}
test_bottom() async {
// When a type is inferred from the expression `null`, the inferred type is
// `dynamic`, but the inferred type of the initializer is `bottom`.
// TODO(paulberry): Is this intentional/desirable?
await assertNoErrorsInCode('''
var v = null;
''');
var v = _resultUnitElement.topLevelVariables[0];
_assertTypeStr(v.type, 'dynamic');
_assertTypeStr(v.initializer.type, 'Null Function()');
}
test_bottom_inClosure() async {
// When a closure's return type is inferred from the expression `null`, the
// inferred type is `dynamic`.
await assertNoErrorsInCode('''
var v = () => null;
''');
var v = _resultUnitElement.topLevelVariables[0];
_assertTypeStr(v.type, 'Null Function()');
_assertTypeStr(v.initializer.type, 'Null Function() Function()');
}
test_circularReference_viaClosures() async {
@ -406,8 +399,8 @@ var y = () => x;
var y = _resultUnitElement.topLevelVariables[1];
expect(x.name, 'x');
expect(y.name, 'y');
_assertTypeStr(x.initializer.returnType, 'dynamic Function()');
_assertTypeStr(y.initializer.returnType, 'dynamic Function()');
_assertTypeStr(x.type, 'dynamic');
_assertTypeStr(y.type, 'dynamic');
}
test_conflictsCanHappen2() async {
@ -4117,7 +4110,7 @@ main() {
]);
var y = findLocalVariable(_resultUnit, 'y');
_assertTypeStr(y.initializer.returnType, 'List<num>');
_assertTypeStr(y.type, 'List<num>');
}
test_nullLiteralShouldNotInferAsBottom() async {