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

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

Issue 2054443002: Add analysis option that will be used to fix #26583 (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 6 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
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 // TODO(jmesserly): this was ported from package:dev_compiler, and needs to be 7 // TODO(jmesserly): this was ported from package:dev_compiler, and needs to be
8 // refactored to fit into analyzer. 8 // refactored to fit into analyzer.
9 library analyzer.src.task.strong.info; 9 library analyzer.src.task.strong.info;
10 10
11 import 'package:analyzer/dart/ast/ast.dart'; 11 import 'package:analyzer/dart/ast/ast.dart';
12 import 'package:analyzer/dart/element/element.dart'; 12 import 'package:analyzer/dart/element/element.dart';
13 import 'package:analyzer/dart/element/type.dart'; 13 import 'package:analyzer/dart/element/type.dart';
14 import 'package:analyzer/src/dart/element/type.dart'; 14 import 'package:analyzer/src/dart/element/type.dart';
15 import 'package:analyzer/src/generated/error.dart'; 15 import 'package:analyzer/src/generated/error.dart';
16 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
16 import 'package:analyzer/src/generated/type_system.dart'; 17 import 'package:analyzer/src/generated/type_system.dart';
17 18
18 /// A down cast due to a variable declaration to a ground type:
19 ///
20 /// T x = expr;
21 ///
22 /// where `T` is ground. We exclude non-ground types as these behave
23 /// differently compared to standard Dart.
24 class AssignmentCast extends DownCast {
25 AssignmentCast(TypeSystem rules, Expression expression, DartType fromType,
26 DartType toType)
27 : super._internal(rules, expression, fromType, toType);
28
29 @override
30 String get name => 'STRONG_MODE_ASSIGNMENT_CAST';
31
32 toErrorCode() => new HintCode(name, message);
33 }
34
35 /// Implicitly injected expression conversion. 19 /// Implicitly injected expression conversion.
36 abstract class CoercionInfo extends StaticInfo { 20 abstract class CoercionInfo extends StaticInfo {
37 static const String _propertyName = 'dev_compiler.src.info.CoercionInfo'; 21 static const String _propertyName = 'dev_compiler.src.info.CoercionInfo';
38 22
39 final TypeSystem rules;
40
41 final Expression node; 23 final Expression node;
42 24
43 CoercionInfo(this.rules, this.node); 25 CoercionInfo(this.node);
44 26
45 DartType get baseType => node.staticType ?? DynamicTypeImpl.instance; 27 DartType get baseType => node.staticType ?? DynamicTypeImpl.instance;
46 DartType get convertedType; 28 DartType get convertedType;
47 29
48 String get message; 30 String get message;
49 DartType get staticType => convertedType; 31 DartType get staticType => convertedType;
50 32
51 toErrorCode() => new HintCode(name, message); 33 toErrorCode() => new HintCode(name, message);
52 34
53 /// Gets the coercion info associated with this node. 35 /// Gets the coercion info associated with this node.
54 static CoercionInfo get(AstNode node) => node.getProperty(_propertyName); 36 static CoercionInfo get(AstNode node) => node.getProperty(_propertyName);
55 37
56 /// Sets the coercion info associated with this node. 38 /// Sets the coercion info associated with this node.
57 static CoercionInfo set(AstNode node, CoercionInfo info) { 39 static CoercionInfo set(AstNode node, CoercionInfo info) {
58 node.setProperty(_propertyName, info); 40 node.setProperty(_propertyName, info);
59 return info; 41 return info;
60 } 42 }
61 } 43 }
62 44
63 /// Base class for all casts from base type to sub type. 45 /// Implicit casts from base type to sub type.
64 abstract class DownCast extends CoercionInfo { 46 class DownCast extends CoercionInfo {
65 final DartType _fromType; 47 final DartType _fromType;
66 final DartType _toType; 48 final DartType _toType;
49 ErrorCode _errorCode;
67 50
68 DownCast._internal( 51 DownCast._(
69 TypeSystem rules, Expression expression, this._fromType, this._toType) 52 Expression expression, this._fromType, this._toType, this._errorCode)
70 : super(rules, expression); 53 : super(expression);
71 54
72 @override 55 @override
73 List<Object> get arguments => [baseType, convertedType]; 56 List<Object> get arguments => [baseType, convertedType];
74 57
75 /// The type being cast from. 58 /// The type being cast from.
76 /// 59 ///
77 /// This is usually the static type of the associated expression, but may not 60 /// This is usually the static type of the associated expression, but may not
78 /// be if the cast is attached to a variable in a for-in loop. 61 /// be if the cast is attached to a variable in a for-in loop.
79 @override 62 @override
80 DartType get baseType => _fromType; 63 DartType get baseType => _fromType;
81 64
65 @override
82 DartType get convertedType => _toType; 66 DartType get convertedType => _toType;
83 67
84 @override 68 @override
85 String get message => 'Unsound implicit cast from {0} to {1}'; 69 String get message => _message;
70
71 @override
72 String get name => _errorCode.name;
73
74 @override
75 toErrorCode() => _errorCode;
76
77 static const String _message = 'Unsound implicit cast from {0} to {1}';
86 78
87 /// Factory to create correct DownCast variant. 79 /// Factory to create correct DownCast variant.
88 static StaticInfo create(StrongTypeSystemImpl rules, Expression expression, 80 static StaticInfo create(StrongTypeSystemImpl rules, Expression expression,
89 DartType fromType, DartType toType) { 81 DartType fromType, DartType toType, AnalysisOptionsImpl options) {
90 // toT <:_R fromT => to <: fromT 82 // toT <:_R fromT => to <: fromT
91 // NB: classes with call methods are subtypes of function 83 // NB: classes with call methods are subtypes of function
92 // types, but the function type is not assignable to the class 84 // types, but the function type is not assignable to the class
93 assert(toType.isSubtypeOf(fromType) || fromType.isAssignableTo(toType)); 85 assert(toType.isSubtypeOf(fromType) || fromType.isAssignableTo(toType));
94 86
95 // Inference "casts": 87 // Inference "casts":
96 if (expression is Literal || expression is FunctionExpression) { 88 if (expression is Literal || expression is FunctionExpression) {
97 // fromT should be an exact type - this will almost certainly fail at 89 // fromT should be an exact type - this will almost certainly fail at
98 // runtime. 90 // runtime.
99 return new StaticTypeError(rules, expression, toType); 91 return new StaticTypeError(expression, toType);
100 } 92 }
101 93
102 if (expression is InstanceCreationExpression) { 94 if (expression is InstanceCreationExpression) {
103 ConstructorElement e = expression.staticElement; 95 ConstructorElement e = expression.staticElement;
104 if (e == null || !e.isFactory) { 96 if (e == null || !e.isFactory) {
105 // fromT should be an exact type - this will almost certainly fail at 97 // fromT should be an exact type - this will almost certainly fail at
106 // runtime. 98 // runtime.
107 return new StaticTypeError(rules, expression, toType); 99 return new StaticTypeError(expression, toType);
108 } 100 }
109 } 101 }
110 102
111 if (StaticInfo.isKnownFunction(expression)) { 103 if (StaticInfo.isKnownFunction(expression)) {
112 return new StaticTypeError(rules, expression, toType); 104 return new StaticTypeError(expression, toType);
113 } 105 }
114 106
115 // TODO(vsm): Change this to an assert when we have generic methods and 107 // TODO(vsm): Change this to an assert when we have generic methods and
116 // fix TypeRules._coerceTo to disallow implicit sideways casts. 108 // fix TypeRules._coerceTo to disallow implicit sideways casts.
109 bool downCastComposite = false;
117 if (!rules.isSubtypeOf(toType, fromType)) { 110 if (!rules.isSubtypeOf(toType, fromType)) {
118 assert(toType.isSubtypeOf(fromType) || fromType.isAssignableTo(toType)); 111 assert(toType.isSubtypeOf(fromType) || fromType.isAssignableTo(toType));
119 return new DownCastComposite(rules, expression, fromType, toType); 112 downCastComposite = true;
120 } 113 }
121 114
122 // Composite cast: these are more likely to fail. 115 // Composite cast: these are more likely to fail.
123 if (!rules.isGroundType(toType)) { 116 if (!rules.isGroundType(toType)) {
124 // This cast is (probably) due to our different treatment of dynamic. 117 // This cast is (probably) due to our different treatment of dynamic.
125 // It may be more likely to fail at runtime. 118 // It may be more likely to fail at runtime.
126 if (fromType is InterfaceType) { 119 if (fromType is InterfaceType) {
127 // For class types, we'd like to allow non-generic down casts, e.g., 120 // For class types, we'd like to allow non-generic down casts, e.g.,
128 // Iterable<T> to List<T>. The intuition here is that raw (generic) 121 // Iterable<T> to List<T>. The intuition here is that raw (generic)
129 // casts are problematic, and we should complain about those. 122 // casts are problematic, and we should complain about those.
130 var typeArgs = fromType.typeArguments; 123 var typeArgs = fromType.typeArguments;
131 if (typeArgs.isEmpty || typeArgs.any((t) => t.isDynamic)) { 124 downCastComposite =
132 return new DownCastComposite(rules, expression, fromType, toType); 125 typeArgs.isEmpty || typeArgs.any((t) => t.isDynamic);
133 }
134 } else { 126 } else {
135 return new DownCastComposite(rules, expression, fromType, toType); 127 downCastComposite = true;
136 } 128 }
137 } 129 }
138 130
139 // Dynamic cast 131 var parent = expression.parent;
140 if (fromType.isDynamic) { 132 String name;
141 return new DynamicCast(rules, expression, fromType, toType); 133 if (downCastComposite) {
134 name = 'STRONG_MODE_DOWN_CAST_COMPOSITE';
135 } else if (fromType.isDynamic) {
136 name = 'STRONG_MODE_DYNAMIC_CAST';
137 } else if (parent is VariableDeclaration &&
138 parent.initializer == expression) {
139 name = 'STRONG_MODE_ASSIGNMENT_CAST';
140 } else {
141 name = 'STRONG_MODE_DOWN_CAST_IMPLICIT';
142 } 142 }
143 143
144 // Assignment cast 144 // For the remaining cases, we allow implicit casts by default.
145 var parent = expression.parent; 145 // However this can be disabled with an option.
146 if (parent is VariableDeclaration && (parent.initializer == expression)) { 146 ErrorCode errorCode;
147 return new AssignmentCast(rules, expression, fromType, toType); 147 if (!options.implicitCasts) {
148 errorCode = new CompileTimeErrorCode(name, _message);
149 } else if (downCastComposite) {
150 errorCode = new StaticWarningCode(name, _message);
151 } else {
152 errorCode = new HintCode(name, _message);
148 } 153 }
149 154 return new DownCast._(expression, fromType, toType, errorCode);
150 // Other casts
151 return new DownCastImplicit(rules, expression, fromType, toType);
152 } 155 }
153 } 156 }
154 157
155 /// Implicit down casts. These are only injected by the compiler by flag.
156 ///
157 /// A down cast to a non-ground type. These behave differently from standard
158 /// Dart and may be more likely to fail at runtime.
159 class DownCastComposite extends DownCast {
160 DownCastComposite(TypeSystem rules, Expression expression, DartType fromType,
161 DartType toType)
162 : super._internal(rules, expression, fromType, toType);
163
164 @override
165 String get name => 'STRONG_MODE_DOWN_CAST_COMPOSITE';
166
167 toErrorCode() => new StaticWarningCode(name, message);
168 }
169
170 /// A down cast to a non-ground type. These behave differently from standard
171 /// Dart and may be more likely to fail at runtime.
172 class DownCastImplicit extends DownCast {
173 DownCastImplicit(TypeSystem rules, Expression expression, DartType fromType,
174 DartType toType)
175 : super._internal(rules, expression, fromType, toType);
176
177 @override
178 String get name => 'STRONG_MODE_DOWN_CAST_IMPLICIT';
179
180 toErrorCode() => new HintCode(name, message);
181 }
182
183 /// A down cast from dynamic to T.
184 class DynamicCast extends DownCast {
185 DynamicCast(TypeSystem rules, Expression expression, DartType fromType,
186 DartType toType)
187 : super._internal(rules, expression, fromType, toType);
188
189 @override
190 String get name => 'STRONG_MODE_DYNAMIC_CAST';
191
192 toErrorCode() => new HintCode(name, message);
193 }
194
195 class DynamicInvoke extends CoercionInfo { 158 class DynamicInvoke extends CoercionInfo {
196 static const String _propertyName = 'dev_compiler.src.info.DynamicInvoke'; 159 static const String _propertyName = 'dev_compiler.src.info.DynamicInvoke';
197 160
198 DynamicInvoke(TypeSystem rules, Expression expression) 161 DynamicInvoke(Expression expression) : super(expression);
199 : super(rules, expression);
200 DartType get convertedType => DynamicTypeImpl.instance; 162 DartType get convertedType => DynamicTypeImpl.instance;
201 String get message => '{0} requires dynamic invoke'; 163 String get message => '{0} requires dynamic invoke';
202 164
203 @override 165 @override
204 String get name => 'STRONG_MODE_DYNAMIC_INVOKE'; 166 String get name => 'STRONG_MODE_DYNAMIC_INVOKE';
205 167
206 toErrorCode() => new HintCode(name, message); 168 toErrorCode() => new HintCode(name, message);
207 169
208 /// Whether this [node] is the target of a dynamic operation. 170 /// Whether this [node] is the target of a dynamic operation.
209 static bool get(AstNode node) => node.getProperty(_propertyName) ?? false; 171 static bool get(AstNode node) => node.getProperty(_propertyName) ?? false;
210 172
211 /// Sets whether this node is the target of a dynamic operation. 173 /// Sets whether this node is the target of a dynamic operation.
212 static bool set(AstNode node, bool value) { 174 static bool set(AstNode node, bool value) {
213 // Free the storage for things that aren't dynamic. 175 // Free the storage for things that aren't dynamic.
214 if (value == false) value = null; 176 if (value == false) value = null;
215 node.setProperty(_propertyName, value); 177 node.setProperty(_propertyName, value);
216 return value; 178 return value;
217 } 179 }
218 } 180 }
219 181
220 /// Standard / unspecialized inferred type. 182 /// A marker for an inferred type.
221 class InferredType extends InferredTypeBase { 183 class InferredType extends CoercionInfo {
222 InferredType(TypeSystem rules, Expression expression, DartType type) 184 @override
223 : super._internal(rules, expression, type); 185 final String name;
224 186
225 @override 187 final DartType type;
226 String get name => 'STRONG_MODE_INFERRED_TYPE'; 188
189 InferredType(Expression expression, this.type, this.name) : super(expression);
227 190
228 /// Factory to create correct InferredType variant. 191 /// Factory to create correct InferredType variant.
229 static InferredTypeBase create( 192 static InferredType create(
230 TypeSystem rules, Expression expression, DartType type) { 193 TypeSystem rules, Expression expression, DartType type) {
231 // Specialized inference: 194 // Specialized inference:
195 String name;
232 if (expression is Literal) { 196 if (expression is Literal) {
233 return new InferredTypeLiteral(rules, expression, type); 197 name = 'STRONG_MODE_INFERRED_TYPE_LITERAL';
198 } else if (expression is InstanceCreationExpression) {
199 name = 'STRONG_MODE_INFERRED_TYPE_ALLOCATION';
200 } else if (expression is FunctionExpression) {
201 name = 'STRONG_MODE_INFERRED_TYPE_CLOSURE';
202 } else {
203 name = 'STRONG_MODE_INFERRED_TYPE';
234 } 204 }
235 if (expression is InstanceCreationExpression) { 205 return new InferredType(expression, type, name);
236 return new InferredTypeAllocation(rules, expression, type);
237 }
238 if (expression is FunctionExpression) {
239 return new InferredTypeClosure(rules, expression, type);
240 }
241 return new InferredType(rules, expression, type);
242 } 206 }
243 }
244
245 /// An inferred type for a non-literal allocation site.
246 class InferredTypeAllocation extends InferredTypeBase {
247 InferredTypeAllocation(TypeSystem rules, Expression expression, DartType type)
248 : super._internal(rules, expression, type);
249
250 @override
251 String get name => 'STRONG_MODE_INFERRED_TYPE_ALLOCATION';
252 }
253
254 /// An inferred type for the wrapped expression, which may need to be
255 /// reified into the term.
256 abstract class InferredTypeBase extends CoercionInfo {
257 final DartType _type;
258
259 InferredTypeBase._internal(
260 TypeSystem rules, Expression expression, this._type)
261 : super(rules, expression);
262 207
263 @override 208 @override
264 List get arguments => [node, type]; 209 List get arguments => [node, type];
210
265 DartType get convertedType => type; 211 DartType get convertedType => type;
212
266 @override 213 @override
267 String get message => '{0} has inferred type {1}'; 214 String get message => '{0} has inferred type {1}';
268 DartType get type => _type;
269 215
270 toErrorCode() => new HintCode(name, message); 216 toErrorCode() => new HintCode(name, message);
271 } 217 }
272 218
273 /// An inferred type for a closure expression.
274 class InferredTypeClosure extends InferredTypeBase {
275 InferredTypeClosure(TypeSystem rules, Expression expression, DartType type)
276 : super._internal(rules, expression, type);
277
278 @override
279 String get name => 'STRONG_MODE_INFERRED_TYPE_CLOSURE';
280 }
281
282 /// An inferred type for a literal expression.
283 class InferredTypeLiteral extends InferredTypeBase {
284 InferredTypeLiteral(TypeSystem rules, Expression expression, DartType type)
285 : super._internal(rules, expression, type);
286
287 @override
288 String get name => 'STRONG_MODE_INFERRED_TYPE_LITERAL';
289 }
290
291 class InvalidFieldOverride extends InvalidOverride { 219 class InvalidFieldOverride extends InvalidOverride {
292 InvalidFieldOverride(AstNode node, ExecutableElement element, 220 InvalidFieldOverride(AstNode node, ExecutableElement element,
293 InterfaceType base, DartType subType, DartType baseType) 221 InterfaceType base, DartType subType, DartType baseType)
294 : super(node, element, base, subType, baseType); 222 : super(node, element, base, subType, baseType);
295 223
296 String get message => 'Field declaration {3}.{1} cannot be ' 224 String get message => 'Field declaration {3}.{1} cannot be '
297 'overridden in {0}.'; 225 'overridden in {0}.';
298 226
299 @override 227 @override
300 String get name => 'STRONG_MODE_INVALID_FIELD_OVERRIDE'; 228 String get name => 'STRONG_MODE_INVALID_FIELD_OVERRIDE';
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after
477 'STRONG_MODE_INFERRED_TYPE_ALLOCATION', 405 'STRONG_MODE_INFERRED_TYPE_ALLOCATION',
478 'STRONG_MODE_INFERRED_TYPE_CLOSURE', 406 'STRONG_MODE_INFERRED_TYPE_CLOSURE',
479 'STRONG_MODE_INFERRED_TYPE_LITERAL', 407 'STRONG_MODE_INFERRED_TYPE_LITERAL',
480 'STRONG_MODE_INVALID_FIELD_OVERRIDE', 408 'STRONG_MODE_INVALID_FIELD_OVERRIDE',
481 'STRONG_MODE_INVALID_METHOD_OVERRIDE', 409 'STRONG_MODE_INVALID_METHOD_OVERRIDE',
482 'STRONG_MODE_INVALID_PARAMETER_DECLARATION', 410 'STRONG_MODE_INVALID_PARAMETER_DECLARATION',
483 'STRONG_MODE_INVALID_SUPER_INVOCATION', 411 'STRONG_MODE_INVALID_SUPER_INVOCATION',
484 'STRONG_MODE_INVALID_VARIABLE_DECLARATION', 412 'STRONG_MODE_INVALID_VARIABLE_DECLARATION',
485 'STRONG_MODE_NON_GROUND_TYPE_CHECK_INFO', 413 'STRONG_MODE_NON_GROUND_TYPE_CHECK_INFO',
486 'STRONG_MODE_STATIC_TYPE_ERROR', 414 'STRONG_MODE_STATIC_TYPE_ERROR',
487 'STRONG_MODE_UNINFERRED_CLOSURE',
488 ]; 415 ];
489 416
490 List<Object> get arguments => [node]; 417 List<Object> get arguments => [node];
491 418
492 String get name; 419 String get name;
493 420
494 /// AST Node this info is attached to. 421 /// AST Node this info is attached to.
495 AstNode get node; 422 AstNode get node;
496 423
497 AnalysisError toAnalysisError() { 424 AnalysisError toAnalysisError() {
(...skipping 22 matching lines...) Expand all
520 // declaration, will have an exact type, so we know a downcast will fail. 447 // declaration, will have an exact type, so we know a downcast will fail.
521 return element is FunctionElement || 448 return element is FunctionElement ||
522 element is MethodElement && element.isStatic; 449 element is MethodElement && element.isStatic;
523 } 450 }
524 } 451 }
525 452
526 class StaticTypeError extends StaticError { 453 class StaticTypeError extends StaticError {
527 final DartType baseType; 454 final DartType baseType;
528 final DartType expectedType; 455 final DartType expectedType;
529 456
530 StaticTypeError(TypeSystem rules, Expression expression, this.expectedType) 457 StaticTypeError(Expression expression, this.expectedType)
531 : baseType = expression.staticType ?? DynamicTypeImpl.instance, 458 : baseType = expression.staticType ?? DynamicTypeImpl.instance,
532 super(expression); 459 super(expression);
533 460
534 @override 461 @override
535 List<Object> get arguments => [node, baseType, expectedType]; 462 List<Object> get arguments => [node, baseType, expectedType];
536 @override 463 @override
537 String get message => 'Type check failed: {0} ({1}) is not of type {2}'; 464 String get message => 'Type check failed: {0} ({1}) is not of type {2}';
538 465
539 @override 466 @override
540 String get name => 'STRONG_MODE_STATIC_TYPE_ERROR'; 467 String get name => 'STRONG_MODE_STATIC_TYPE_ERROR';
541 } 468 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/task/strong/checker.dart ('k') | pkg/analyzer/test/src/task/strong/checker_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698