| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /// Defines static information collected by the type checker and used later by | 5 /// Defines static information collected by the type checker and used later by |
| 6 /// emitters to generate code. | 6 /// emitters to generate code. |
| 7 // TODO(jmesserly): this was ported from package:dev_compiler, and needs to be | 7 // TODO(jmesserly): this was ported from package:dev_compiler, and needs to be |
| 8 // refactored to fit into analyzer. | 8 // refactored to fit into analyzer. |
| 9 library analyzer.src.task.strong.info; | 9 library analyzer.src.task.strong.info; |
| 10 | 10 |
| 11 import 'package:analyzer/src/generated/ast.dart'; | 11 import 'package:analyzer/src/generated/ast.dart'; |
| 12 import 'package:analyzer/src/generated/element.dart'; | 12 import 'package:analyzer/src/generated/element.dart'; |
| 13 import 'package:analyzer/src/generated/error.dart'; | 13 import 'package:analyzer/src/generated/error.dart'; |
| 14 | 14 |
| 15 import 'rules.dart'; | 15 import 'rules.dart'; |
| 16 | 16 |
| 17 // A down cast due to a variable declaration to a ground type. E.g., |
| 18 // T x = expr; |
| 19 // where T is ground. We exclude non-ground types as these behave differently |
| 20 // compared to standard Dart. |
| 21 class AssignmentCast extends DownCast { |
| 22 AssignmentCast(TypeRules rules, Expression expression, Cast cast) |
| 23 : super._internal(rules, expression, cast); |
| 24 |
| 25 @override |
| 26 String get name => 'STRONG_MODE_ASSIGNMENT_CAST'; |
| 27 |
| 28 toErrorCode() => new HintCode(name, message); |
| 29 } |
| 30 |
| 31 // Coercion which casts one type to another |
| 32 class Cast extends Coercion { |
| 33 Cast(DartType fromType, DartType toType) : super(fromType, toType); |
| 34 } |
| 35 |
| 17 // The abstract type of coercions mapping one type to another. | 36 // The abstract type of coercions mapping one type to another. |
| 18 // This class also exposes static builder functions which | 37 // This class also exposes static builder functions which |
| 19 // check for errors and reduce redundant coercions to the identity. | 38 // check for errors and reduce redundant coercions to the identity. |
| 20 abstract class Coercion { | 39 abstract class Coercion { |
| 21 final DartType fromType; | 40 final DartType fromType; |
| 22 final DartType toType; | 41 final DartType toType; |
| 23 Coercion(this.fromType, this.toType); | 42 Coercion(this.fromType, this.toType); |
| 24 static Coercion cast(DartType fromT, DartType toT) => new Cast(fromT, toT); | 43 static Coercion cast(DartType fromT, DartType toT) => new Cast(fromT, toT); |
| 44 static Coercion error() => new CoercionError(); |
| 25 static Coercion identity(DartType type) => new Identity(type); | 45 static Coercion identity(DartType type) => new Identity(type); |
| 26 static Coercion error() => new CoercionError(); | |
| 27 } | |
| 28 | |
| 29 // Coercion which casts one type to another | |
| 30 class Cast extends Coercion { | |
| 31 Cast(DartType fromType, DartType toType) : super(fromType, toType); | |
| 32 } | |
| 33 | |
| 34 // The identity coercion | |
| 35 class Identity extends Coercion { | |
| 36 Identity(DartType fromType) : super(fromType, fromType); | |
| 37 } | 46 } |
| 38 | 47 |
| 39 // The error coercion. This coercion signals that a coercion | 48 // The error coercion. This coercion signals that a coercion |
| 40 // could not be generated. The code generator should not see | 49 // could not be generated. The code generator should not see |
| 41 // these. | 50 // these. |
| 42 class CoercionError extends Coercion { | 51 class CoercionError extends Coercion { |
| 43 CoercionError() : super(null, null); | 52 CoercionError() : super(null, null); |
| 44 } | 53 } |
| 45 | 54 |
| 46 // TODO(jmesserly): this could use some refactoring. These are essentially | |
| 47 // like ErrorCodes in analyzer, but we're including some details in our message. | |
| 48 // Analyzer instead has template strings, and replaces '{0}' with the first | |
| 49 // argument. | |
| 50 abstract class StaticInfo { | |
| 51 /// AST Node this info is attached to. | |
| 52 AstNode get node; | |
| 53 | |
| 54 // TODO(jmesserly): review the usage of error codes. We probably want our own, | |
| 55 // as well as some DDC specific [ErrorType]s. | |
| 56 ErrorCode toErrorCode(); | |
| 57 | |
| 58 // TODO(jmesserly): what convention to use here? | |
| 59 String get name => 'dev_compiler.$runtimeType'; | |
| 60 | |
| 61 List<Object> get arguments => [node]; | |
| 62 | |
| 63 AnalysisError toAnalysisError() { | |
| 64 int begin = node is AnnotatedNode | |
| 65 ? (node as AnnotatedNode).firstTokenAfterCommentAndMetadata.offset | |
| 66 : node.offset; | |
| 67 int length = node.end - begin; | |
| 68 var source = (node.root as CompilationUnit).element.source; | |
| 69 return new AnalysisError(source, begin, length, toErrorCode(), arguments); | |
| 70 } | |
| 71 } | |
| 72 | |
| 73 /// Implicitly injected expression conversion. | 55 /// Implicitly injected expression conversion. |
| 74 abstract class CoercionInfo extends StaticInfo { | 56 abstract class CoercionInfo extends StaticInfo { |
| 57 static const String _propertyName = 'dev_compiler.src.info.CoercionInfo'; |
| 58 |
| 75 final TypeRules rules; | 59 final TypeRules rules; |
| 76 | 60 |
| 77 final Expression node; | 61 final Expression node; |
| 78 | 62 |
| 79 DartType get convertedType; | |
| 80 | |
| 81 CoercionInfo(this.rules, this.node); | 63 CoercionInfo(this.rules, this.node); |
| 82 | 64 |
| 83 DartType get baseType => rules.getStaticType(node); | 65 DartType get baseType => rules.getStaticType(node); |
| 66 DartType get convertedType; |
| 67 |
| 68 String get message; |
| 84 DartType get staticType => convertedType; | 69 DartType get staticType => convertedType; |
| 85 | 70 |
| 86 String get message; | |
| 87 toErrorCode() => new HintCode(name, message); | 71 toErrorCode() => new HintCode(name, message); |
| 88 | 72 |
| 89 static const String _propertyName = 'dev_compiler.src.info.CoercionInfo'; | |
| 90 | |
| 91 /// Gets the coercion info associated with this node. | 73 /// Gets the coercion info associated with this node. |
| 92 static CoercionInfo get(AstNode node) => node.getProperty(_propertyName); | 74 static CoercionInfo get(AstNode node) => node.getProperty(_propertyName); |
| 93 | 75 |
| 94 /// Sets the coercion info associated with this node. | 76 /// Sets the coercion info associated with this node. |
| 95 static CoercionInfo set(AstNode node, CoercionInfo info) { | 77 static CoercionInfo set(AstNode node, CoercionInfo info) { |
| 96 node.setProperty(_propertyName, info); | 78 node.setProperty(_propertyName, info); |
| 97 return info; | 79 return info; |
| 98 } | 80 } |
| 99 } | 81 } |
| 100 | 82 |
| 101 // Base class for all casts from base type to sub type. | 83 // Base class for all casts from base type to sub type. |
| 102 abstract class DownCast extends CoercionInfo { | 84 abstract class DownCast extends CoercionInfo { |
| 103 Cast _cast; | 85 Cast _cast; |
| 104 | 86 |
| 105 DownCast._internal(TypeRules rules, Expression expression, this._cast) | 87 DownCast._internal(TypeRules rules, Expression expression, this._cast) |
| 106 : super(rules, expression) { | 88 : super(rules, expression) { |
| 107 assert(_cast.toType != baseType && | 89 assert(_cast.toType != baseType && |
| 108 _cast.fromType == baseType && | 90 _cast.fromType == baseType && |
| 109 (baseType.isDynamic || | 91 (baseType.isDynamic || |
| 110 // Call methods make the following non-redundant | 92 // Call methods make the following non-redundant |
| 111 _cast.toType.isSubtypeOf(baseType) || | 93 _cast.toType.isSubtypeOf(baseType) || |
| 112 baseType.isAssignableTo(_cast.toType))); | 94 baseType.isAssignableTo(_cast.toType))); |
| 113 } | 95 } |
| 114 | 96 |
| 97 @override List<Object> get arguments => [node, baseType, convertedType]; |
| 98 |
| 115 Cast get cast => _cast; | 99 Cast get cast => _cast; |
| 116 | 100 |
| 117 DartType get convertedType => _cast.toType; | 101 DartType get convertedType => _cast.toType; |
| 118 | |
| 119 @override List<Object> get arguments => [node, baseType, convertedType]; | |
| 120 @override String get message => '{0} ({1}) will need runtime check ' | 102 @override String get message => '{0} ({1}) will need runtime check ' |
| 121 'to cast to type {2}'; | 103 'to cast to type {2}'; |
| 122 | 104 |
| 123 // Factory to create correct DownCast variant. | 105 // Factory to create correct DownCast variant. |
| 124 static StaticInfo create(TypeRules rules, Expression expression, Cast cast, | 106 static StaticInfo create(TypeRules rules, Expression expression, Cast cast, |
| 125 {String reason}) { | 107 {String reason}) { |
| 126 final fromT = cast.fromType; | 108 final fromT = cast.fromType; |
| 127 final toT = cast.toType; | 109 final toT = cast.toType; |
| 128 | 110 |
| 129 // toT <:_R fromT => to <: fromT | 111 // toT <:_R fromT => to <: fromT |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 188 if (parent is VariableDeclaration && (parent.initializer == expression)) { | 170 if (parent is VariableDeclaration && (parent.initializer == expression)) { |
| 189 return new AssignmentCast(rules, expression, cast); | 171 return new AssignmentCast(rules, expression, cast); |
| 190 } | 172 } |
| 191 | 173 |
| 192 // Other casts | 174 // Other casts |
| 193 return new DownCastImplicit(rules, expression, cast); | 175 return new DownCastImplicit(rules, expression, cast); |
| 194 } | 176 } |
| 195 } | 177 } |
| 196 | 178 |
| 197 // | 179 // |
| 198 // Standard down casts. These casts are implicitly injected by the compiler. | |
| 199 // | |
| 200 | |
| 201 // A down cast from dynamic to T. | |
| 202 class DynamicCast extends DownCast { | |
| 203 DynamicCast(TypeRules rules, Expression expression, Cast cast) | |
| 204 : super._internal(rules, expression, cast); | |
| 205 | |
| 206 toErrorCode() => new HintCode(name, message); | |
| 207 } | |
| 208 | |
| 209 // A down cast due to a variable declaration to a ground type. E.g., | |
| 210 // T x = expr; | |
| 211 // where T is ground. We exclude non-ground types as these behave differently | |
| 212 // compared to standard Dart. | |
| 213 class AssignmentCast extends DownCast { | |
| 214 AssignmentCast(TypeRules rules, Expression expression, Cast cast) | |
| 215 : super._internal(rules, expression, cast); | |
| 216 | |
| 217 toErrorCode() => new HintCode(name, message); | |
| 218 } | |
| 219 | |
| 220 // | |
| 221 // Temporary "casts" of allocation sites - literals, constructor invocations, | |
| 222 // and closures. These should be handled by contextual inference. In most | |
| 223 // cases, inference will be sufficient, though in some it may unmask an actual | |
| 224 // error: e.g., | |
| 225 // List<int> l = [1, 2, 3]; // Inference succeeds | |
| 226 // List<String> l = [1, 2, 3]; // Inference reveals static type error | |
| 227 // We're marking all as warnings for now. | |
| 228 // | |
| 229 // TODO(vsm,leafp): Remove this. | |
| 230 class UninferredClosure extends DownCast { | |
| 231 UninferredClosure(TypeRules rules, FunctionExpression expression, Cast cast) | |
| 232 : super._internal(rules, expression, cast); | |
| 233 | |
| 234 toErrorCode() => new StaticTypeWarningCode(name, message); | |
| 235 } | |
| 236 | |
| 237 // | |
| 238 // Implicit down casts. These are only injected by the compiler by flag. | 180 // Implicit down casts. These are only injected by the compiler by flag. |
| 239 // | 181 // |
| 240 | |
| 241 // A down cast to a non-ground type. These behave differently from standard | 182 // A down cast to a non-ground type. These behave differently from standard |
| 242 // Dart and may be more likely to fail at runtime. | 183 // Dart and may be more likely to fail at runtime. |
| 243 class DownCastComposite extends DownCast { | 184 class DownCastComposite extends DownCast { |
| 244 DownCastComposite(TypeRules rules, Expression expression, Cast cast) | 185 DownCastComposite(TypeRules rules, Expression expression, Cast cast) |
| 245 : super._internal(rules, expression, cast); | 186 : super._internal(rules, expression, cast); |
| 246 | 187 |
| 188 @override |
| 189 String get name => 'STRONG_MODE_DOWN_CAST_COMPOSITE'; |
| 190 |
| 247 toErrorCode() => new StaticTypeWarningCode(name, message); | 191 toErrorCode() => new StaticTypeWarningCode(name, message); |
| 248 } | 192 } |
| 249 | 193 |
| 250 // A down cast to a non-ground type. These behave differently from standard | 194 // A down cast to a non-ground type. These behave differently from standard |
| 251 // Dart and may be more likely to fail at runtime. | 195 // Dart and may be more likely to fail at runtime. |
| 252 class DownCastImplicit extends DownCast { | 196 class DownCastImplicit extends DownCast { |
| 253 DownCastImplicit(TypeRules rules, Expression expression, Cast cast) | 197 DownCastImplicit(TypeRules rules, Expression expression, Cast cast) |
| 254 : super._internal(rules, expression, cast); | 198 : super._internal(rules, expression, cast); |
| 255 | 199 |
| 200 @override |
| 201 String get name => 'STRONG_MODE_DOWN_CAST_IMPLICIT'; |
| 202 |
| 256 toErrorCode() => new HintCode(name, message); | 203 toErrorCode() => new HintCode(name, message); |
| 257 } | 204 } |
| 258 | 205 |
| 259 // An inferred type for the wrapped expression, which may need to be | 206 // |
| 260 // reified into the term | 207 // Standard down casts. These casts are implicitly injected by the compiler. |
| 261 abstract class InferredTypeBase extends CoercionInfo { | 208 // |
| 262 final DartType _type; | |
| 263 | 209 |
| 264 InferredTypeBase._internal(TypeRules rules, Expression expression, this._type) | 210 // A down cast from dynamic to T. |
| 265 : super(rules, expression); | 211 class DynamicCast extends DownCast { |
| 212 DynamicCast(TypeRules rules, Expression expression, Cast cast) |
| 213 : super._internal(rules, expression, cast); |
| 266 | 214 |
| 267 DartType get type => _type; | 215 @override |
| 268 DartType get convertedType => type; | 216 String get name => 'STRONG_MODE_DYNAMIC_CAST'; |
| 269 @override String get message => '{0} has inferred type {1}'; | |
| 270 @override List get arguments => [node, type]; | |
| 271 | 217 |
| 272 toErrorCode() => new HintCode(name, message); | 218 toErrorCode() => new HintCode(name, message); |
| 273 } | 219 } |
| 274 | 220 |
| 221 class DynamicInvoke extends CoercionInfo { |
| 222 static const String _propertyName = 'dev_compiler.src.info.DynamicInvoke'; |
| 223 |
| 224 DynamicInvoke(TypeRules rules, Expression expression) |
| 225 : super(rules, expression); |
| 226 DartType get convertedType => rules.provider.dynamicType; |
| 227 String get message => '{0} requires dynamic invoke'; |
| 228 |
| 229 @override |
| 230 String get name => 'STRONG_MODE_DYNAMIC_INVOKE'; |
| 231 |
| 232 toErrorCode() => new HintCode(name, message); |
| 233 |
| 234 /// Whether this [node] is the target of a dynamic operation. |
| 235 static bool get(AstNode node) { |
| 236 var value = node.getProperty(_propertyName); |
| 237 return value != null ? value : false; |
| 238 } |
| 239 |
| 240 /// Sets whether this node is the target of a dynamic operation. |
| 241 static bool set(AstNode node, bool value) { |
| 242 // Free the storage for things that aren't dynamic. |
| 243 if (value == false) value = null; |
| 244 node.setProperty(_propertyName, value); |
| 245 return value; |
| 246 } |
| 247 } |
| 248 |
| 249 // The identity coercion |
| 250 class Identity extends Coercion { |
| 251 Identity(DartType fromType) : super(fromType, fromType); |
| 252 } |
| 253 |
| 275 // Standard / unspecialized inferred type | 254 // Standard / unspecialized inferred type |
| 276 class InferredType extends InferredTypeBase { | 255 class InferredType extends InferredTypeBase { |
| 277 InferredType(TypeRules rules, Expression expression, DartType type) | 256 InferredType(TypeRules rules, Expression expression, DartType type) |
| 278 : super._internal(rules, expression, type); | 257 : super._internal(rules, expression, type); |
| 279 | 258 |
| 259 @override |
| 260 String get name => 'STRONG_MODE_INFERRED_TYPE'; |
| 261 |
| 280 // Factory to create correct InferredType variant. | 262 // Factory to create correct InferredType variant. |
| 281 static InferredTypeBase create( | 263 static InferredTypeBase create( |
| 282 TypeRules rules, Expression expression, DartType type) { | 264 TypeRules rules, Expression expression, DartType type) { |
| 283 // Specialized inference: | 265 // Specialized inference: |
| 284 if (expression is Literal) { | 266 if (expression is Literal) { |
| 285 return new InferredTypeLiteral(rules, expression, type); | 267 return new InferredTypeLiteral(rules, expression, type); |
| 286 } | 268 } |
| 287 if (expression is InstanceCreationExpression) { | 269 if (expression is InstanceCreationExpression) { |
| 288 return new InferredTypeAllocation(rules, expression, type); | 270 return new InferredTypeAllocation(rules, expression, type); |
| 289 } | 271 } |
| 290 if (expression is FunctionExpression) { | 272 if (expression is FunctionExpression) { |
| 291 return new InferredTypeClosure(rules, expression, type); | 273 return new InferredTypeClosure(rules, expression, type); |
| 292 } | 274 } |
| 293 return new InferredType(rules, expression, type); | 275 return new InferredType(rules, expression, type); |
| 294 } | 276 } |
| 295 } | 277 } |
| 296 | 278 |
| 297 // An infered type for a literal expression. | |
| 298 class InferredTypeLiteral extends InferredTypeBase { | |
| 299 InferredTypeLiteral(TypeRules rules, Expression expression, DartType type) | |
| 300 : super._internal(rules, expression, type); | |
| 301 } | |
| 302 | |
| 303 // An inferred type for a non-literal allocation site. | 279 // An inferred type for a non-literal allocation site. |
| 304 class InferredTypeAllocation extends InferredTypeBase { | 280 class InferredTypeAllocation extends InferredTypeBase { |
| 305 InferredTypeAllocation(TypeRules rules, Expression expression, DartType type) | 281 InferredTypeAllocation(TypeRules rules, Expression expression, DartType type) |
| 306 : super._internal(rules, expression, type); | 282 : super._internal(rules, expression, type); |
| 283 |
| 284 @override |
| 285 String get name => 'STRONG_MODE_INFERRED_TYPE_ALLOCATION'; |
| 286 } |
| 287 |
| 288 // An inferred type for the wrapped expression, which may need to be |
| 289 // reified into the term |
| 290 abstract class InferredTypeBase extends CoercionInfo { |
| 291 final DartType _type; |
| 292 |
| 293 InferredTypeBase._internal(TypeRules rules, Expression expression, this._type) |
| 294 : super(rules, expression); |
| 295 |
| 296 @override List get arguments => [node, type]; |
| 297 DartType get convertedType => type; |
| 298 @override String get message => '{0} has inferred type {1}'; |
| 299 DartType get type => _type; |
| 300 |
| 301 toErrorCode() => new HintCode(name, message); |
| 307 } | 302 } |
| 308 | 303 |
| 309 // An inferred type for a closure expression | 304 // An inferred type for a closure expression |
| 310 class InferredTypeClosure extends InferredTypeBase { | 305 class InferredTypeClosure extends InferredTypeBase { |
| 311 InferredTypeClosure(TypeRules rules, Expression expression, DartType type) | 306 InferredTypeClosure(TypeRules rules, Expression expression, DartType type) |
| 312 : super._internal(rules, expression, type); | 307 : super._internal(rules, expression, type); |
| 308 |
| 309 @override |
| 310 String get name => 'STRONG_MODE_INFERRED_TYPE_CLOSURE'; |
| 313 } | 311 } |
| 314 | 312 |
| 315 class DynamicInvoke extends CoercionInfo { | 313 // An inferred type for a literal expression. |
| 316 DynamicInvoke(TypeRules rules, Expression expression) | 314 class InferredTypeLiteral extends InferredTypeBase { |
| 317 : super(rules, expression); | 315 InferredTypeLiteral(TypeRules rules, Expression expression, DartType type) |
| 316 : super._internal(rules, expression, type); |
| 318 | 317 |
| 319 DartType get convertedType => rules.provider.dynamicType; | 318 @override |
| 320 String get message => '{0} requires dynamic invoke'; | 319 String get name => 'STRONG_MODE_INFERRED_TYPE_LITERAL'; |
| 321 toErrorCode() => new HintCode(name, message); | |
| 322 | |
| 323 static const String _propertyName = 'dev_compiler.src.info.DynamicInvoke'; | |
| 324 | |
| 325 /// Whether this [node] is the target of a dynamic operation. | |
| 326 static bool get(AstNode node) { | |
| 327 var value = node.getProperty(_propertyName); | |
| 328 return value != null ? value : false; | |
| 329 } | |
| 330 | |
| 331 /// Sets whether this node is the target of a dynamic operation. | |
| 332 static bool set(AstNode node, bool value) { | |
| 333 // Free the storage for things that aren't dynamic. | |
| 334 if (value == false) value = null; | |
| 335 node.setProperty(_propertyName, value); | |
| 336 return value; | |
| 337 } | |
| 338 } | 320 } |
| 339 | 321 |
| 340 abstract class StaticError extends StaticInfo { | 322 class InvalidFieldOverride extends InvalidOverride { |
| 341 final AstNode node; | 323 InvalidFieldOverride(AstNode node, ExecutableElement element, |
| 324 InterfaceType base, DartType subType, DartType baseType) |
| 325 : super(node, element, base, subType, baseType); |
| 342 | 326 |
| 343 StaticError(this.node); | 327 String get message => 'Field declaration {3}.{1} cannot be ' |
| 328 'overridden in {0}.'; |
| 344 | 329 |
| 345 String get message; | 330 @override |
| 346 | 331 String get name => 'STRONG_MODE_INVALID_FIELD_OVERRIDE'; |
| 347 toErrorCode() => new CompileTimeErrorCode(name, message); | |
| 348 } | 332 } |
| 349 | 333 |
| 350 class StaticTypeError extends StaticError { | 334 // Invalid override due to incompatible type. I.e., the overridden signature |
| 351 final DartType baseType; | 335 // is not compatible with the original. |
| 352 final DartType expectedType; | 336 class InvalidMethodOverride extends InvalidOverride { |
| 353 String reason = null; | 337 InvalidMethodOverride(AstNode node, ExecutableElement element, |
| 338 InterfaceType base, FunctionType subType, FunctionType baseType) |
| 339 : super(node, element, base, subType, baseType); |
| 354 | 340 |
| 355 StaticTypeError(TypeRules rules, Expression expression, this.expectedType, | 341 String get message => _messageHelper('Invalid override'); |
| 356 {this.reason}) | |
| 357 : baseType = rules.getStaticType(expression), | |
| 358 super(expression); | |
| 359 | 342 |
| 360 @override List<Object> get arguments => [node, baseType, expectedType]; | 343 @override |
| 361 @override String get message => | 344 String get name => 'STRONG_MODE_INVALID_METHOD_OVERRIDE'; |
| 362 'Type check failed: {0} ({1}) is not of type {2}' + | |
| 363 ((reason == null) ? '' : ' because $reason'); | |
| 364 } | |
| 365 | |
| 366 class InvalidVariableDeclaration extends StaticError { | |
| 367 final DartType expectedType; | |
| 368 | |
| 369 InvalidVariableDeclaration( | |
| 370 TypeRules rules, AstNode declaration, this.expectedType) | |
| 371 : super(declaration); | |
| 372 | |
| 373 @override List<Object> get arguments => [expectedType]; | |
| 374 @override String get message => 'Type check failed: null is not of type {0}'; | |
| 375 } | |
| 376 | |
| 377 class InvalidParameterDeclaration extends StaticError { | |
| 378 final DartType expectedType; | |
| 379 | |
| 380 InvalidParameterDeclaration( | |
| 381 TypeRules rules, FormalParameter declaration, this.expectedType) | |
| 382 : super(declaration); | |
| 383 | |
| 384 @override List<Object> get arguments => [node, expectedType]; | |
| 385 @override String get message => 'Type check failed: {0} is not of type {1}'; | |
| 386 } | |
| 387 | |
| 388 class NonGroundTypeCheckInfo extends StaticInfo { | |
| 389 final DartType type; | |
| 390 final AstNode node; | |
| 391 | |
| 392 NonGroundTypeCheckInfo(this.node, this.type) { | |
| 393 assert(node is IsExpression || node is AsExpression); | |
| 394 } | |
| 395 | |
| 396 @override List<Object> get arguments => [type]; | |
| 397 String get message => | |
| 398 "Runtime check on non-ground type {0} may throw StrongModeError"; | |
| 399 | |
| 400 toErrorCode() => new HintCode(name, message); | |
| 401 } | 345 } |
| 402 | 346 |
| 403 // Invalid override of an instance member of a class. | 347 // Invalid override of an instance member of a class. |
| 404 abstract class InvalidOverride extends StaticError { | 348 abstract class InvalidOverride extends StaticError { |
| 405 /// Member declaration with the invalid override. | 349 /// Member declaration with the invalid override. |
| 406 final ExecutableElement element; | 350 final ExecutableElement element; |
| 407 | 351 |
| 408 /// Type (class or interface) that provides the base declaration. | 352 /// Type (class or interface) that provides the base declaration. |
| 409 final InterfaceType base; | 353 final InterfaceType base; |
| 410 | 354 |
| 411 /// Actual type of the overridden member. | 355 /// Actual type of the overridden member. |
| 412 final DartType subType; | 356 final DartType subType; |
| 413 | 357 |
| 414 /// Actual type of the base member. | 358 /// Actual type of the base member. |
| 415 final DartType baseType; | 359 final DartType baseType; |
| 416 | 360 |
| 417 /// Whether the error comes from combining a base class and an interface | 361 /// Whether the error comes from combining a base class and an interface |
| 418 final bool fromBaseClass; | 362 final bool fromBaseClass; |
| 419 | 363 |
| 420 /// Whether the error comes from a mixin (either overriding a base class or an | 364 /// Whether the error comes from a mixin (either overriding a base class or an |
| 421 /// interface declaration). | 365 /// interface declaration). |
| 422 final bool fromMixin; | 366 final bool fromMixin; |
| 423 | 367 |
| 424 InvalidOverride( | 368 InvalidOverride( |
| 425 AstNode node, this.element, this.base, this.subType, this.baseType) | 369 AstNode node, this.element, this.base, this.subType, this.baseType) |
| 426 : fromBaseClass = node is ExtendsClause, | 370 : fromBaseClass = node is ExtendsClause, |
| 427 fromMixin = node.parent is WithClause, | 371 fromMixin = node.parent is WithClause, |
| 428 super(node); | 372 super(node); |
| 429 | 373 |
| 430 ClassElement get parent => element.enclosingElement; | |
| 431 | |
| 432 @override List<Object> get arguments => | 374 @override List<Object> get arguments => |
| 433 [parent.name, element.name, subType, base, baseType]; | 375 [parent.name, element.name, subType, base, baseType]; |
| 434 | 376 |
| 377 ClassElement get parent => element.enclosingElement; |
| 378 |
| 435 String _messageHelper(String errorName) { | 379 String _messageHelper(String errorName) { |
| 436 var lcErrorName = errorName.toLowerCase(); | 380 var lcErrorName = errorName.toLowerCase(); |
| 437 var intro = fromBaseClass | 381 var intro = fromBaseClass |
| 438 ? 'Base class introduces an $lcErrorName' | 382 ? 'Base class introduces an $lcErrorName' |
| 439 : (fromMixin ? 'Mixin introduces an $lcErrorName' : errorName); | 383 : (fromMixin ? 'Mixin introduces an $lcErrorName' : errorName); |
| 440 return '$intro. The type of {0}.{1} ({2}) is not a ' | 384 return '$intro. The type of {0}.{1} ({2}) is not a ' |
| 441 'subtype of {3}.{1} ({4}).'; | 385 'subtype of {3}.{1} ({4}).'; |
| 442 } | 386 } |
| 443 } | 387 } |
| 444 | 388 |
| 445 // Invalid override due to incompatible type. I.e., the overridden signature | 389 class InvalidParameterDeclaration extends StaticError { |
| 446 // is not compatible with the original. | 390 final DartType expectedType; |
| 447 class InvalidMethodOverride extends InvalidOverride { | |
| 448 InvalidMethodOverride(AstNode node, ExecutableElement element, | |
| 449 InterfaceType base, FunctionType subType, FunctionType baseType) | |
| 450 : super(node, element, base, subType, baseType); | |
| 451 | 391 |
| 452 String get message => _messageHelper('Invalid override'); | 392 InvalidParameterDeclaration( |
| 453 } | 393 TypeRules rules, FormalParameter declaration, this.expectedType) |
| 394 : super(declaration); |
| 454 | 395 |
| 455 class InvalidFieldOverride extends InvalidOverride { | 396 @override List<Object> get arguments => [node, expectedType]; |
| 456 InvalidFieldOverride(AstNode node, ExecutableElement element, | 397 @override String get message => 'Type check failed: {0} is not of type {1}'; |
| 457 InterfaceType base, DartType subType, DartType baseType) | 398 @override |
| 458 : super(node, element, base, subType, baseType); | 399 String get name => 'STRONG_MODE_INVALID_PARAMETER_DECLARATION'; |
| 459 | |
| 460 String get message => 'Field declaration {3}.{1} cannot be ' | |
| 461 'overridden in {0}.'; | |
| 462 } | 400 } |
| 463 | 401 |
| 464 /// Dart constructors have one weird quirk, illustrated with this example: | 402 /// Dart constructors have one weird quirk, illustrated with this example: |
| 465 /// | 403 /// |
| 466 /// class Base { | 404 /// class Base { |
| 467 /// var x; | 405 /// var x; |
| 468 /// Base() : x = print('Base.1') { | 406 /// Base() : x = print('Base.1') { |
| 469 /// print('Base.2'); | 407 /// print('Base.2'); |
| 470 /// } | 408 /// } |
| 471 /// } | 409 /// } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 488 /// | 426 /// |
| 489 /// Better to have `super` at the end, as required by the Dart style guide: | 427 /// Better to have `super` at the end, as required by the Dart style guide: |
| 490 /// <http://goo.gl/q1T4BB> | 428 /// <http://goo.gl/q1T4BB> |
| 491 /// | 429 /// |
| 492 /// For now this is the only pattern we support. | 430 /// For now this is the only pattern we support. |
| 493 class InvalidSuperInvocation extends StaticError { | 431 class InvalidSuperInvocation extends StaticError { |
| 494 InvalidSuperInvocation(SuperConstructorInvocation node) : super(node); | 432 InvalidSuperInvocation(SuperConstructorInvocation node) : super(node); |
| 495 | 433 |
| 496 @override String get message => "super call must be last in an initializer " | 434 @override String get message => "super call must be last in an initializer " |
| 497 "list (see http://goo.gl/q1T4BB): {0}"; | 435 "list (see http://goo.gl/q1T4BB): {0}"; |
| 436 |
| 437 @override |
| 438 String get name => 'STRONG_MODE_INVALID_SUPER_INVOCATION'; |
| 498 } | 439 } |
| 440 |
| 441 class InvalidVariableDeclaration extends StaticError { |
| 442 final DartType expectedType; |
| 443 |
| 444 InvalidVariableDeclaration( |
| 445 TypeRules rules, AstNode declaration, this.expectedType) |
| 446 : super(declaration); |
| 447 |
| 448 @override List<Object> get arguments => [expectedType]; |
| 449 @override String get message => 'Type check failed: null is not of type {0}'; |
| 450 |
| 451 @override |
| 452 String get name => 'STRONG_MODE_INVALID_VARIABLE_DECLARATION'; |
| 453 } |
| 454 |
| 455 class NonGroundTypeCheckInfo extends StaticInfo { |
| 456 final DartType type; |
| 457 final AstNode node; |
| 458 |
| 459 NonGroundTypeCheckInfo(this.node, this.type) { |
| 460 assert(node is IsExpression || node is AsExpression); |
| 461 } |
| 462 |
| 463 @override List<Object> get arguments => [type]; |
| 464 String get message => |
| 465 "Runtime check on non-ground type {0} may throw StrongModeError"; |
| 466 |
| 467 @override |
| 468 String get name => 'STRONG_MODE_NON_GROUND_TYPE_CHECK_INFO'; |
| 469 |
| 470 toErrorCode() => new HintCode(name, message); |
| 471 } |
| 472 |
| 473 abstract class StaticError extends StaticInfo { |
| 474 final AstNode node; |
| 475 |
| 476 StaticError(this.node); |
| 477 |
| 478 String get message; |
| 479 |
| 480 toErrorCode() => new CompileTimeErrorCode(name, message); |
| 481 } |
| 482 |
| 483 // TODO(jmesserly): this could use some refactoring. These are essentially |
| 484 // like ErrorCodes in analyzer, but we're including some details in our message. |
| 485 // Analyzer instead has template strings, and replaces '{0}' with the first |
| 486 // argument. |
| 487 abstract class StaticInfo { |
| 488 List<Object> get arguments => [node]; |
| 489 |
| 490 String get name; |
| 491 |
| 492 /// AST Node this info is attached to. |
| 493 AstNode get node; |
| 494 |
| 495 AnalysisError toAnalysisError() { |
| 496 int begin = node is AnnotatedNode |
| 497 ? (node as AnnotatedNode).firstTokenAfterCommentAndMetadata.offset |
| 498 : node.offset; |
| 499 int length = node.end - begin; |
| 500 var source = (node.root as CompilationUnit).element.source; |
| 501 return new AnalysisError(source, begin, length, toErrorCode(), arguments); |
| 502 } |
| 503 |
| 504 // TODO(jmesserly): review the usage of error codes. We probably want our own, |
| 505 // as well as some DDC specific [ErrorType]s. |
| 506 ErrorCode toErrorCode(); |
| 507 } |
| 508 |
| 509 class StaticTypeError extends StaticError { |
| 510 final DartType baseType; |
| 511 final DartType expectedType; |
| 512 String reason = null; |
| 513 |
| 514 StaticTypeError(TypeRules rules, Expression expression, this.expectedType, |
| 515 {this.reason}) |
| 516 : baseType = rules.getStaticType(expression), |
| 517 super(expression); |
| 518 |
| 519 @override List<Object> get arguments => [node, baseType, expectedType]; |
| 520 @override String get message => |
| 521 'Type check failed: {0} ({1}) is not of type {2}' + |
| 522 ((reason == null) ? '' : ' because $reason'); |
| 523 |
| 524 @override |
| 525 String get name => 'STRONG_MODE_STATIC_TYPE_ERROR'; |
| 526 } |
| 527 |
| 528 // |
| 529 // Temporary "casts" of allocation sites - literals, constructor invocations, |
| 530 // and closures. These should be handled by contextual inference. In most |
| 531 // cases, inference will be sufficient, though in some it may unmask an actual |
| 532 // error: e.g., |
| 533 // List<int> l = [1, 2, 3]; // Inference succeeds |
| 534 // List<String> l = [1, 2, 3]; // Inference reveals static type error |
| 535 // We're marking all as warnings for now. |
| 536 // |
| 537 // TODO(vsm,leafp): Remove this. |
| 538 class UninferredClosure extends DownCast { |
| 539 UninferredClosure(TypeRules rules, FunctionExpression expression, Cast cast) |
| 540 : super._internal(rules, expression, cast); |
| 541 |
| 542 @override |
| 543 String get name => 'STRONG_MODE_UNINFERRED_CLOSURE'; |
| 544 |
| 545 toErrorCode() => new StaticTypeWarningCode(name, message); |
| 546 } |
| OLD | NEW |