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 |