mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 09:01:42 +00:00
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:
parent
42dec58c01
commit
085076337b
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -344,7 +344,7 @@ class TypeSystemTypeOperations
|
|||
bool isLocalVariableWithoutDeclaredType(PromotableElement variable) {
|
||||
return variable is LocalVariableElement &&
|
||||
variable.hasImplicitType &&
|
||||
variable.initializer == null;
|
||||
!variable.hasInitializer;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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 &&
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue