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 |