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