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

Side by Side Diff: packages/analyzer/lib/src/task/strong/info.dart

Issue 1521693002: Roll Observatory deps (charted -> ^0.3.0) (Closed) Base URL: https://chromium.googlesource.com/external/github.com/dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years 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
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 /// Defines static information collected by the type checker and used later by
6 /// emitters to generate code.
7 // TODO(jmesserly): this was ported from package:dev_compiler, and needs to be
8 // refactored to fit into analyzer.
9 library analyzer.src.task.strong.info;
10
11 import 'package:analyzer/src/generated/ast.dart';
12 import 'package:analyzer/src/generated/element.dart';
13 import 'package:analyzer/src/generated/error.dart';
14
15 import 'rules.dart';
16
17 // The abstract type of coercions mapping one type to another.
18 // This class also exposes static builder functions which
19 // check for errors and reduce redundant coercions to the identity.
20 abstract class Coercion {
21 final DartType fromType;
22 final DartType toType;
23 Coercion(this.fromType, this.toType);
24 static Coercion cast(DartType fromT, DartType toT) => new Cast(fromT, toT);
25 static Coercion identity(DartType type) => new Identity(type);
26 static Coercion error() => new CoercionError();
27 }
28
29 // Coercion which casts one type to another
30 class Cast extends Coercion {
31 Cast(DartType fromType, DartType toType) : super(fromType, toType);
32 }
33
34 // The identity coercion
35 class Identity extends Coercion {
36 Identity(DartType fromType) : super(fromType, fromType);
37 }
38
39 // The error coercion. This coercion signals that a coercion
40 // could not be generated. The code generator should not see
41 // these.
42 class CoercionError extends Coercion {
43 CoercionError() : super(null, null);
44 }
45
46 // TODO(jmesserly): this could use some refactoring. These are essentially
47 // like ErrorCodes in analyzer, but we're including some details in our message.
48 // Analyzer instead has template strings, and replaces '{0}' with the first
49 // argument.
50 abstract class StaticInfo {
51 /// AST Node this info is attached to.
52 AstNode get node;
53
54 // TODO(jmesserly): review the usage of error codes. We probably want our own,
55 // as well as some DDC specific [ErrorType]s.
56 ErrorCode toErrorCode();
57
58 // TODO(jmesserly): what convention to use here?
59 String get name => 'dev_compiler.$runtimeType';
60
61 List<Object> get arguments => [node];
62
63 AnalysisError toAnalysisError() {
64 int begin = node is AnnotatedNode
65 ? (node as AnnotatedNode).firstTokenAfterCommentAndMetadata.offset
66 : node.offset;
67 int length = node.end - begin;
68 var source = (node.root as CompilationUnit).element.source;
69 return new AnalysisError(source, begin, length, toErrorCode(), arguments);
70 }
71 }
72
73 /// Implicitly injected expression conversion.
74 abstract class CoercionInfo extends StaticInfo {
75 final TypeRules rules;
76
77 final Expression node;
78
79 DartType get convertedType;
80
81 CoercionInfo(this.rules, this.node);
82
83 DartType get baseType => rules.getStaticType(node);
84 DartType get staticType => convertedType;
85
86 String get message;
87 toErrorCode() => new HintCode(name, message);
88
89 static const String _propertyName = 'dev_compiler.src.info.CoercionInfo';
90
91 /// Gets the coercion info associated with this node.
92 static CoercionInfo get(AstNode node) => node.getProperty(_propertyName);
93
94 /// Sets the coercion info associated with this node.
95 static CoercionInfo set(AstNode node, CoercionInfo info) {
96 node.setProperty(_propertyName, info);
97 return info;
98 }
99 }
100
101 // Base class for all casts from base type to sub type.
102 abstract class DownCast extends CoercionInfo {
103 Cast _cast;
104
105 DownCast._internal(TypeRules rules, Expression expression, this._cast)
106 : super(rules, expression) {
107 assert(_cast.toType != baseType &&
108 _cast.fromType == baseType &&
109 (baseType.isDynamic ||
110 // Call methods make the following non-redundant
111 _cast.toType.isSubtypeOf(baseType) ||
112 baseType.isAssignableTo(_cast.toType)));
113 }
114
115 Cast get cast => _cast;
116
117 DartType get convertedType => _cast.toType;
118
119 @override List<Object> get arguments => [node, baseType, convertedType];
120 @override String get message => '{0} ({1}) will need runtime check '
121 'to cast to type {2}';
122
123 // Factory to create correct DownCast variant.
124 static StaticInfo create(TypeRules rules, Expression expression, Cast cast,
125 {String reason}) {
126 final fromT = cast.fromType;
127 final toT = cast.toType;
128
129 // toT <:_R fromT => to <: fromT
130 // NB: classes with call methods are subtypes of function
131 // types, but the function type is not assignable to the class
132 assert(toT.isSubtypeOf(fromT) || fromT.isAssignableTo(toT));
133
134 // Handle null call specially.
135 if (expression is NullLiteral) {
136 // TODO(vsm): Create a NullCast for this once we revisit nonnullability.
137 return new DownCastImplicit(rules, expression, cast);
138 }
139
140 // Inference "casts":
141 if (expression is Literal) {
142 // fromT should be an exact type - this will almost certainly fail at
143 // runtime.
144 return new StaticTypeError(rules, expression, toT, reason: reason);
145 }
146 if (expression is FunctionExpression) {
147 // fromT should be an exact type - this will almost certainly fail at
148 // runtime.
149 return new UninferredClosure(rules, expression, cast);
150 }
151 if (expression is InstanceCreationExpression) {
152 // fromT should be an exact type - this will almost certainly fail at
153 // runtime.
154 return new StaticTypeError(rules, expression, toT, reason: reason);
155 }
156
157 // Composite cast: these are more likely to fail.
158 if (!rules.isGroundType(toT)) {
159 // This cast is (probably) due to our different treatment of dynamic.
160 // It may be more likely to fail at runtime.
161 return new DownCastComposite(rules, expression, cast);
162 }
163
164 // Dynamic cast
165 if (fromT.isDynamic) {
166 return new DynamicCast(rules, expression, cast);
167 }
168
169 // Assignment cast
170 var parent = expression.parent;
171 if (parent is VariableDeclaration && (parent.initializer == expression)) {
172 return new AssignmentCast(rules, expression, cast);
173 }
174
175 // Other casts
176 return new DownCastImplicit(rules, expression, cast);
177 }
178 }
179
180 //
181 // Standard down casts. These casts are implicitly injected by the compiler.
182 //
183
184 // A down cast from dynamic to T.
185 class DynamicCast extends DownCast {
186 DynamicCast(TypeRules rules, Expression expression, Cast cast)
187 : super._internal(rules, expression, cast);
188
189 toErrorCode() => new HintCode(name, message);
190 }
191
192 // A down cast due to a variable declaration to a ground type. E.g.,
193 // T x = expr;
194 // where T is ground. We exclude non-ground types as these behave differently
195 // compared to standard Dart.
196 class AssignmentCast extends DownCast {
197 AssignmentCast(TypeRules rules, Expression expression, Cast cast)
198 : super._internal(rules, expression, cast);
199
200 toErrorCode() => new HintCode(name, message);
201 }
202
203 //
204 // Temporary "casts" of allocation sites - literals, constructor invocations,
205 // and closures. These should be handled by contextual inference. In most
206 // cases, inference will be sufficient, though in some it may unmask an actual
207 // error: e.g.,
208 // List<int> l = [1, 2, 3]; // Inference succeeds
209 // List<String> l = [1, 2, 3]; // Inference reveals static type error
210 // We're marking all as warnings for now.
211 //
212 // TODO(vsm,leafp): Remove this.
213 class UninferredClosure extends DownCast {
214 UninferredClosure(TypeRules rules, FunctionExpression expression, Cast cast)
215 : super._internal(rules, expression, cast);
216
217 toErrorCode() => new StaticTypeWarningCode(name, message);
218 }
219
220 //
221 // Implicit down casts. These are only injected by the compiler by flag.
222 //
223
224 // A down cast to a non-ground type. These behave differently from standard
225 // Dart and may be more likely to fail at runtime.
226 class DownCastComposite extends DownCast {
227 DownCastComposite(TypeRules rules, Expression expression, Cast cast)
228 : super._internal(rules, expression, cast);
229
230 toErrorCode() => new StaticTypeWarningCode(name, message);
231 }
232
233 // A down cast to a non-ground type. These behave differently from standard
234 // Dart and may be more likely to fail at runtime.
235 class DownCastImplicit extends DownCast {
236 DownCastImplicit(TypeRules rules, Expression expression, Cast cast)
237 : super._internal(rules, expression, cast);
238
239 toErrorCode() => new HintCode(name, message);
240 }
241
242 // An inferred type for the wrapped expression, which may need to be
243 // reified into the term
244 abstract class InferredTypeBase extends CoercionInfo {
245 final DartType _type;
246
247 InferredTypeBase._internal(TypeRules rules, Expression expression, this._type)
248 : super(rules, expression);
249
250 DartType get type => _type;
251 DartType get convertedType => type;
252 @override String get message => '{0} has inferred type {1}';
253 @override List get arguments => [node, type];
254
255 toErrorCode() => new HintCode(name, message);
256 }
257
258 // Standard / unspecialized inferred type
259 class InferredType extends InferredTypeBase {
260 InferredType(TypeRules rules, Expression expression, DartType type)
261 : super._internal(rules, expression, type);
262
263 // Factory to create correct InferredType variant.
264 static InferredTypeBase create(
265 TypeRules rules, Expression expression, DartType type) {
266 // Specialized inference:
267 if (expression is Literal) {
268 return new InferredTypeLiteral(rules, expression, type);
269 }
270 if (expression is InstanceCreationExpression) {
271 return new InferredTypeAllocation(rules, expression, type);
272 }
273 if (expression is FunctionExpression) {
274 return new InferredTypeClosure(rules, expression, type);
275 }
276 return new InferredType(rules, expression, type);
277 }
278 }
279
280 // An infered type for a literal expression.
281 class InferredTypeLiteral extends InferredTypeBase {
282 InferredTypeLiteral(TypeRules rules, Expression expression, DartType type)
283 : super._internal(rules, expression, type);
284 }
285
286 // An inferred type for a non-literal allocation site.
287 class InferredTypeAllocation extends InferredTypeBase {
288 InferredTypeAllocation(TypeRules rules, Expression expression, DartType type)
289 : super._internal(rules, expression, type);
290 }
291
292 // An inferred type for a closure expression
293 class InferredTypeClosure extends InferredTypeBase {
294 InferredTypeClosure(TypeRules rules, Expression expression, DartType type)
295 : super._internal(rules, expression, type);
296 }
297
298 class DynamicInvoke extends CoercionInfo {
299 DynamicInvoke(TypeRules rules, Expression expression)
300 : super(rules, expression);
301
302 DartType get convertedType => rules.provider.dynamicType;
303 String get message => '{0} requires dynamic invoke';
304 toErrorCode() => new HintCode(name, message);
305
306 static const String _propertyName = 'dev_compiler.src.info.DynamicInvoke';
307
308 /// Whether this [node] is the target of a dynamic operation.
309 static bool get(AstNode node) {
310 var value = node.getProperty(_propertyName);
311 return value != null ? value : false;
312 }
313
314 /// Sets whether this node is the target of a dynamic operation.
315 static bool set(AstNode node, bool value) {
316 // Free the storage for things that aren't dynamic.
317 if (value == false) value = null;
318 node.setProperty(_propertyName, value);
319 return value;
320 }
321 }
322
323 abstract class StaticError extends StaticInfo {
324 final AstNode node;
325
326 StaticError(this.node);
327
328 String get message;
329
330 toErrorCode() => new CompileTimeErrorCode(name, message);
331 }
332
333 class StaticTypeError extends StaticError {
334 final DartType baseType;
335 final DartType expectedType;
336 String reason = null;
337
338 StaticTypeError(TypeRules rules, Expression expression, this.expectedType,
339 {this.reason})
340 : baseType = rules.getStaticType(expression),
341 super(expression);
342
343 @override List<Object> get arguments => [node, baseType, expectedType];
344 @override String get message =>
345 'Type check failed: {0} ({1}) is not of type {2}' +
346 ((reason == null) ? '' : ' because $reason');
347 }
348
349 class InvalidVariableDeclaration extends StaticError {
350 final DartType expectedType;
351
352 InvalidVariableDeclaration(
353 TypeRules rules, AstNode declaration, this.expectedType)
354 : super(declaration);
355
356 @override List<Object> get arguments => [expectedType];
357 @override String get message => 'Type check failed: null is not of type {0}';
358 }
359
360 class InvalidParameterDeclaration extends StaticError {
361 final DartType expectedType;
362
363 InvalidParameterDeclaration(
364 TypeRules rules, FormalParameter declaration, this.expectedType)
365 : super(declaration);
366
367 @override List<Object> get arguments => [node, expectedType];
368 @override String get message => 'Type check failed: {0} is not of type {1}';
369 }
370
371 class NonGroundTypeCheckInfo extends StaticInfo {
372 final DartType type;
373 final AstNode node;
374
375 NonGroundTypeCheckInfo(this.node, this.type) {
376 assert(node is IsExpression || node is AsExpression);
377 }
378
379 @override List<Object> get arguments => [type];
380 String get message =>
381 "Runtime check on non-ground type {0} may throw StrongModeError";
382
383 toErrorCode() => new HintCode(name, message);
384 }
385
386 // Invalid override of an instance member of a class.
387 abstract class InvalidOverride extends StaticError {
388 /// Member declaration with the invalid override.
389 final ExecutableElement element;
390
391 /// Type (class or interface) that provides the base declaration.
392 final InterfaceType base;
393
394 /// Actual type of the overridden member.
395 final DartType subType;
396
397 /// Actual type of the base member.
398 final DartType baseType;
399
400 /// Whether the error comes from combining a base class and an interface
401 final bool fromBaseClass;
402
403 /// Whether the error comes from a mixin (either overriding a base class or an
404 /// interface declaration).
405 final bool fromMixin;
406
407 InvalidOverride(
408 AstNode node, this.element, this.base, this.subType, this.baseType)
409 : fromBaseClass = node is ExtendsClause,
410 fromMixin = node.parent is WithClause,
411 super(node);
412
413 ClassElement get parent => element.enclosingElement;
414
415 @override List<Object> get arguments =>
416 [parent.name, element.name, subType, base, baseType];
417
418 String _messageHelper(String errorName) {
419 var lcErrorName = errorName.toLowerCase();
420 var intro = fromBaseClass
421 ? 'Base class introduces an $lcErrorName'
422 : (fromMixin ? 'Mixin introduces an $lcErrorName' : errorName);
423 return '$intro. The type of {0}.{1} ({2}) is not a '
424 'subtype of {3}.{1} ({4}).';
425 }
426 }
427
428 // Invalid override due to incompatible type. I.e., the overridden signature
429 // is not compatible with the original.
430 class InvalidMethodOverride extends InvalidOverride {
431 InvalidMethodOverride(AstNode node, ExecutableElement element,
432 InterfaceType base, FunctionType subType, FunctionType baseType)
433 : super(node, element, base, subType, baseType);
434
435 String get message => _messageHelper('Invalid override');
436 }
437
438 /// Dart constructors have one weird quirk, illustrated with this example:
439 ///
440 /// class Base {
441 /// var x;
442 /// Base() : x = print('Base.1') {
443 /// print('Base.2');
444 /// }
445 /// }
446 ///
447 /// class Derived extends Base {
448 /// var y, z;
449 /// Derived()
450 /// : y = print('Derived.1'),
451 /// super(),
452 /// z = print('Derived.2') {
453 /// print('Derived.3');
454 /// }
455 /// }
456 ///
457 /// The order will be Derived.1, Base.1, Derived.2, Base.2, Derived.3; this
458 /// ordering preserves the invariant that code can't observe uninitialized
459 /// state, however it results in super constructor body not being run
460 /// immediately after super initializers. Normally this isn't observable, but it
461 /// could be if initializers have side effects.
462 ///
463 /// Better to have `super` at the end, as required by the Dart style guide:
464 /// <http://goo.gl/q1T4BB>
465 ///
466 /// For now this is the only pattern we support.
467 class InvalidSuperInvocation extends StaticError {
468 InvalidSuperInvocation(SuperConstructorInvocation node) : super(node);
469
470 @override String get message => "super call must be last in an initializer "
471 "list (see http://goo.gl/q1T4BB): {0}";
472 }
OLDNEW
« no previous file with comments | « packages/analyzer/lib/src/task/strong/checker.dart ('k') | packages/analyzer/lib/src/task/strong/rules.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698