diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md index b6f824d0f5a..7ff78e19d2f 100644 --- a/pkg/analyzer/CHANGELOG.md +++ b/pkg/analyzer/CHANGELOG.md @@ -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. diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart index d605b1c189d..31dadf01495 100644 --- a/pkg/analyzer/lib/dart/element/element.dart +++ b/pkg/analyzer/lib/dart/element/element.dart @@ -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. diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart index 9a4651c78bc..191f7afe07e 100644 --- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart +++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart @@ -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); } } diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart index 3ad2cf91aef..46b2b3e9be1 100644 --- a/pkg/analyzer/lib/src/dart/element/element.dart +++ b/pkg/analyzer/lib/src/dart/element/element.dart @@ -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); } } diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart index 655578d6060..29c863bbb51 100644 --- a/pkg/analyzer/lib/src/dart/element/member.dart +++ b/pkg/analyzer/lib/src/dart/element/member.dart @@ -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); } } diff --git a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart index 92e70c17be6..1c2938f12ec 100644 --- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart +++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart @@ -344,7 +344,7 @@ class TypeSystemTypeOperations bool isLocalVariableWithoutDeclaredType(PromotableElement variable) { return variable is LocalVariableElement && variable.hasImplicitType && - variable.initializer == null; + !variable.hasInitializer; } @override diff --git a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart index 7dd433553b9..81255f6c8be 100644 --- a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart +++ b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart @@ -369,14 +369,7 @@ class ResolutionVisitor extends RecursiveAstVisitor { 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 { 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); }); }); diff --git a/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart index ce9ed26fd46..fb599638012 100644 --- a/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart +++ b/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart @@ -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(); } diff --git a/pkg/analyzer/lib/src/error/constructor_fields_verifier.dart b/pkg/analyzer/lib/src/error/constructor_fields_verifier.dart index efefa53bcd9..f3cea21456b 100644 --- a/pkg/analyzer/lib/src/error/constructor_fields_verifier.dart +++ b/pkg/analyzer/lib/src/error/constructor_fields_verifier.dart @@ -98,9 +98,9 @@ class ConstructorFieldsVerifier { _initialFieldMap = {}; 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; } } } diff --git a/pkg/analyzer/lib/src/error/inheritance_override.dart b/pkg/analyzer/lib/src/error/inheritance_override.dart index cac64404d92..159b36dd7cf 100644 --- a/pkg/analyzer/lib/src/error/inheritance_override.dart +++ b/pkg/analyzer/lib/src/error/inheritance_override.dart @@ -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)) { diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart index 32fd1848dbd..3b5fb678ebc 100644 --- a/pkg/analyzer/lib/src/generated/resolver.dart +++ b/pkg/analyzer/lib/src/generated/resolver.dart @@ -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 && diff --git a/pkg/analyzer/lib/src/summary2/top_level_inference.dart b/pkg/analyzer/lib/src/summary2/top_level_inference.dart index 2bd572770f6..0918c7038d4 100644 --- a/pkg/analyzer/lib/src/summary2/top_level_inference.dart +++ b/pkg/analyzer/lib/src/summary2/top_level_inference.dart @@ -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 { final Set _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; diff --git a/pkg/analyzer/lib/src/task/strong_mode.dart b/pkg/analyzer/lib/src/task/strong_mode.dart index d4f9bc9f2da..7e2636a6406 100644 --- a/pkg/analyzer/lib/src/task/strong_mode.dart +++ b/pkg/analyzer/lib/src/task/strong_mode.dart @@ -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; } diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml index e2d78c987a7..ce9a46b835b 100644 --- a/pkg/analyzer/pubspec.yaml +++ b/pkg/analyzer/pubspec.yaml @@ -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 diff --git a/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart index 33c55da4cd0..0aae50a3227 100644 --- a/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart +++ b/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart @@ -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 { diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart index 43f38c7737c..3484cc70fce 100644 --- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart +++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart @@ -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'); + _assertTypeStr(y.type, 'List'); } test_nullLiteralShouldNotInferAsBottom() async {