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 ec8626fd7e1ff93e6ffd2d8ff6c85277a6bb167f..5b147e745c7401e30a9db0f1268a0064d4874b49 100644 |
--- a/pkg/analyzer/lib/src/task/strong/info.dart |
+++ b/pkg/analyzer/lib/src/task/strong/info.dart |
@@ -13,34 +13,16 @@ import 'package:analyzer/dart/element/element.dart'; |
import 'package:analyzer/dart/element/type.dart'; |
import 'package:analyzer/src/dart/element/type.dart'; |
import 'package:analyzer/src/generated/error.dart'; |
+import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl; |
import 'package:analyzer/src/generated/type_system.dart'; |
-/// A down cast due to a variable declaration to a ground type: |
-/// |
-/// 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(TypeSystem rules, Expression expression, DartType fromType, |
- DartType toType) |
- : super._internal(rules, expression, fromType, toType); |
- |
- @override |
- String get name => 'STRONG_MODE_ASSIGNMENT_CAST'; |
- |
- toErrorCode() => new HintCode(name, message); |
-} |
- |
/// Implicitly injected expression conversion. |
abstract class CoercionInfo extends StaticInfo { |
static const String _propertyName = 'dev_compiler.src.info.CoercionInfo'; |
- final TypeSystem rules; |
- |
final Expression node; |
- CoercionInfo(this.rules, this.node); |
+ CoercionInfo(this.node); |
DartType get baseType => node.staticType ?? DynamicTypeImpl.instance; |
DartType get convertedType; |
@@ -60,14 +42,15 @@ abstract class CoercionInfo extends StaticInfo { |
} |
} |
-/// Base class for all casts from base type to sub type. |
-abstract class DownCast extends CoercionInfo { |
+/// Implicit casts from base type to sub type. |
+class DownCast extends CoercionInfo { |
final DartType _fromType; |
final DartType _toType; |
+ ErrorCode _errorCode; |
- DownCast._internal( |
- TypeSystem rules, Expression expression, this._fromType, this._toType) |
- : super(rules, expression); |
+ DownCast._( |
+ Expression expression, this._fromType, this._toType, this._errorCode) |
+ : super(expression); |
@override |
List<Object> get arguments => [baseType, convertedType]; |
@@ -79,14 +62,23 @@ abstract class DownCast extends CoercionInfo { |
@override |
DartType get baseType => _fromType; |
+ @override |
DartType get convertedType => _toType; |
@override |
- String get message => 'Unsound implicit cast from {0} to {1}'; |
+ String get message => _message; |
+ |
+ @override |
+ String get name => _errorCode.name; |
+ |
+ @override |
+ toErrorCode() => _errorCode; |
+ |
+ static const String _message = 'Unsound implicit cast from {0} to {1}'; |
/// Factory to create correct DownCast variant. |
static StaticInfo create(StrongTypeSystemImpl rules, Expression expression, |
- DartType fromType, DartType toType) { |
+ DartType fromType, DartType toType, AnalysisOptionsImpl options) { |
// toT <:_R fromT => to <: fromT |
// NB: classes with call methods are subtypes of function |
// types, but the function type is not assignable to the class |
@@ -96,7 +88,7 @@ abstract class DownCast extends CoercionInfo { |
if (expression is Literal || expression is FunctionExpression) { |
// fromT should be an exact type - this will almost certainly fail at |
// runtime. |
- return new StaticTypeError(rules, expression, toType); |
+ return new StaticTypeError(expression, toType); |
} |
if (expression is InstanceCreationExpression) { |
@@ -104,19 +96,20 @@ abstract class DownCast extends CoercionInfo { |
if (e == null || !e.isFactory) { |
// fromT should be an exact type - this will almost certainly fail at |
// runtime. |
- return new StaticTypeError(rules, expression, toType); |
+ return new StaticTypeError(expression, toType); |
} |
} |
if (StaticInfo.isKnownFunction(expression)) { |
- return new StaticTypeError(rules, expression, toType); |
+ return new StaticTypeError(expression, toType); |
} |
// TODO(vsm): Change this to an assert when we have generic methods and |
// fix TypeRules._coerceTo to disallow implicit sideways casts. |
+ bool downCastComposite = false; |
if (!rules.isSubtypeOf(toType, fromType)) { |
assert(toType.isSubtypeOf(fromType) || fromType.isAssignableTo(toType)); |
- return new DownCastComposite(rules, expression, fromType, toType); |
+ downCastComposite = true; |
} |
// Composite cast: these are more likely to fail. |
@@ -128,75 +121,44 @@ abstract class DownCast extends CoercionInfo { |
// Iterable<T> to List<T>. The intuition here is that raw (generic) |
// casts are problematic, and we should complain about those. |
var typeArgs = fromType.typeArguments; |
- if (typeArgs.isEmpty || typeArgs.any((t) => t.isDynamic)) { |
- return new DownCastComposite(rules, expression, fromType, toType); |
- } |
+ downCastComposite = |
+ typeArgs.isEmpty || typeArgs.any((t) => t.isDynamic); |
} else { |
- return new DownCastComposite(rules, expression, fromType, toType); |
+ downCastComposite = true; |
} |
} |
- // Dynamic cast |
- if (fromType.isDynamic) { |
- return new DynamicCast(rules, expression, fromType, toType); |
- } |
- |
- // Assignment cast |
var parent = expression.parent; |
- if (parent is VariableDeclaration && (parent.initializer == expression)) { |
- return new AssignmentCast(rules, expression, fromType, toType); |
+ String name; |
+ if (downCastComposite) { |
+ name = 'STRONG_MODE_DOWN_CAST_COMPOSITE'; |
+ } else if (fromType.isDynamic) { |
+ name = 'STRONG_MODE_DYNAMIC_CAST'; |
+ } else if (parent is VariableDeclaration && |
+ parent.initializer == expression) { |
+ name = 'STRONG_MODE_ASSIGNMENT_CAST'; |
+ } else { |
+ name = 'STRONG_MODE_DOWN_CAST_IMPLICIT'; |
} |
- // Other casts |
- return new DownCastImplicit(rules, expression, fromType, toType); |
+ // For the remaining cases, we allow implicit casts by default. |
+ // However this can be disabled with an option. |
+ ErrorCode errorCode; |
+ if (!options.implicitCasts) { |
+ errorCode = new CompileTimeErrorCode(name, _message); |
+ } else if (downCastComposite) { |
+ errorCode = new StaticWarningCode(name, _message); |
+ } else { |
+ errorCode = new HintCode(name, _message); |
+ } |
+ return new DownCast._(expression, fromType, toType, errorCode); |
} |
} |
-/// 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(TypeSystem rules, Expression expression, DartType fromType, |
- DartType toType) |
- : super._internal(rules, expression, fromType, toType); |
- |
- @override |
- String get name => 'STRONG_MODE_DOWN_CAST_COMPOSITE'; |
- |
- toErrorCode() => new StaticWarningCode(name, message); |
-} |
- |
-/// A down cast to a non-ground type. These behave differently from standard |
-/// Dart and may be more likely to fail at runtime. |
-class DownCastImplicit extends DownCast { |
- DownCastImplicit(TypeSystem rules, Expression expression, DartType fromType, |
- DartType toType) |
- : super._internal(rules, expression, fromType, toType); |
- |
- @override |
- String get name => 'STRONG_MODE_DOWN_CAST_IMPLICIT'; |
- |
- toErrorCode() => new HintCode(name, message); |
-} |
- |
-/// A down cast from dynamic to T. |
-class DynamicCast extends DownCast { |
- DynamicCast(TypeSystem rules, Expression expression, DartType fromType, |
- DartType toType) |
- : super._internal(rules, expression, fromType, toType); |
- |
- @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(TypeSystem rules, Expression expression) |
- : super(rules, expression); |
+ DynamicInvoke(Expression expression) : super(expression); |
DartType get convertedType => DynamicTypeImpl.instance; |
String get message => '{0} requires dynamic invoke'; |
@@ -217,77 +179,43 @@ class DynamicInvoke extends CoercionInfo { |
} |
} |
-/// Standard / unspecialized inferred type. |
-class InferredType extends InferredTypeBase { |
- InferredType(TypeSystem rules, Expression expression, DartType type) |
- : super._internal(rules, expression, type); |
- |
+/// A marker for an inferred type. |
+class InferredType extends CoercionInfo { |
@override |
- String get name => 'STRONG_MODE_INFERRED_TYPE'; |
+ final String name; |
+ |
+ final DartType type; |
+ |
+ InferredType(Expression expression, this.type, this.name) : super(expression); |
/// Factory to create correct InferredType variant. |
- static InferredTypeBase create( |
+ static InferredType create( |
TypeSystem rules, Expression expression, DartType type) { |
// Specialized inference: |
+ String name; |
if (expression is Literal) { |
- return new InferredTypeLiteral(rules, expression, type); |
- } |
- if (expression is InstanceCreationExpression) { |
- return new InferredTypeAllocation(rules, expression, type); |
+ name = 'STRONG_MODE_INFERRED_TYPE_LITERAL'; |
+ } else if (expression is InstanceCreationExpression) { |
+ name = 'STRONG_MODE_INFERRED_TYPE_ALLOCATION'; |
+ } else if (expression is FunctionExpression) { |
+ name = 'STRONG_MODE_INFERRED_TYPE_CLOSURE'; |
+ } else { |
+ name = 'STRONG_MODE_INFERRED_TYPE'; |
} |
- if (expression is FunctionExpression) { |
- return new InferredTypeClosure(rules, expression, type); |
- } |
- return new InferredType(rules, expression, type); |
+ return new InferredType(expression, type, name); |
} |
-} |
- |
-/// An inferred type for a non-literal allocation site. |
-class InferredTypeAllocation extends InferredTypeBase { |
- InferredTypeAllocation(TypeSystem rules, Expression expression, DartType type) |
- : super._internal(rules, expression, type); |
- |
- @override |
- String get name => 'STRONG_MODE_INFERRED_TYPE_ALLOCATION'; |
-} |
- |
-/// An inferred type for the wrapped expression, which may need to be |
-/// reified into the term. |
-abstract class InferredTypeBase extends CoercionInfo { |
- final DartType _type; |
- |
- InferredTypeBase._internal( |
- TypeSystem rules, Expression expression, this._type) |
- : super(rules, expression); |
@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 HintCode(name, message); |
} |
-/// An inferred type for a closure expression. |
-class InferredTypeClosure extends InferredTypeBase { |
- InferredTypeClosure(TypeSystem rules, Expression expression, DartType type) |
- : super._internal(rules, expression, type); |
- |
- @override |
- String get name => 'STRONG_MODE_INFERRED_TYPE_CLOSURE'; |
-} |
- |
-/// An inferred type for a literal expression. |
-class InferredTypeLiteral extends InferredTypeBase { |
- InferredTypeLiteral(TypeSystem rules, Expression expression, DartType type) |
- : super._internal(rules, expression, type); |
- |
- @override |
- String get name => 'STRONG_MODE_INFERRED_TYPE_LITERAL'; |
-} |
- |
class InvalidFieldOverride extends InvalidOverride { |
InvalidFieldOverride(AstNode node, ExecutableElement element, |
InterfaceType base, DartType subType, DartType baseType) |
@@ -484,7 +412,6 @@ abstract class StaticInfo { |
'STRONG_MODE_INVALID_VARIABLE_DECLARATION', |
'STRONG_MODE_NON_GROUND_TYPE_CHECK_INFO', |
'STRONG_MODE_STATIC_TYPE_ERROR', |
- 'STRONG_MODE_UNINFERRED_CLOSURE', |
]; |
List<Object> get arguments => [node]; |
@@ -527,7 +454,7 @@ class StaticTypeError extends StaticError { |
final DartType baseType; |
final DartType expectedType; |
- StaticTypeError(TypeSystem rules, Expression expression, this.expectedType) |
+ StaticTypeError(Expression expression, this.expectedType) |
: baseType = expression.staticType ?? DynamicTypeImpl.instance, |
super(expression); |