Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(371)

Side by Side Diff: lib/src/info.dart

Issue 1401273002: Move DDC to analyzer-based checker (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: rebase Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/src/compiler.dart ('k') | lib/src/server/server.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 'package:analyzer/src/generated/ast.dart'; 9 import 'package:analyzer/src/generated/ast.dart';
10 import 'package:analyzer/src/generated/element.dart'; 10 import 'package:analyzer/src/generated/element.dart';
11 import 'package:analyzer/src/generated/error.dart';
12 import 'package:analyzer/src/generated/parser.dart'; 11 import 'package:analyzer/src/generated/parser.dart';
13 12
14 import 'checker/rules.dart';
15 import 'utils.dart' as utils; 13 import 'utils.dart' as utils;
14 import 'package:analyzer/src/task/strong/info.dart';
15 export 'package:analyzer/src/task/strong/info.dart';
16 16
17 /// Represents a summary of the results collected by running the program 17 /// Represents a summary of the results collected by running the program
18 /// checker. 18 /// checker.
19 class CheckerResults { 19 class CheckerResults {
20 final List<LibraryInfo> libraries; 20 final List<LibraryInfo> libraries;
21 final TypeRules rules;
22 final bool failure; 21 final bool failure;
23 22
24 CheckerResults(this.libraries, this.rules, this.failure); 23 CheckerResults(this.libraries, this.failure);
25 } 24 }
26 25
27 /// Computed information about each library. 26 /// Computed information about each library.
28 class LibraryInfo { 27 class LibraryInfo {
29 /// Canonical name of the library. This is unfortunately not derived from the 28 /// Canonical name of the library. This is unfortunately not derived from the
30 /// library directive as it doesn't have any meaningful rules enforced. 29 /// library directive as it doesn't have any meaningful rules enforced.
31 /// Instead, this is inferred from the path to the file defining the library. 30 /// Instead, this is inferred from the path to the file defining the library.
32 final String name; 31 final String name;
33 32
34 /// Corresponding analyzer element. 33 /// Corresponding analyzer element.
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 // TODO(jmesserly): as a workaround for analyzer <0.26.0-alpha.1. 94 // TODO(jmesserly): as a workaround for analyzer <0.26.0-alpha.1.
96 // ResolutionCopier won't copy the type, so we do it here. 95 // ResolutionCopier won't copy the type, so we do it here.
97 @override 96 @override
98 AwaitExpression visitAwaitExpression(AwaitExpression node) { 97 AwaitExpression visitAwaitExpression(AwaitExpression node) {
99 var clone = super.visitAwaitExpression(node); 98 var clone = super.visitAwaitExpression(node);
100 clone.staticType = node.staticType; 99 clone.staticType = node.staticType;
101 clone.propagatedType = node.propagatedType; 100 clone.propagatedType = node.propagatedType;
102 return clone; 101 return clone;
103 } 102 }
104 } 103 }
105
106 // The abstract type of coercions mapping one type to another.
107 // This class also exposes static builder functions which
108 // check for errors and reduce redundant coercions to the identity.
109 abstract class Coercion {
110 final DartType fromType;
111 final DartType toType;
112 Coercion(this.fromType, this.toType);
113 static Coercion cast(DartType fromT, DartType toT) => new Cast(fromT, toT);
114 static Coercion identity(DartType type) => new Identity(type);
115 static Coercion error() => new CoercionError();
116 }
117
118 // Coercion which casts one type to another
119 class Cast extends Coercion {
120 Cast(DartType fromType, DartType toType) : super(fromType, toType);
121 }
122
123 // The identity coercion
124 class Identity extends Coercion {
125 Identity(DartType fromType) : super(fromType, fromType);
126 }
127
128 // The error coercion. This coercion signals that a coercion
129 // could not be generated. The code generator should not see
130 // these.
131 class CoercionError extends Coercion {
132 CoercionError() : super(null, null);
133 }
134
135 // TODO(jmesserly): this could use some refactoring. These are essentially
136 // like ErrorCodes in analyzer, but we're including some details in our message.
137 // Analyzer instead has template strings, and replaces '{0}' with the first
138 // argument.
139 abstract class StaticInfo {
140 /// AST Node this info is attached to.
141 AstNode get node;
142
143 // TODO(jmesserly): review the usage of error codes. We probably want our own,
144 // as well as some DDC specific [ErrorType]s.
145 ErrorCode toErrorCode();
146
147 // TODO(jmesserly): what convention to use here?
148 String get name => 'dev_compiler.$runtimeType';
149
150 List<Object> get arguments => [node];
151
152 AnalysisError toAnalysisError() {
153 int begin = node is AnnotatedNode
154 ? (node as AnnotatedNode).firstTokenAfterCommentAndMetadata.offset
155 : node.offset;
156 int length = node.end - begin;
157 var source = (node.root as CompilationUnit).element.source;
158 return new AnalysisError(source, begin, length, toErrorCode(), arguments);
159 }
160 }
161
162 /// Implicitly injected expression conversion.
163 abstract class CoercionInfo extends StaticInfo {
164 final TypeRules rules;
165
166 final Expression node;
167
168 DartType get convertedType;
169
170 CoercionInfo(this.rules, this.node);
171
172 DartType get baseType => rules.getStaticType(node);
173 DartType get staticType => convertedType;
174
175 String get message;
176 toErrorCode() => new HintCode(name, message);
177
178 static const String _propertyName = 'dev_compiler.src.info.CoercionInfo';
179
180 /// Gets the coercion info associated with this node.
181 static CoercionInfo get(AstNode node) => node.getProperty(_propertyName);
182
183 /// Sets the coercion info associated with this node.
184 static CoercionInfo set(AstNode node, CoercionInfo info) {
185 node.setProperty(_propertyName, info);
186 return info;
187 }
188 }
189
190 // Base class for all casts from base type to sub type.
191 abstract class DownCast extends CoercionInfo {
192 Cast _cast;
193
194 DownCast._internal(TypeRules rules, Expression expression, this._cast)
195 : super(rules, expression) {
196 assert(_cast.toType != baseType &&
197 _cast.fromType == baseType &&
198 (baseType.isDynamic ||
199 // Call methods make the following non-redundant
200 _cast.toType.isSubtypeOf(baseType) ||
201 baseType.isAssignableTo(_cast.toType)));
202 }
203
204 Cast get cast => _cast;
205
206 DartType get convertedType => _cast.toType;
207
208 @override List<Object> get arguments => [node, baseType, convertedType];
209 @override String get message => '{0} ({1}) will need runtime check '
210 'to cast to type {2}';
211
212 // Factory to create correct DownCast variant.
213 static StaticInfo create(TypeRules rules, Expression expression, Cast cast,
214 {String reason}) {
215 final fromT = cast.fromType;
216 final toT = cast.toType;
217
218 // toT <:_R fromT => to <: fromT
219 // NB: classes with call methods are subtypes of function
220 // types, but the function type is not assignable to the class
221 assert(toT.isSubtypeOf(fromT) || fromT.isAssignableTo(toT));
222
223 // Handle null call specially.
224 if (expression is NullLiteral) {
225 // TODO(vsm): Create a NullCast for this once we revisit nonnullability.
226 return new DownCastImplicit(rules, expression, cast);
227 }
228
229 // Inference "casts":
230 if (expression is Literal) {
231 // fromT should be an exact type - this will almost certainly fail at
232 // runtime.
233 return new StaticTypeError(rules, expression, toT, reason: reason);
234 }
235 if (expression is FunctionExpression) {
236 // fromT should be an exact type - this will almost certainly fail at
237 // runtime.
238 return new UninferredClosure(rules, expression, cast);
239 }
240 if (expression is InstanceCreationExpression) {
241 // fromT should be an exact type - this will almost certainly fail at
242 // runtime.
243 return new StaticTypeError(rules, expression, toT, reason: reason);
244 }
245
246 // Composite cast: these are more likely to fail.
247 if (!rules.isGroundType(toT)) {
248 // This cast is (probably) due to our different treatment of dynamic.
249 // It may be more likely to fail at runtime.
250 return new DownCastComposite(rules, expression, cast);
251 }
252
253 // Dynamic cast
254 if (fromT.isDynamic) {
255 return new DynamicCast(rules, expression, cast);
256 }
257
258 // Assignment cast
259 var parent = expression.parent;
260 if (parent is VariableDeclaration && (parent.initializer == expression)) {
261 return new AssignmentCast(rules, expression, cast);
262 }
263
264 // Other casts
265 return new DownCastImplicit(rules, expression, cast);
266 }
267 }
268
269 //
270 // Standard down casts. These casts are implicitly injected by the compiler.
271 //
272
273 // A down cast from dynamic to T.
274 class DynamicCast extends DownCast {
275 DynamicCast(TypeRules rules, Expression expression, Cast cast)
276 : super._internal(rules, expression, cast);
277
278 toErrorCode() => new HintCode(name, message);
279 }
280
281 // A down cast due to a variable declaration to a ground type. E.g.,
282 // T x = expr;
283 // where T is ground. We exclude non-ground types as these behave differently
284 // compared to standard Dart.
285 class AssignmentCast extends DownCast {
286 AssignmentCast(TypeRules rules, Expression expression, Cast cast)
287 : super._internal(rules, expression, cast);
288
289 toErrorCode() => new HintCode(name, message);
290 }
291
292 //
293 // Temporary "casts" of allocation sites - literals, constructor invocations,
294 // and closures. These should be handled by contextual inference. In most
295 // cases, inference will be sufficient, though in some it may unmask an actual
296 // error: e.g.,
297 // List<int> l = [1, 2, 3]; // Inference succeeds
298 // List<String> l = [1, 2, 3]; // Inference reveals static type error
299 // We're marking all as warnings for now.
300 //
301 // TODO(vsm,leafp): Remove this.
302 class UninferredClosure extends DownCast {
303 UninferredClosure(TypeRules rules, FunctionExpression expression, Cast cast)
304 : super._internal(rules, expression, cast);
305
306 toErrorCode() => new StaticTypeWarningCode(name, message);
307 }
308
309 //
310 // Implicit down casts. These are only injected by the compiler by flag.
311 //
312
313 // A down cast to a non-ground type. These behave differently from standard
314 // Dart and may be more likely to fail at runtime.
315 class DownCastComposite extends DownCast {
316 DownCastComposite(TypeRules rules, Expression expression, Cast cast)
317 : super._internal(rules, expression, cast);
318
319 toErrorCode() => new StaticTypeWarningCode(name, message);
320 }
321
322 // A down cast to a non-ground type. These behave differently from standard
323 // Dart and may be more likely to fail at runtime.
324 class DownCastImplicit extends DownCast {
325 DownCastImplicit(TypeRules rules, Expression expression, Cast cast)
326 : super._internal(rules, expression, cast);
327
328 toErrorCode() => new HintCode(name, message);
329 }
330
331 // An inferred type for the wrapped expression, which may need to be
332 // reified into the term
333 abstract class InferredTypeBase extends CoercionInfo {
334 final DartType _type;
335
336 InferredTypeBase._internal(TypeRules rules, Expression expression, this._type)
337 : super(rules, expression);
338
339 DartType get type => _type;
340 DartType get convertedType => type;
341 @override String get message => '{0} has inferred type {1}';
342 @override List get arguments => [node, type];
343
344 toErrorCode() => new HintCode(name, message);
345 }
346
347 // Standard / unspecialized inferred type
348 class InferredType extends InferredTypeBase {
349 InferredType(TypeRules rules, Expression expression, DartType type)
350 : super._internal(rules, expression, type);
351
352 // Factory to create correct InferredType variant.
353 static InferredTypeBase create(
354 TypeRules rules, Expression expression, DartType type) {
355 // Specialized inference:
356 if (expression is Literal) {
357 return new InferredTypeLiteral(rules, expression, type);
358 }
359 if (expression is InstanceCreationExpression) {
360 return new InferredTypeAllocation(rules, expression, type);
361 }
362 if (expression is FunctionExpression) {
363 return new InferredTypeClosure(rules, expression, type);
364 }
365 return new InferredType(rules, expression, type);
366 }
367 }
368
369 // An infered type for a literal expression.
370 class InferredTypeLiteral extends InferredTypeBase {
371 InferredTypeLiteral(TypeRules rules, Expression expression, DartType type)
372 : super._internal(rules, expression, type);
373 }
374
375 // An inferred type for a non-literal allocation site.
376 class InferredTypeAllocation extends InferredTypeBase {
377 InferredTypeAllocation(TypeRules rules, Expression expression, DartType type)
378 : super._internal(rules, expression, type);
379 }
380
381 // An inferred type for a closure expression
382 class InferredTypeClosure extends InferredTypeBase {
383 InferredTypeClosure(TypeRules rules, Expression expression, DartType type)
384 : super._internal(rules, expression, type);
385 }
386
387 class DynamicInvoke extends CoercionInfo {
388 DynamicInvoke(TypeRules rules, Expression expression)
389 : super(rules, expression);
390
391 DartType get convertedType => rules.provider.dynamicType;
392 String get message => '{0} requires dynamic invoke';
393 toErrorCode() => new HintCode(name, message);
394
395 static const String _propertyName = 'dev_compiler.src.info.DynamicInvoke';
396
397 /// Whether this [node] is the target of a dynamic operation.
398 static bool get(AstNode node) {
399 var value = node.getProperty(_propertyName);
400 return value != null ? value : false;
401 }
402
403 /// Sets whether this node is the target of a dynamic operation.
404 static bool set(AstNode node, bool value) {
405 // Free the storage for things that aren't dynamic.
406 if (value == false) value = null;
407 node.setProperty(_propertyName, value);
408 return value;
409 }
410 }
411
412 abstract class StaticError extends StaticInfo {
413 final AstNode node;
414
415 StaticError(this.node);
416
417 String get message;
418
419 toErrorCode() => new CompileTimeErrorCode(name, message);
420 }
421
422 class StaticTypeError extends StaticError {
423 final DartType baseType;
424 final DartType expectedType;
425 String reason = null;
426
427 StaticTypeError(TypeRules rules, Expression expression, this.expectedType,
428 {this.reason})
429 : baseType = rules.getStaticType(expression),
430 super(expression);
431
432 @override List<Object> get arguments => [node, baseType, expectedType];
433 @override String get message =>
434 'Type check failed: {0} ({1}) is not of type {2}' +
435 ((reason == null) ? '' : ' because $reason');
436 }
437
438 class InvalidVariableDeclaration extends StaticError {
439 final DartType expectedType;
440
441 InvalidVariableDeclaration(
442 TypeRules rules, AstNode declaration, this.expectedType)
443 : super(declaration);
444
445 @override List<Object> get arguments => [expectedType];
446 @override String get message => 'Type check failed: null is not of type {0}';
447 }
448
449 class InvalidParameterDeclaration extends StaticError {
450 final DartType expectedType;
451
452 InvalidParameterDeclaration(
453 TypeRules rules, FormalParameter declaration, this.expectedType)
454 : super(declaration);
455
456 @override List<Object> get arguments => [node, expectedType];
457 @override String get message => 'Type check failed: {0} is not of type {1}';
458 }
459
460 class NonGroundTypeCheckInfo extends StaticInfo {
461 final DartType type;
462 final AstNode node;
463
464 NonGroundTypeCheckInfo(this.node, this.type) {
465 assert(node is IsExpression || node is AsExpression);
466 }
467
468 @override List<Object> get arguments => [type];
469 String get message =>
470 "Runtime check on non-ground type {0} may throw StrongModeError";
471
472 toErrorCode() => new HintCode(name, message);
473 }
474
475 // Invalid override of an instance member of a class.
476 abstract class InvalidOverride extends StaticError {
477 /// Member declaration with the invalid override.
478 final ExecutableElement element;
479
480 /// Type (class or interface) that provides the base declaration.
481 final InterfaceType base;
482
483 /// Actual type of the overridden member.
484 final DartType subType;
485
486 /// Actual type of the base member.
487 final DartType baseType;
488
489 /// Whether the error comes from combining a base class and an interface
490 final bool fromBaseClass;
491
492 /// Whether the error comes from a mixin (either overriding a base class or an
493 /// interface declaration).
494 final bool fromMixin;
495
496 InvalidOverride(
497 AstNode node, this.element, this.base, this.subType, this.baseType)
498 : fromBaseClass = node is ExtendsClause,
499 fromMixin = node.parent is WithClause,
500 super(node);
501
502 ClassElement get parent => element.enclosingElement;
503
504 @override List<Object> get arguments =>
505 [parent.name, element.name, subType, base, baseType];
506
507 String _messageHelper(String errorName) {
508 var lcErrorName = errorName.toLowerCase();
509 var intro = fromBaseClass
510 ? 'Base class introduces an $lcErrorName'
511 : (fromMixin ? 'Mixin introduces an $lcErrorName' : errorName);
512 return '$intro. The type of {0}.{1} ({2}) is not a '
513 'subtype of {3}.{1} ({4}).';
514 }
515 }
516
517 // Invalid override due to incompatible type. I.e., the overridden signature
518 // is not compatible with the original.
519 class InvalidMethodOverride extends InvalidOverride {
520 InvalidMethodOverride(AstNode node, ExecutableElement element,
521 InterfaceType base, FunctionType subType, FunctionType baseType)
522 : super(node, element, base, subType, baseType);
523
524 String get message => _messageHelper('Invalid override');
525 }
526
527 /// Used to mark unexpected situations in our compiler were we couldn't compute
528 /// the type of an expression.
529 // TODO(sigmund): This is normally a result of another error that is caught by
530 // the analyzer, so this should likely be removed in the future.
531 class MissingTypeError extends StaticInfo {
532 final AstNode node;
533 toErrorCode() => new StaticTypeWarningCode(name, message);
534
535 MissingTypeError(this.node);
536
537 @override List<Object> get arguments => [node, node.runtimeType];
538 String get message => "type analysis didn't compute the type of: {0} {1}";
539 }
540
541 /// Dart constructors have one weird quirk, illustrated with this example:
542 ///
543 /// class Base {
544 /// var x;
545 /// Base() : x = print('Base.1') {
546 /// print('Base.2');
547 /// }
548 /// }
549 ///
550 /// class Derived extends Base {
551 /// var y, z;
552 /// Derived()
553 /// : y = print('Derived.1'),
554 /// super(),
555 /// z = print('Derived.2') {
556 /// print('Derived.3');
557 /// }
558 /// }
559 ///
560 /// The order will be Derived.1, Base.1, Derived.2, Base.2, Derived.3; this
561 /// ordering preserves the invariant that code can't observe uninitialized
562 /// state, however it results in super constructor body not being run
563 /// immediately after super initializers. Normally this isn't observable, but it
564 /// could be if initializers have side effects.
565 ///
566 /// Better to have `super` at the end, as required by the Dart style guide:
567 /// <http://goo.gl/q1T4BB>
568 ///
569 /// For now this is the only pattern we support.
570 class InvalidSuperInvocation extends StaticError {
571 InvalidSuperInvocation(SuperConstructorInvocation node) : super(node);
572
573 @override String get message => "super call must be last in an initializer "
574 "list (see http://goo.gl/q1T4BB): {0}";
575 }
OLDNEW
« no previous file with comments | « lib/src/compiler.dart ('k') | lib/src/server/server.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698