| 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 |
| 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' as analyzer; | 13 import 'package:analyzer/src/generated/error.dart' as analyzer; |
| 14 import 'package:analyzer/src/generated/scanner.dart' | |
| 15 show Token, TokenType, SyntheticStringToken; | |
| 16 import 'package:logging/logging.dart' show Level; | 14 import 'package:logging/logging.dart' show Level; |
| 17 | 15 |
| 18 import 'package:dev_compiler/src/checker/rules.dart'; | 16 import 'package:dev_compiler/src/checker/rules.dart'; |
| 19 import 'package:dev_compiler/src/utils.dart' as utils; | 17 import 'package:dev_compiler/src/utils.dart' as utils; |
| 20 | 18 |
| 21 import 'report.dart' show Message; | 19 import 'report.dart' show Message; |
| 22 | 20 |
| 23 /// Represents a summary of the results collected by running the program | 21 /// Represents a summary of the results collected by running the program |
| 24 /// checker. | 22 /// checker. |
| 25 class CheckerResults { | 23 class CheckerResults { |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 102 @override | 100 @override |
| 103 int get begin => node is AnnotatedNode | 101 int get begin => node is AnnotatedNode |
| 104 ? (node as AnnotatedNode).firstTokenAfterCommentAndMetadata.offset | 102 ? (node as AnnotatedNode).firstTokenAfterCommentAndMetadata.offset |
| 105 : node.offset; | 103 : node.offset; |
| 106 | 104 |
| 107 @override | 105 @override |
| 108 int get end => node.end; | 106 int get end => node.end; |
| 109 } | 107 } |
| 110 | 108 |
| 111 /// Implicitly injected expression conversion. | 109 /// Implicitly injected expression conversion. |
| 112 // TODO(jmesserly): rename to have Expression suffix? | 110 abstract class CoercionInfo extends StaticInfo { |
| 113 abstract class Conversion extends Expression with StaticInfo { | |
| 114 final TypeRules rules; | 111 final TypeRules rules; |
| 115 | 112 |
| 116 // TODO(jmesserly): should probably rename this "operand" for consistency with | 113 final Expression node; |
| 117 // analyzer's unary expressions (e.g. PrefixExpression). | |
| 118 final Expression expression; | |
| 119 | 114 |
| 120 AstNode get node => expression; | 115 DartType get convertedType; |
| 121 DartType _convertedType; | |
| 122 | 116 |
| 123 Conversion(this.rules, this.expression) { | 117 CoercionInfo(this.rules, this.node); |
| 124 this._convertedType = _getConvertedType(); | |
| 125 } | |
| 126 | 118 |
| 127 DartType get baseType => rules.getStaticType(expression); | 119 DartType get baseType => rules.getStaticType(node); |
| 128 DartType get convertedType => _convertedType; | 120 DartType get staticType => convertedType; |
| 129 DartType get staticType => _convertedType; | |
| 130 | |
| 131 DartType _getConvertedType(); | |
| 132 | 121 |
| 133 // safe iff this cannot throw | 122 // safe iff this cannot throw |
| 134 bool get safe => false; | 123 bool get safe => false; |
| 135 | 124 |
| 136 Level get level => safe ? Level.CONFIG : Level.INFO; | 125 Level get level => safe ? Level.CONFIG : Level.INFO; |
| 137 | 126 |
| 138 String get description => '${this.runtimeType}: $baseType to $convertedType'; | 127 String get description => '${this.runtimeType}: $baseType to $convertedType'; |
| 139 | 128 |
| 140 Token get beginToken => expression.beginToken; | 129 static const String _propertyName = 'dev_compiler.Conversion'; |
| 141 Token get endToken => expression.endToken; | |
| 142 | 130 |
| 143 @override | 131 /// Gets the coercion info associated with this node. |
| 144 void visitChildren(AstVisitor visitor) { | 132 static CoercionInfo get(AstNode node) => node.getProperty(_propertyName); |
| 145 expression.accept(visitor); | 133 |
| 134 /// Sets the coercion info associated with this node. |
| 135 static CoercionInfo set(AstNode node, CoercionInfo info) { |
| 136 node.setProperty(_propertyName, info); |
| 137 return info; |
| 146 } | 138 } |
| 147 | |
| 148 // Use same precedence as MethodInvocation. | |
| 149 int get precedence => 15; | |
| 150 | |
| 151 @override | |
| 152 Iterable get childEntities => new ChildEntities()..add(expression); | |
| 153 } | 139 } |
| 154 | 140 |
| 155 // Base class for all casts from base type to sub type. | 141 // Base class for all casts from base type to sub type. |
| 156 abstract class DownCast extends Conversion { | 142 abstract class DownCast extends CoercionInfo { |
| 157 Cast _cast; | 143 Cast _cast; |
| 158 | 144 |
| 159 DownCast._internal(TypeRules rules, Expression expression, this._cast) | 145 DownCast._internal(TypeRules rules, Expression expression, this._cast) |
| 160 : super(rules, expression) { | 146 : super(rules, expression) { |
| 161 assert(_cast.toType != baseType && | 147 assert(_cast.toType != baseType && |
| 162 _cast.fromType == baseType && | 148 _cast.fromType == baseType && |
| 163 (baseType.isDynamic || | 149 (baseType.isDynamic || |
| 164 // Call methods make the following non-redundant | 150 // Call methods make the following non-redundant |
| 165 _cast.toType.isSubtypeOf(baseType) || | 151 _cast.toType.isSubtypeOf(baseType) || |
| 166 baseType.isAssignableTo(_cast.toType))); | 152 baseType.isAssignableTo(_cast.toType))); |
| 167 } | 153 } |
| 168 | 154 |
| 169 Cast get cast => _cast; | 155 Cast get cast => _cast; |
| 170 | 156 |
| 171 DartType _getConvertedType() => _cast.toType; | 157 DartType get convertedType => _cast.toType; |
| 172 | 158 |
| 173 String get message => '$expression ($baseType) will need runtime check ' | 159 String get message => '$node ($baseType) will need runtime check ' |
| 174 'to cast to type $convertedType'; | 160 'to cast to type $convertedType'; |
| 175 | 161 |
| 176 // Factory to create correct DownCast variant. | 162 // Factory to create correct DownCast variant. |
| 177 static StaticInfo create(TypeRules rules, Expression expression, Cast cast, | 163 static StaticInfo create(TypeRules rules, Expression expression, Cast cast, |
| 178 {String reason}) { | 164 {String reason}) { |
| 179 final fromT = cast.fromType; | 165 final fromT = cast.fromType; |
| 180 final toT = cast.toType; | 166 final toT = cast.toType; |
| 181 | 167 |
| 182 // toT <:_R fromT => to <: fromT | 168 // toT <:_R fromT => to <: fromT |
| 183 // NB: classes with call methods are subtypes of function | 169 // NB: classes with call methods are subtypes of function |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 | 214 |
| 229 // Assignment cast | 215 // Assignment cast |
| 230 var parent = expression.parent; | 216 var parent = expression.parent; |
| 231 if (parent is VariableDeclaration && (parent.initializer == expression)) { | 217 if (parent is VariableDeclaration && (parent.initializer == expression)) { |
| 232 return new AssignmentCast(rules, expression, cast); | 218 return new AssignmentCast(rules, expression, cast); |
| 233 } | 219 } |
| 234 | 220 |
| 235 // Other casts | 221 // Other casts |
| 236 return new DownCastImplicit(rules, expression, cast); | 222 return new DownCastImplicit(rules, expression, cast); |
| 237 } | 223 } |
| 238 | |
| 239 accept(AstVisitor visitor) { | |
| 240 if (visitor is ConversionVisitor) { | |
| 241 return visitor.visitDownCast(this); | |
| 242 } else { | |
| 243 return expression.accept(visitor); | |
| 244 } | |
| 245 } | |
| 246 } | 224 } |
| 247 | 225 |
| 248 // | 226 // |
| 249 // Standard down casts. These casts are implicitly injected by the compiler. | 227 // Standard down casts. These casts are implicitly injected by the compiler. |
| 250 // | 228 // |
| 251 | 229 |
| 252 // A down cast from dynamic to T. | 230 // A down cast from dynamic to T. |
| 253 class DynamicCast extends DownCast { | 231 class DynamicCast extends DownCast { |
| 254 DynamicCast(TypeRules rules, Expression expression, Cast cast) | 232 DynamicCast(TypeRules rules, Expression expression, Cast cast) |
| 255 : super._internal(rules, expression, cast); | 233 : super._internal(rules, expression, cast); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 302 // Dart and may be more likely to fail at runtime. | 280 // Dart and may be more likely to fail at runtime. |
| 303 class DownCastImplicit extends DownCast { | 281 class DownCastImplicit extends DownCast { |
| 304 DownCastImplicit(TypeRules rules, Expression expression, Cast cast) | 282 DownCastImplicit(TypeRules rules, Expression expression, Cast cast) |
| 305 : super._internal(rules, expression, cast); | 283 : super._internal(rules, expression, cast); |
| 306 | 284 |
| 307 final Level level = Level.WARNING; | 285 final Level level = Level.WARNING; |
| 308 } | 286 } |
| 309 | 287 |
| 310 // An inferred type for the wrapped expression, which may need to be | 288 // An inferred type for the wrapped expression, which may need to be |
| 311 // reified into the term | 289 // reified into the term |
| 312 abstract class InferredTypeBase extends Conversion { | 290 abstract class InferredTypeBase extends CoercionInfo { |
| 313 DartType _type; | 291 final DartType _type; |
| 314 | 292 |
| 315 InferredTypeBase._internal(TypeRules rules, Expression expression, this._type) | 293 InferredTypeBase._internal(TypeRules rules, Expression expression, this._type) |
| 316 : super(rules, expression); | 294 : super(rules, expression); |
| 317 | 295 |
| 318 DartType get type => _type; | 296 DartType get type => _type; |
| 319 | 297 DartType get convertedType => type; |
| 320 DartType _getConvertedType() => type; | 298 String get message => '$node has inferred type $type'; |
| 321 | |
| 322 String get message => '$expression has inferred type $type'; | |
| 323 | |
| 324 Level get level => Level.INFO; | 299 Level get level => Level.INFO; |
| 325 | |
| 326 accept(AstVisitor visitor) { | |
| 327 if (visitor is ConversionVisitor) { | |
| 328 return visitor.visitInferredTypeBase(this); | |
| 329 } else { | |
| 330 return expression.accept(visitor); | |
| 331 } | |
| 332 } | |
| 333 } | 300 } |
| 334 | 301 |
| 335 // Standard / unspecialized inferred type | 302 // Standard / unspecialized inferred type |
| 336 class InferredType extends InferredTypeBase { | 303 class InferredType extends InferredTypeBase { |
| 337 InferredType(TypeRules rules, Expression expression, DartType type) | 304 InferredType(TypeRules rules, Expression expression, DartType type) |
| 338 : super._internal(rules, expression, type); | 305 : super._internal(rules, expression, type); |
| 339 | 306 |
| 340 // Factory to create correct InferredType variant. | 307 // Factory to create correct InferredType variant. |
| 341 static InferredTypeBase create( | 308 static InferredTypeBase create( |
| 342 TypeRules rules, Expression expression, DartType type) { | 309 TypeRules rules, Expression expression, DartType type) { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 366 InferredTypeAllocation(TypeRules rules, Expression expression, DartType type) | 333 InferredTypeAllocation(TypeRules rules, Expression expression, DartType type) |
| 367 : super._internal(rules, expression, type); | 334 : super._internal(rules, expression, type); |
| 368 } | 335 } |
| 369 | 336 |
| 370 // An inferred type for a closure expression | 337 // An inferred type for a closure expression |
| 371 class InferredTypeClosure extends InferredTypeBase { | 338 class InferredTypeClosure extends InferredTypeBase { |
| 372 InferredTypeClosure(TypeRules rules, Expression expression, DartType type) | 339 InferredTypeClosure(TypeRules rules, Expression expression, DartType type) |
| 373 : super._internal(rules, expression, type); | 340 : super._internal(rules, expression, type); |
| 374 } | 341 } |
| 375 | 342 |
| 376 class DynamicInvoke extends Conversion { | 343 class DynamicInvoke extends CoercionInfo { |
| 377 DynamicInvoke(TypeRules rules, Expression expression) | 344 DynamicInvoke(TypeRules rules, Expression expression) |
| 378 : super(rules, expression); | 345 : super(rules, expression); |
| 379 | 346 |
| 380 DartType _getConvertedType() => rules.provider.dynamicType; | 347 DartType get convertedType => rules.provider.dynamicType; |
| 381 | 348 String get message => '$node requires dynamic invoke'; |
| 382 String get message => '$expression requires dynamic invoke'; | |
| 383 Level get level => Level.INFO; | 349 Level get level => Level.INFO; |
| 384 | |
| 385 accept(AstVisitor visitor) { | |
| 386 if (visitor is ConversionVisitor) { | |
| 387 return visitor.visitDynamicInvoke(this); | |
| 388 } else { | |
| 389 return expression.accept(visitor); | |
| 390 } | |
| 391 } | |
| 392 } | 350 } |
| 393 | 351 |
| 394 abstract class StaticError extends StaticInfo { | 352 abstract class StaticError extends StaticInfo { |
| 395 final AstNode node; | 353 final AstNode node; |
| 396 | 354 |
| 397 StaticError(this.node); | 355 StaticError(this.node); |
| 398 | 356 |
| 399 Level get level => Level.SEVERE; | 357 Level get level => Level.SEVERE; |
| 400 } | 358 } |
| 401 | 359 |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 549 /// <http://goo.gl/q1T4BB> | 507 /// <http://goo.gl/q1T4BB> |
| 550 /// | 508 /// |
| 551 /// For now this is the only pattern we support. | 509 /// For now this is the only pattern we support. |
| 552 class InvalidSuperInvocation extends StaticError { | 510 class InvalidSuperInvocation extends StaticError { |
| 553 InvalidSuperInvocation(SuperConstructorInvocation node) : super(node); | 511 InvalidSuperInvocation(SuperConstructorInvocation node) : super(node); |
| 554 | 512 |
| 555 String get message => "super call must be last in an initializer list " | 513 String get message => "super call must be last in an initializer list " |
| 556 "(see http://goo.gl/q1T4BB): $node"; | 514 "(see http://goo.gl/q1T4BB): $node"; |
| 557 } | 515 } |
| 558 | 516 |
| 559 /// A simple generalizing visitor interface for the conversion nodes. | |
| 560 /// This can be mixed in to your visitor if the AST can contain these nodes. | |
| 561 abstract class ConversionVisitor<R> implements AstVisitor<R> { | |
| 562 /// This method must be implemented. It is typically supplied by the base | |
| 563 /// GeneralizingAstVisitor<R>. | |
| 564 R visitNode(AstNode node); | |
| 565 | |
| 566 /// The catch-all for any kind of conversion | |
| 567 R visitConversion(Conversion node) => visitNode(node); | |
| 568 | |
| 569 // Methods for conversion subtypes: | |
| 570 R visitDownCast(DownCast node) => visitConversion(node); | |
| 571 R visitDynamicInvoke(DynamicInvoke node) => visitConversion(node); | |
| 572 R visitInferredTypeBase(InferredTypeBase node) => visitConversion(node); | |
| 573 } | |
| 574 | |
| 575 /// Automatically infer list of types by scanning this library using mirrors. | 517 /// Automatically infer list of types by scanning this library using mirrors. |
| 576 final List<Type> infoTypes = () { | 518 final List<Type> infoTypes = () { |
| 577 var allTypes = new Set(); | 519 var allTypes = new Set(); |
| 578 var baseTypes = new Set(); | 520 var baseTypes = new Set(); |
| 579 var infoMirror = reflectClass(StaticInfo); | 521 var infoMirror = reflectClass(StaticInfo); |
| 580 var libMirror = infoMirror.owner as LibraryMirror; | 522 var libMirror = infoMirror.owner as LibraryMirror; |
| 581 var declarations = libMirror.declarations.values; | 523 var declarations = libMirror.declarations.values; |
| 582 for (ClassMirror cls in declarations.where((d) => d is ClassMirror)) { | 524 for (ClassMirror cls in declarations.where((d) => d is ClassMirror)) { |
| 583 if (cls.isSubtypeOf(infoMirror)) { | 525 if (cls.isSubtypeOf(infoMirror)) { |
| 584 allTypes.add(cls); | 526 allTypes.add(cls); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 596 var isError = severity == analyzer.ErrorSeverity.WARNING; | 538 var isError = severity == analyzer.ErrorSeverity.WARNING; |
| 597 var level = isError ? Level.SEVERE : Level.WARNING; | 539 var level = isError ? Level.SEVERE : Level.WARNING; |
| 598 int begin = error.offset; | 540 int begin = error.offset; |
| 599 int end = begin + error.length; | 541 int end = begin + error.length; |
| 600 return new AnalyzerError(error.message, level, begin, end); | 542 return new AnalyzerError(error.message, level, begin, end); |
| 601 } | 543 } |
| 602 | 544 |
| 603 const AnalyzerError(String message, Level level, int begin, int end) | 545 const AnalyzerError(String message, Level level, int begin, int end) |
| 604 : super(message, level, begin, end); | 546 : super(message, level, begin, end); |
| 605 } | 547 } |
| OLD | NEW |