| Index: pkg/analyzer/lib/src/task/strong/info.dart
|
| diff --git a/pkg/analyzer/lib/src/task/strong/info.dart b/pkg/analyzer/lib/src/task/strong/info.dart
|
| index 9d4812f8b9839edc61a1dea5da4431605cf954dc..0c2e48a58309f2634fbc8918cc8c4e6d389ad315 100644
|
| --- a/pkg/analyzer/lib/src/task/strong/info.dart
|
| +++ b/pkg/analyzer/lib/src/task/strong/info.dart
|
| @@ -14,6 +14,25 @@ import 'package:analyzer/src/generated/error.dart';
|
|
|
| import 'rules.dart';
|
|
|
| +// A down cast due to a variable declaration to a ground type. E.g.,
|
| +// T x = expr;
|
| +// where T is ground. We exclude non-ground types as these behave differently
|
| +// compared to standard Dart.
|
| +class AssignmentCast extends DownCast {
|
| + AssignmentCast(TypeRules rules, Expression expression, Cast cast)
|
| + : super._internal(rules, expression, cast);
|
| +
|
| + @override
|
| + String get name => 'STRONG_MODE_ASSIGNMENT_CAST';
|
| +
|
| + toErrorCode() => new HintCode(name, message);
|
| +}
|
| +
|
| +// Coercion which casts one type to another
|
| +class Cast extends Coercion {
|
| + Cast(DartType fromType, DartType toType) : super(fromType, toType);
|
| +}
|
| +
|
| // The abstract type of coercions mapping one type to another.
|
| // This class also exposes static builder functions which
|
| // check for errors and reduce redundant coercions to the identity.
|
| @@ -22,18 +41,8 @@ abstract class Coercion {
|
| final DartType toType;
|
| Coercion(this.fromType, this.toType);
|
| static Coercion cast(DartType fromT, DartType toT) => new Cast(fromT, toT);
|
| - static Coercion identity(DartType type) => new Identity(type);
|
| static Coercion error() => new CoercionError();
|
| -}
|
| -
|
| -// Coercion which casts one type to another
|
| -class Cast extends Coercion {
|
| - Cast(DartType fromType, DartType toType) : super(fromType, toType);
|
| -}
|
| -
|
| -// The identity coercion
|
| -class Identity extends Coercion {
|
| - Identity(DartType fromType) : super(fromType, fromType);
|
| + static Coercion identity(DartType type) => new Identity(type);
|
| }
|
|
|
| // The error coercion. This coercion signals that a coercion
|
| @@ -43,50 +52,23 @@ class CoercionError extends Coercion {
|
| CoercionError() : super(null, null);
|
| }
|
|
|
| -// TODO(jmesserly): this could use some refactoring. These are essentially
|
| -// like ErrorCodes in analyzer, but we're including some details in our message.
|
| -// Analyzer instead has template strings, and replaces '{0}' with the first
|
| -// argument.
|
| -abstract class StaticInfo {
|
| - /// AST Node this info is attached to.
|
| - AstNode get node;
|
| -
|
| - // TODO(jmesserly): review the usage of error codes. We probably want our own,
|
| - // as well as some DDC specific [ErrorType]s.
|
| - ErrorCode toErrorCode();
|
| -
|
| - // TODO(jmesserly): what convention to use here?
|
| - String get name => 'dev_compiler.$runtimeType';
|
| -
|
| - List<Object> get arguments => [node];
|
| -
|
| - AnalysisError toAnalysisError() {
|
| - int begin = node is AnnotatedNode
|
| - ? (node as AnnotatedNode).firstTokenAfterCommentAndMetadata.offset
|
| - : node.offset;
|
| - int length = node.end - begin;
|
| - var source = (node.root as CompilationUnit).element.source;
|
| - return new AnalysisError(source, begin, length, toErrorCode(), arguments);
|
| - }
|
| -}
|
| -
|
| /// Implicitly injected expression conversion.
|
| abstract class CoercionInfo extends StaticInfo {
|
| + static const String _propertyName = 'dev_compiler.src.info.CoercionInfo';
|
| +
|
| final TypeRules rules;
|
|
|
| final Expression node;
|
|
|
| - DartType get convertedType;
|
| -
|
| CoercionInfo(this.rules, this.node);
|
|
|
| DartType get baseType => rules.getStaticType(node);
|
| - DartType get staticType => convertedType;
|
| + DartType get convertedType;
|
|
|
| String get message;
|
| - toErrorCode() => new HintCode(name, message);
|
| + DartType get staticType => convertedType;
|
|
|
| - static const String _propertyName = 'dev_compiler.src.info.CoercionInfo';
|
| + toErrorCode() => new HintCode(name, message);
|
|
|
| /// Gets the coercion info associated with this node.
|
| static CoercionInfo get(AstNode node) => node.getProperty(_propertyName);
|
| @@ -112,11 +94,11 @@ abstract class DownCast extends CoercionInfo {
|
| baseType.isAssignableTo(_cast.toType)));
|
| }
|
|
|
| + @override List<Object> get arguments => [node, baseType, convertedType];
|
| +
|
| Cast get cast => _cast;
|
|
|
| DartType get convertedType => _cast.toType;
|
| -
|
| - @override List<Object> get arguments => [node, baseType, convertedType];
|
| @override String get message => '{0} ({1}) will need runtime check '
|
| 'to cast to type {2}';
|
|
|
| @@ -195,55 +177,17 @@ abstract class DownCast extends CoercionInfo {
|
| }
|
|
|
| //
|
| -// Standard down casts. These casts are implicitly injected by the compiler.
|
| -//
|
| -
|
| -// A down cast from dynamic to T.
|
| -class DynamicCast extends DownCast {
|
| - DynamicCast(TypeRules rules, Expression expression, Cast cast)
|
| - : super._internal(rules, expression, cast);
|
| -
|
| - toErrorCode() => new HintCode(name, message);
|
| -}
|
| -
|
| -// A down cast due to a variable declaration to a ground type. E.g.,
|
| -// T x = expr;
|
| -// where T is ground. We exclude non-ground types as these behave differently
|
| -// compared to standard Dart.
|
| -class AssignmentCast extends DownCast {
|
| - AssignmentCast(TypeRules rules, Expression expression, Cast cast)
|
| - : super._internal(rules, expression, cast);
|
| -
|
| - toErrorCode() => new HintCode(name, message);
|
| -}
|
| -
|
| -//
|
| -// Temporary "casts" of allocation sites - literals, constructor invocations,
|
| -// and closures. These should be handled by contextual inference. In most
|
| -// cases, inference will be sufficient, though in some it may unmask an actual
|
| -// error: e.g.,
|
| -// List<int> l = [1, 2, 3]; // Inference succeeds
|
| -// List<String> l = [1, 2, 3]; // Inference reveals static type error
|
| -// We're marking all as warnings for now.
|
| -//
|
| -// TODO(vsm,leafp): Remove this.
|
| -class UninferredClosure extends DownCast {
|
| - UninferredClosure(TypeRules rules, FunctionExpression expression, Cast cast)
|
| - : super._internal(rules, expression, cast);
|
| -
|
| - toErrorCode() => new StaticTypeWarningCode(name, message);
|
| -}
|
| -
|
| -//
|
| // Implicit down casts. These are only injected by the compiler by flag.
|
| //
|
| -
|
| // A down cast to a non-ground type. These behave differently from standard
|
| // Dart and may be more likely to fail at runtime.
|
| class DownCastComposite extends DownCast {
|
| DownCastComposite(TypeRules rules, Expression expression, Cast cast)
|
| : super._internal(rules, expression, cast);
|
|
|
| + @override
|
| + String get name => 'STRONG_MODE_DOWN_CAST_COMPOSITE';
|
| +
|
| toErrorCode() => new StaticTypeWarningCode(name, message);
|
| }
|
|
|
| @@ -253,23 +197,58 @@ class DownCastImplicit extends DownCast {
|
| DownCastImplicit(TypeRules rules, Expression expression, Cast cast)
|
| : super._internal(rules, expression, cast);
|
|
|
| + @override
|
| + String get name => 'STRONG_MODE_DOWN_CAST_IMPLICIT';
|
| +
|
| toErrorCode() => new HintCode(name, message);
|
| }
|
|
|
| -// An inferred type for the wrapped expression, which may need to be
|
| -// reified into the term
|
| -abstract class InferredTypeBase extends CoercionInfo {
|
| - final DartType _type;
|
| +//
|
| +// Standard down casts. These casts are implicitly injected by the compiler.
|
| +//
|
|
|
| - InferredTypeBase._internal(TypeRules rules, Expression expression, this._type)
|
| +// A down cast from dynamic to T.
|
| +class DynamicCast extends DownCast {
|
| + DynamicCast(TypeRules rules, Expression expression, Cast cast)
|
| + : super._internal(rules, expression, cast);
|
| +
|
| + @override
|
| + String get name => 'STRONG_MODE_DYNAMIC_CAST';
|
| +
|
| + toErrorCode() => new HintCode(name, message);
|
| +}
|
| +
|
| +class DynamicInvoke extends CoercionInfo {
|
| + static const String _propertyName = 'dev_compiler.src.info.DynamicInvoke';
|
| +
|
| + DynamicInvoke(TypeRules rules, Expression expression)
|
| : super(rules, expression);
|
| + DartType get convertedType => rules.provider.dynamicType;
|
| + String get message => '{0} requires dynamic invoke';
|
|
|
| - DartType get type => _type;
|
| - DartType get convertedType => type;
|
| - @override String get message => '{0} has inferred type {1}';
|
| - @override List get arguments => [node, type];
|
| + @override
|
| + String get name => 'STRONG_MODE_DYNAMIC_INVOKE';
|
|
|
| toErrorCode() => new HintCode(name, message);
|
| +
|
| + /// Whether this [node] is the target of a dynamic operation.
|
| + static bool get(AstNode node) {
|
| + var value = node.getProperty(_propertyName);
|
| + return value != null ? value : false;
|
| + }
|
| +
|
| + /// Sets whether this node is the target of a dynamic operation.
|
| + static bool set(AstNode node, bool value) {
|
| + // Free the storage for things that aren't dynamic.
|
| + if (value == false) value = null;
|
| + node.setProperty(_propertyName, value);
|
| + return value;
|
| + }
|
| +}
|
| +
|
| +// The identity coercion
|
| +class Identity extends Coercion {
|
| + Identity(DartType fromType) : super(fromType, fromType);
|
| }
|
|
|
| // Standard / unspecialized inferred type
|
| @@ -277,6 +256,9 @@ class InferredType extends InferredTypeBase {
|
| InferredType(TypeRules rules, Expression expression, DartType type)
|
| : super._internal(rules, expression, type);
|
|
|
| + @override
|
| + String get name => 'STRONG_MODE_INFERRED_TYPE';
|
| +
|
| // Factory to create correct InferredType variant.
|
| static InferredTypeBase create(
|
| TypeRules rules, Expression expression, DartType type) {
|
| @@ -294,110 +276,72 @@ class InferredType extends InferredTypeBase {
|
| }
|
| }
|
|
|
| -// An infered type for a literal expression.
|
| -class InferredTypeLiteral extends InferredTypeBase {
|
| - InferredTypeLiteral(TypeRules rules, Expression expression, DartType type)
|
| - : super._internal(rules, expression, type);
|
| -}
|
| -
|
| // An inferred type for a non-literal allocation site.
|
| class InferredTypeAllocation extends InferredTypeBase {
|
| InferredTypeAllocation(TypeRules rules, Expression expression, DartType type)
|
| : super._internal(rules, expression, type);
|
| -}
|
|
|
| -// An inferred type for a closure expression
|
| -class InferredTypeClosure extends InferredTypeBase {
|
| - InferredTypeClosure(TypeRules rules, Expression expression, DartType type)
|
| - : super._internal(rules, expression, type);
|
| + @override
|
| + String get name => 'STRONG_MODE_INFERRED_TYPE_ALLOCATION';
|
| }
|
|
|
| -class DynamicInvoke extends CoercionInfo {
|
| - DynamicInvoke(TypeRules rules, Expression expression)
|
| - : super(rules, expression);
|
| -
|
| - DartType get convertedType => rules.provider.dynamicType;
|
| - String get message => '{0} requires dynamic invoke';
|
| - toErrorCode() => new HintCode(name, message);
|
| -
|
| - static const String _propertyName = 'dev_compiler.src.info.DynamicInvoke';
|
| -
|
| - /// Whether this [node] is the target of a dynamic operation.
|
| - static bool get(AstNode node) {
|
| - var value = node.getProperty(_propertyName);
|
| - return value != null ? value : false;
|
| - }
|
| -
|
| - /// Sets whether this node is the target of a dynamic operation.
|
| - static bool set(AstNode node, bool value) {
|
| - // Free the storage for things that aren't dynamic.
|
| - if (value == false) value = null;
|
| - node.setProperty(_propertyName, value);
|
| - return value;
|
| - }
|
| -}
|
| -
|
| -abstract class StaticError extends StaticInfo {
|
| - final AstNode node;
|
| +// An inferred type for the wrapped expression, which may need to be
|
| +// reified into the term
|
| +abstract class InferredTypeBase extends CoercionInfo {
|
| + final DartType _type;
|
|
|
| - StaticError(this.node);
|
| + InferredTypeBase._internal(TypeRules rules, Expression expression, this._type)
|
| + : super(rules, expression);
|
|
|
| - String get message;
|
| + @override List get arguments => [node, type];
|
| + DartType get convertedType => type;
|
| + @override String get message => '{0} has inferred type {1}';
|
| + DartType get type => _type;
|
|
|
| - toErrorCode() => new CompileTimeErrorCode(name, message);
|
| + toErrorCode() => new HintCode(name, message);
|
| }
|
|
|
| -class StaticTypeError extends StaticError {
|
| - final DartType baseType;
|
| - final DartType expectedType;
|
| - String reason = null;
|
| -
|
| - StaticTypeError(TypeRules rules, Expression expression, this.expectedType,
|
| - {this.reason})
|
| - : baseType = rules.getStaticType(expression),
|
| - super(expression);
|
| +// An inferred type for a closure expression
|
| +class InferredTypeClosure extends InferredTypeBase {
|
| + InferredTypeClosure(TypeRules rules, Expression expression, DartType type)
|
| + : super._internal(rules, expression, type);
|
|
|
| - @override List<Object> get arguments => [node, baseType, expectedType];
|
| - @override String get message =>
|
| - 'Type check failed: {0} ({1}) is not of type {2}' +
|
| - ((reason == null) ? '' : ' because $reason');
|
| + @override
|
| + String get name => 'STRONG_MODE_INFERRED_TYPE_CLOSURE';
|
| }
|
|
|
| -class InvalidVariableDeclaration extends StaticError {
|
| - final DartType expectedType;
|
| -
|
| - InvalidVariableDeclaration(
|
| - TypeRules rules, AstNode declaration, this.expectedType)
|
| - : super(declaration);
|
| +// An inferred type for a literal expression.
|
| +class InferredTypeLiteral extends InferredTypeBase {
|
| + InferredTypeLiteral(TypeRules rules, Expression expression, DartType type)
|
| + : super._internal(rules, expression, type);
|
|
|
| - @override List<Object> get arguments => [expectedType];
|
| - @override String get message => 'Type check failed: null is not of type {0}';
|
| + @override
|
| + String get name => 'STRONG_MODE_INFERRED_TYPE_LITERAL';
|
| }
|
|
|
| -class InvalidParameterDeclaration extends StaticError {
|
| - final DartType expectedType;
|
| +class InvalidFieldOverride extends InvalidOverride {
|
| + InvalidFieldOverride(AstNode node, ExecutableElement element,
|
| + InterfaceType base, DartType subType, DartType baseType)
|
| + : super(node, element, base, subType, baseType);
|
|
|
| - InvalidParameterDeclaration(
|
| - TypeRules rules, FormalParameter declaration, this.expectedType)
|
| - : super(declaration);
|
| + String get message => 'Field declaration {3}.{1} cannot be '
|
| + 'overridden in {0}.';
|
|
|
| - @override List<Object> get arguments => [node, expectedType];
|
| - @override String get message => 'Type check failed: {0} is not of type {1}';
|
| + @override
|
| + String get name => 'STRONG_MODE_INVALID_FIELD_OVERRIDE';
|
| }
|
|
|
| -class NonGroundTypeCheckInfo extends StaticInfo {
|
| - final DartType type;
|
| - final AstNode node;
|
| -
|
| - NonGroundTypeCheckInfo(this.node, this.type) {
|
| - assert(node is IsExpression || node is AsExpression);
|
| - }
|
| +// Invalid override due to incompatible type. I.e., the overridden signature
|
| +// is not compatible with the original.
|
| +class InvalidMethodOverride extends InvalidOverride {
|
| + InvalidMethodOverride(AstNode node, ExecutableElement element,
|
| + InterfaceType base, FunctionType subType, FunctionType baseType)
|
| + : super(node, element, base, subType, baseType);
|
|
|
| - @override List<Object> get arguments => [type];
|
| - String get message =>
|
| - "Runtime check on non-ground type {0} may throw StrongModeError";
|
| + String get message => _messageHelper('Invalid override');
|
|
|
| - toErrorCode() => new HintCode(name, message);
|
| + @override
|
| + String get name => 'STRONG_MODE_INVALID_METHOD_OVERRIDE';
|
| }
|
|
|
| // Invalid override of an instance member of a class.
|
| @@ -427,11 +371,11 @@ abstract class InvalidOverride extends StaticError {
|
| fromMixin = node.parent is WithClause,
|
| super(node);
|
|
|
| - ClassElement get parent => element.enclosingElement;
|
| -
|
| @override List<Object> get arguments =>
|
| [parent.name, element.name, subType, base, baseType];
|
|
|
| + ClassElement get parent => element.enclosingElement;
|
| +
|
| String _messageHelper(String errorName) {
|
| var lcErrorName = errorName.toLowerCase();
|
| var intro = fromBaseClass
|
| @@ -442,23 +386,17 @@ abstract class InvalidOverride extends StaticError {
|
| }
|
| }
|
|
|
| -// Invalid override due to incompatible type. I.e., the overridden signature
|
| -// is not compatible with the original.
|
| -class InvalidMethodOverride extends InvalidOverride {
|
| - InvalidMethodOverride(AstNode node, ExecutableElement element,
|
| - InterfaceType base, FunctionType subType, FunctionType baseType)
|
| - : super(node, element, base, subType, baseType);
|
| -
|
| - String get message => _messageHelper('Invalid override');
|
| -}
|
| +class InvalidParameterDeclaration extends StaticError {
|
| + final DartType expectedType;
|
|
|
| -class InvalidFieldOverride extends InvalidOverride {
|
| - InvalidFieldOverride(AstNode node, ExecutableElement element,
|
| - InterfaceType base, DartType subType, DartType baseType)
|
| - : super(node, element, base, subType, baseType);
|
| + InvalidParameterDeclaration(
|
| + TypeRules rules, FormalParameter declaration, this.expectedType)
|
| + : super(declaration);
|
|
|
| - String get message => 'Field declaration {3}.{1} cannot be '
|
| - 'overridden in {0}.';
|
| + @override List<Object> get arguments => [node, expectedType];
|
| + @override String get message => 'Type check failed: {0} is not of type {1}';
|
| + @override
|
| + String get name => 'STRONG_MODE_INVALID_PARAMETER_DECLARATION';
|
| }
|
|
|
| /// Dart constructors have one weird quirk, illustrated with this example:
|
| @@ -495,4 +433,114 @@ class InvalidSuperInvocation extends StaticError {
|
|
|
| @override String get message => "super call must be last in an initializer "
|
| "list (see http://goo.gl/q1T4BB): {0}";
|
| +
|
| + @override
|
| + String get name => 'STRONG_MODE_INVALID_SUPER_INVOCATION';
|
| +}
|
| +
|
| +class InvalidVariableDeclaration extends StaticError {
|
| + final DartType expectedType;
|
| +
|
| + InvalidVariableDeclaration(
|
| + TypeRules rules, AstNode declaration, this.expectedType)
|
| + : super(declaration);
|
| +
|
| + @override List<Object> get arguments => [expectedType];
|
| + @override String get message => 'Type check failed: null is not of type {0}';
|
| +
|
| + @override
|
| + String get name => 'STRONG_MODE_INVALID_VARIABLE_DECLARATION';
|
| +}
|
| +
|
| +class NonGroundTypeCheckInfo extends StaticInfo {
|
| + final DartType type;
|
| + final AstNode node;
|
| +
|
| + NonGroundTypeCheckInfo(this.node, this.type) {
|
| + assert(node is IsExpression || node is AsExpression);
|
| + }
|
| +
|
| + @override List<Object> get arguments => [type];
|
| + String get message =>
|
| + "Runtime check on non-ground type {0} may throw StrongModeError";
|
| +
|
| + @override
|
| + String get name => 'STRONG_MODE_NON_GROUND_TYPE_CHECK_INFO';
|
| +
|
| + toErrorCode() => new HintCode(name, message);
|
| +}
|
| +
|
| +abstract class StaticError extends StaticInfo {
|
| + final AstNode node;
|
| +
|
| + StaticError(this.node);
|
| +
|
| + String get message;
|
| +
|
| + toErrorCode() => new CompileTimeErrorCode(name, message);
|
| +}
|
| +
|
| +// TODO(jmesserly): this could use some refactoring. These are essentially
|
| +// like ErrorCodes in analyzer, but we're including some details in our message.
|
| +// Analyzer instead has template strings, and replaces '{0}' with the first
|
| +// argument.
|
| +abstract class StaticInfo {
|
| + List<Object> get arguments => [node];
|
| +
|
| + String get name;
|
| +
|
| + /// AST Node this info is attached to.
|
| + AstNode get node;
|
| +
|
| + AnalysisError toAnalysisError() {
|
| + int begin = node is AnnotatedNode
|
| + ? (node as AnnotatedNode).firstTokenAfterCommentAndMetadata.offset
|
| + : node.offset;
|
| + int length = node.end - begin;
|
| + var source = (node.root as CompilationUnit).element.source;
|
| + return new AnalysisError(source, begin, length, toErrorCode(), arguments);
|
| + }
|
| +
|
| + // TODO(jmesserly): review the usage of error codes. We probably want our own,
|
| + // as well as some DDC specific [ErrorType]s.
|
| + ErrorCode toErrorCode();
|
| +}
|
| +
|
| +class StaticTypeError extends StaticError {
|
| + final DartType baseType;
|
| + final DartType expectedType;
|
| + String reason = null;
|
| +
|
| + StaticTypeError(TypeRules rules, Expression expression, this.expectedType,
|
| + {this.reason})
|
| + : baseType = rules.getStaticType(expression),
|
| + super(expression);
|
| +
|
| + @override List<Object> get arguments => [node, baseType, expectedType];
|
| + @override String get message =>
|
| + 'Type check failed: {0} ({1}) is not of type {2}' +
|
| + ((reason == null) ? '' : ' because $reason');
|
| +
|
| + @override
|
| + String get name => 'STRONG_MODE_STATIC_TYPE_ERROR';
|
| +}
|
| +
|
| +//
|
| +// Temporary "casts" of allocation sites - literals, constructor invocations,
|
| +// and closures. These should be handled by contextual inference. In most
|
| +// cases, inference will be sufficient, though in some it may unmask an actual
|
| +// error: e.g.,
|
| +// List<int> l = [1, 2, 3]; // Inference succeeds
|
| +// List<String> l = [1, 2, 3]; // Inference reveals static type error
|
| +// We're marking all as warnings for now.
|
| +//
|
| +// TODO(vsm,leafp): Remove this.
|
| +class UninferredClosure extends DownCast {
|
| + UninferredClosure(TypeRules rules, FunctionExpression expression, Cast cast)
|
| + : super._internal(rules, expression, cast);
|
| +
|
| + @override
|
| + String get name => 'STRONG_MODE_UNINFERRED_CLOSURE';
|
| +
|
| + toErrorCode() => new StaticTypeWarningCode(name, message);
|
| }
|
|
|