Chromium Code Reviews| 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. |
|
Leaf
2015/12/04 23:58:43
this comment should go away, it only makes sense i
|
| +// |
| - 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); |
| } |