| 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 library dev_compiler.src.info; | 7 library dev_compiler.src.info; |
| 8 | 8 |
| 9 import 'dart:mirrors'; | 9 import 'dart:mirrors'; |
| 10 | 10 |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 expression.accept(visitor); | 183 expression.accept(visitor); |
| 184 } | 184 } |
| 185 | 185 |
| 186 // Use same precedence as MethodInvocation. | 186 // Use same precedence as MethodInvocation. |
| 187 int get precedence => 15; | 187 int get precedence => 15; |
| 188 | 188 |
| 189 @override | 189 @override |
| 190 Iterable get childEntities => new ChildEntities()..add(expression); | 190 Iterable get childEntities => new ChildEntities()..add(expression); |
| 191 } | 191 } |
| 192 | 192 |
| 193 // A down cast from a subtype to a supertype. This must be checked at | 193 // Base class for all casts from base type to sub type. |
| 194 // runtime to recover soundness. | 194 abstract class DownCast extends Conversion { |
| 195 abstract class DownCastBase extends Conversion { | |
| 196 Cast _cast; | 195 Cast _cast; |
| 197 | 196 |
| 198 DownCastBase._internal(TypeRules rules, Expression expression, this._cast) | 197 DownCast._internal(TypeRules rules, Expression expression, this._cast) |
| 199 : super(rules, expression) { | 198 : super(rules, expression) { |
| 200 assert(_cast.toType != baseType && | 199 assert(_cast.toType != baseType && |
| 201 _cast.fromType == baseType && | 200 _cast.fromType == baseType && |
| 202 (baseType.isDynamic || | 201 (baseType.isDynamic || |
| 203 // Call methods make the following non-redundant | 202 // Call methods make the following non-redundant |
| 204 _cast.toType.isSubtypeOf(baseType) || | 203 _cast.toType.isSubtypeOf(baseType) || |
| 205 baseType.isAssignableTo(_cast.toType))); | 204 baseType.isAssignableTo(_cast.toType))); |
| 206 } | 205 } |
| 207 | 206 |
| 208 Cast get cast => _cast; | 207 Cast get cast => _cast; |
| 209 | 208 |
| 210 DartType _getConvertedType() => _cast.toType; | 209 DartType _getConvertedType() => _cast.toType; |
| 211 | 210 |
| 212 String get message => '$expression ($baseType) will need runtime check ' | 211 String get message => '$expression ($baseType) will need runtime check ' |
| 213 'to cast to type $convertedType'; | 212 'to cast to type $convertedType'; |
| 214 | 213 |
| 215 // Differentiate between Function down cast and non-Function down cast? The | |
| 216 // former seems less likely to actually succeed. | |
| 217 Level get level => | |
| 218 (_cast.toType is FunctionType) ? Level.WARNING : super.level; | |
| 219 | |
| 220 accept(AstVisitor visitor) { | |
| 221 if (visitor is ConversionVisitor) { | |
| 222 return visitor.visitDownCastBase(this); | |
| 223 } else { | |
| 224 return expression.accept(visitor); | |
| 225 } | |
| 226 } | |
| 227 } | |
| 228 | |
| 229 // Standard / unspecialized down cast. | |
| 230 class DownCast extends DownCastBase { | |
| 231 DownCast(TypeRules rules, Expression expression, Cast cast) | |
| 232 : super._internal(rules, expression, cast); | |
| 233 | |
| 234 // Factory to create correct DownCast variant. | 214 // Factory to create correct DownCast variant. |
| 235 static DownCastBase create( | 215 static StaticInfo create(TypeRules rules, Expression expression, Cast cast) { |
| 236 TypeRules rules, Expression expression, Cast cast) { | |
| 237 final fromT = cast.fromType; | 216 final fromT = cast.fromType; |
| 238 final toT = cast.toType; | 217 final toT = cast.toType; |
| 239 | 218 |
| 240 // toT <:_R fromT => to <: fromT | 219 // toT <:_R fromT => to <: fromT |
| 241 // NB: classes with call methods are subtypes of function | 220 // NB: classes with call methods are subtypes of function |
| 242 // types, but the function type is not assignable to the class | 221 // types, but the function type is not assignable to the class |
| 243 assert(toT.isSubtypeOf(fromT) || fromT.isAssignableTo(toT)); | 222 assert(toT.isSubtypeOf(fromT) || fromT.isAssignableTo(toT)); |
| 244 | 223 |
| 245 // Specialized casts: | 224 // Handle null call specially. |
| 225 if (expression is NullLiteral) { |
| 226 if (rules.isNonNullableType(toT)) { |
| 227 return new StaticTypeError(rules, expression, toT); |
| 228 } else { |
| 229 // We should only get here if some coercion is required. |
| 230 assert(rules.maybeNonNullableType(toT)); |
| 231 // TODO(vsm): Create a NullCast for this once we revisit nonnullability. |
| 232 return new DownCastImplicit(rules, expression, cast); |
| 233 } |
| 234 } |
| 235 |
| 236 // Inference "casts": |
| 246 if (expression is Literal) { | 237 if (expression is Literal) { |
| 247 // fromT should be an exact type - this will almost certainly fail at | 238 // fromT should be an exact type - this will almost certainly fail at |
| 248 // runtime. | 239 // runtime. |
| 249 return new DownCastLiteral(rules, expression, cast); | 240 return new InferableLiteral(rules, expression, cast); |
| 241 } |
| 242 if (expression is FunctionExpression) { |
| 243 // fromT should be an exact type - this will almost certainly fail at |
| 244 // runtime. |
| 245 return new InferableClosure(rules, expression, cast); |
| 250 } | 246 } |
| 251 if (expression is InstanceCreationExpression) { | 247 if (expression is InstanceCreationExpression) { |
| 252 // fromT should be an exact type - this will almost certainly fail at | 248 // fromT should be an exact type - this will almost certainly fail at |
| 253 // runtime. | 249 // runtime. |
| 254 return new DownCastExact(rules, expression, cast); | 250 return new InferableAllocation(rules, expression, cast); |
| 255 } | 251 } |
| 256 if (fromT.isSubtypeOf(toT) && !fromT.isDynamic) { | 252 |
| 253 // Composite cast: these are more likely to fail. |
| 254 if (!rules.isGroundType(toT)) { |
| 257 // This cast is (probably) due to our different treatment of dynamic. | 255 // This cast is (probably) due to our different treatment of dynamic. |
| 258 // It may be more likely to fail at runtime. | 256 // It may be more likely to fail at runtime. |
| 259 return new DownCastDynamic(rules, expression, cast); | 257 return new DownCastComposite(rules, expression, cast); |
| 260 } | 258 } |
| 261 return new DownCast(rules, expression, cast); | 259 |
| 260 // Dynamic cast |
| 261 if (fromT.isDynamic) { |
| 262 return new DynamicCast(rules, expression, cast); |
| 263 } |
| 264 |
| 265 // Assignment cast |
| 266 var parent = expression.parent; |
| 267 if (parent is VariableDeclaration && (parent.initializer == expression)) { |
| 268 return new AssignmentCast(rules, expression, cast); |
| 269 } |
| 270 |
| 271 // Other casts |
| 272 return new DownCastImplicit(rules, expression, cast); |
| 273 } |
| 274 |
| 275 accept(AstVisitor visitor) { |
| 276 if (visitor is ConversionVisitor) { |
| 277 return visitor.visitDownCast(this); |
| 278 } else { |
| 279 return expression.accept(visitor); |
| 280 } |
| 262 } | 281 } |
| 263 } | 282 } |
| 264 | 283 |
| 265 // A down cast that would be "unnecessary" with standard Dart rules. | 284 // |
| 266 // E.g., the fromType <: toType in standard Dart but not in our restricted | 285 // Standard down casts. These casts are implicitly injected by the compiler. |
| 267 // rules. These occur due to our stricter rules on dynamic type parameters in | 286 // |
| 268 // generics. | 287 |
| 269 class DownCastDynamic extends DownCastBase { | 288 // A down cast from dynamic to T. |
| 270 DownCastDynamic(TypeRules rules, Expression expression, Cast cast) | 289 class DynamicCast extends DownCast { |
| 290 DynamicCast(TypeRules rules, Expression expression, Cast cast) |
| 291 : super._internal(rules, expression, cast); |
| 292 |
| 293 final Level level = Level.INFO; |
| 294 } |
| 295 |
| 296 // A down cast due to a variable declaration to a ground type. E.g., |
| 297 // T x = expr; |
| 298 // where T is ground. We exclude non-ground types as these behave differently |
| 299 // compared to standard Dart. |
| 300 class AssignmentCast extends DownCast { |
| 301 AssignmentCast(TypeRules rules, Expression expression, Cast cast) |
| 302 : super._internal(rules, expression, cast); |
| 303 |
| 304 final Level level = Level.INFO; |
| 305 } |
| 306 |
| 307 // |
| 308 // Temporary "casts" of allocation sites - literals, constructor invocations, |
| 309 // and closures. These should be handled by contextual inference. In most |
| 310 // cases, inference will be sufficient, though in some it may unmask an actual |
| 311 // error: e.g., |
| 312 // List<int> l = [1, 2, 3]; // Inference succeeds |
| 313 // List<String> l = [1, 2, 3]; // Inference reveals static type error |
| 314 // We're marking all as warnings for now. |
| 315 // |
| 316 |
| 317 // A "down cast" on a literal expression. |
| 318 class InferableLiteral extends DownCast { |
| 319 InferableLiteral(TypeRules rules, Literal expression, Cast cast) |
| 271 : super._internal(rules, expression, cast); | 320 : super._internal(rules, expression, cast); |
| 272 | 321 |
| 273 final Level level = Level.WARNING; | 322 final Level level = Level.WARNING; |
| 274 } | 323 } |
| 275 | 324 |
| 276 // A down cast on a literal expression. This should never succeed. | 325 // A "down cast" on a closure literal. |
| 277 // TODO(vsm): Mark as severe / error? | 326 class InferableClosure extends DownCast { |
| 278 class DownCastLiteral extends DownCastBase { | 327 InferableClosure(TypeRules rules, FunctionExpression expression, Cast cast) |
| 279 DownCastLiteral(TypeRules rules, Expression expression, Cast cast) | |
| 280 : super._internal(rules, expression, cast); | 328 : super._internal(rules, expression, cast); |
| 281 | 329 |
| 282 final Level level = Level.WARNING; | 330 final Level level = Level.WARNING; |
| 283 } | 331 } |
| 284 | 332 |
| 285 // A down cast on a non-literal allocation site. This should never succeed. | 333 // A "down cast" on a non-literal allocation site. |
| 286 // TODO(vsm): Mark as severe / error? | 334 class InferableAllocation extends DownCast { |
| 287 class DownCastExact extends DownCastBase { | 335 InferableAllocation( |
| 288 DownCastExact(TypeRules rules, Expression expression, Cast cast) | 336 TypeRules rules, InstanceCreationExpression expression, Cast cast) |
| 289 : super._internal(rules, expression, cast); | 337 : super._internal(rules, expression, cast); |
| 290 | 338 |
| 291 final Level level = Level.WARNING; | 339 final Level level = Level.WARNING; |
| 292 } | 340 } |
| 293 | 341 |
| 342 // |
| 343 // Implicit down casts. These are only injected by the compiler by flag. |
| 344 // |
| 345 |
| 346 // A down cast to a non-ground type. These behave differently from standard |
| 347 // Dart and may be more likely to fail at runtime. |
| 348 class DownCastComposite extends DownCast { |
| 349 DownCastComposite(TypeRules rules, Expression expression, Cast cast) |
| 350 : super._internal(rules, expression, cast); |
| 351 |
| 352 final Level level = Level.WARNING; |
| 353 } |
| 354 |
| 355 // A down cast to a non-ground type. These behave differently from standard |
| 356 // Dart and may be more likely to fail at runtime. |
| 357 class DownCastImplicit extends DownCast { |
| 358 DownCastImplicit(TypeRules rules, Expression expression, Cast cast) |
| 359 : super._internal(rules, expression, cast); |
| 360 |
| 361 final Level level = Level.WARNING; |
| 362 } |
| 363 |
| 364 // TODO(vsm): Remove these. |
| 365 |
| 294 // A wrapped closure coerces the underlying type to the desired type. | 366 // A wrapped closure coerces the underlying type to the desired type. |
| 295 class ClosureWrapBase extends Conversion { | 367 class ClosureWrapBase extends Conversion { |
| 296 FunctionType _wrappedType; | 368 FunctionType _wrappedType; |
| 297 Wrapper _wrapper; | 369 Wrapper _wrapper; |
| 298 | 370 |
| 299 ClosureWrapBase._internal( | 371 ClosureWrapBase._internal( |
| 300 TypeRules rules, Expression expression, this._wrapper, this._wrappedType) | 372 TypeRules rules, Expression expression, this._wrapper, this._wrappedType) |
| 301 : super(rules, expression) { | 373 : super(rules, expression) { |
| 302 assert(baseType is FunctionType); | 374 assert(baseType is FunctionType); |
| 303 assert(!rules.isSubTypeOf(baseType, _wrappedType)); | 375 assert(!rules.isSubTypeOf(baseType, _wrappedType)); |
| (...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 574 /// GeneralizingAstVisitor<R>. | 646 /// GeneralizingAstVisitor<R>. |
| 575 R visitNode(AstNode node); | 647 R visitNode(AstNode node); |
| 576 | 648 |
| 577 // Handle runtime operations | 649 // Handle runtime operations |
| 578 R visitRuntimeOperation(RuntimeOperation node) => visitNode(node); | 650 R visitRuntimeOperation(RuntimeOperation node) => visitNode(node); |
| 579 | 651 |
| 580 /// The catch-all for any kind of conversion | 652 /// The catch-all for any kind of conversion |
| 581 R visitConversion(Conversion node) => visitNode(node); | 653 R visitConversion(Conversion node) => visitNode(node); |
| 582 | 654 |
| 583 // Methods for conversion subtypes: | 655 // Methods for conversion subtypes: |
| 584 R visitDownCastBase(DownCastBase node) => visitConversion(node); | 656 R visitDownCast(DownCast node) => visitConversion(node); |
| 585 R visitDownCast(DownCast node) => visitDownCastBase(node); | |
| 586 R visitDownCastDynamic(DownCastDynamic node) => visitDownCastBase(node); | |
| 587 R visitDownCastExact(DownCastExact node) => visitDownCastBase(node); | |
| 588 R visitClosureWrapBase(ClosureWrapBase node) => visitConversion(node); | 657 R visitClosureWrapBase(ClosureWrapBase node) => visitConversion(node); |
| 589 R visitClosureWrap(ClosureWrap node) => visitClosureWrapBase(node); | 658 R visitClosureWrap(ClosureWrap node) => visitClosureWrapBase(node); |
| 590 R visitDynamicInvoke(DynamicInvoke node) => visitConversion(node); | 659 R visitDynamicInvoke(DynamicInvoke node) => visitConversion(node); |
| 591 } | 660 } |
| 592 | 661 |
| 593 /// Automatically infer list of types by scanning this library using mirrors. | 662 /// Automatically infer list of types by scanning this library using mirrors. |
| 594 final List<Type> infoTypes = () { | 663 final List<Type> infoTypes = () { |
| 595 var allTypes = new Set(); | 664 var allTypes = new Set(); |
| 596 var baseTypes = new Set(); | 665 var baseTypes = new Set(); |
| 597 var infoMirror = reflectClass(StaticInfo); | 666 var infoMirror = reflectClass(StaticInfo); |
| 598 var declarations = infoMirror.owner.declarations.values; | 667 var declarations = infoMirror.owner.declarations.values; |
| 599 for (var cls in declarations.where((d) => d is ClassMirror)) { | 668 for (var cls in declarations.where((d) => d is ClassMirror)) { |
| 600 if (cls.isSubtypeOf(infoMirror)) { | 669 if (cls.isSubtypeOf(infoMirror)) { |
| 601 allTypes.add(cls); | 670 allTypes.add(cls); |
| 602 baseTypes.add(cls.superclass); | 671 baseTypes.add(cls.superclass); |
| 603 } | 672 } |
| 604 } | 673 } |
| 605 allTypes.removeAll(baseTypes); | 674 allTypes.removeAll(baseTypes); |
| 606 return new List<Type>.from(allTypes.map((mirror) => mirror.reflectedType)) | 675 return new List<Type>.from(allTypes.map((mirror) => mirror.reflectedType)) |
| 607 ..sort((t1, t2) => '$t1'.compareTo('$t2')); | 676 ..sort((t1, t2) => '$t1'.compareTo('$t2')); |
| 608 }(); | 677 }(); |
| OLD | NEW |