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

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

Issue 2761633002: Infer fields/getters/setters types according to the new top-level inference rules. (Closed)
Patch Set: Created 3 years, 9 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 | « no previous file | pkg/analyzer/test/generated/strong_mode_test.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 library analyzer.src.task.strong_mode; 5 library analyzer.src.task.strong_mode;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 8
9 import 'package:analyzer/dart/ast/ast.dart'; 9 import 'package:analyzer/dart/ast/ast.dart';
10 import 'package:analyzer/dart/ast/visitor.dart'; 10 import 'package:analyzer/dart/ast/visitor.dart';
(...skipping 11 matching lines...) Expand all
22 * Return `true` if the given [expression] is an immediately-evident expression, 22 * Return `true` if the given [expression] is an immediately-evident expression,
23 * so can be used to infer the type for a top-level variable or a class field. 23 * so can be used to infer the type for a top-level variable or a class field.
24 */ 24 */
25 bool isValidForTypeInference(Expression expression) { 25 bool isValidForTypeInference(Expression expression) {
26 var visitor = new _IsValidForTypeInferenceVisitor(); 26 var visitor = new _IsValidForTypeInferenceVisitor();
27 expression.accept(visitor); 27 expression.accept(visitor);
28 return visitor.isValid; 28 return visitor.isValid;
29 } 29 }
30 30
31 /** 31 /**
32 * Sets the type of the field. This is stored in the field itself, and the 32 * Sets the type of the field. The types in implicit accessors are updated
33 * synthetic getter/setter types. 33 * implicitly, and the types of explicit accessors should be updated separately.
34 */ 34 */
35 void setFieldType(VariableElement field, DartType newType) { 35 void setFieldType(VariableElement field, DartType newType) {
36 (field as VariableElementImpl).type = newType; 36 (field as VariableElementImpl).type = newType;
37 if (field.initializer != null) {
38 (field.initializer as ExecutableElementImpl).returnType = newType;
39 }
40 } 37 }
41 38
42 /** 39 /**
43 * Return the element for the single parameter of the given [setter], or `null`
44 * if the executable element is not a setter or does not have a single
45 * parameter.
46 */
47 ParameterElement _getParameter(ExecutableElement setter) {
48 if (setter is PropertyAccessorElement && setter.isSetter) {
49 List<ParameterElement> parameters = setter.parameters;
50 if (parameters.length == 1) {
51 return parameters[0];
52 }
53 }
54 return null;
55 }
56
57 /**
58 * A function that returns `true` if the given [element] passes the filter. 40 * A function that returns `true` if the given [element] passes the filter.
59 */ 41 */
60 typedef bool VariableFilter(VariableElement element); 42 typedef bool VariableFilter(VariableElement element);
61 43
62 /** 44 /**
63 * An object used to infer the type of instance fields and the return types of 45 * An object used to infer the type of instance fields and the return types of
64 * instance methods within a single compilation unit. 46 * instance methods within a single compilation unit.
65 */ 47 */
66 class InstanceMemberInferrer { 48 class InstanceMemberInferrer {
67 /** 49 /**
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
121 103
122 /** 104 /**
123 * Return `true` if the list of [elements] contains only methods. 105 * Return `true` if the list of [elements] contains only methods.
124 */ 106 */
125 bool _allSameElementKind( 107 bool _allSameElementKind(
126 ExecutableElement element, List<ExecutableElement> elements) { 108 ExecutableElement element, List<ExecutableElement> elements) {
127 return elements.every((e) => e.kind == element.kind); 109 return elements.every((e) => e.kind == element.kind);
128 } 110 }
129 111
130 /** 112 /**
113 * Compute the inferred type for the given property accessor [element]. The
114 * returned value is never `null`, but might be an error, and/or have the
115 * `null` type.
116 */
117 _FieldOverrideInferenceResult _computeFieldOverrideType(
118 ExecutableElement element) {
119 String name = element.displayName;
120
121 var overriddenElements = <ExecutableElement>[];
122 overriddenElements.addAll(
123 inheritanceManager.lookupOverrides(element.enclosingElement, name));
124 overriddenElements.addAll(
125 inheritanceManager.lookupOverrides(element.enclosingElement, '$name='));
126
127 bool isCovariant = false;
128 DartType impliedType;
129 for (ExecutableElement overriddenElement in overriddenElements) {
130 FunctionType overriddenType =
131 _toOverriddenFunctionType(element, overriddenElement);
132 if (overriddenType == null) {
133 return new _FieldOverrideInferenceResult(false, null, true);
134 }
135
136 DartType type;
137 if (overriddenElement.kind == ElementKind.GETTER) {
138 type = overriddenType.returnType;
139 } else if (overriddenElement.kind == ElementKind.SETTER) {
140 if (overriddenType.parameters.length == 1) {
141 ParameterElement parameter = overriddenType.parameters[0];
142 type = parameter.type;
143 isCovariant = isCovariant || parameter.isCovariant;
144 }
145 } else {
146 return new _FieldOverrideInferenceResult(false, null, true);
147 }
148
149 if (impliedType == null) {
150 impliedType = type;
151 } else if (type != impliedType) {
152 return new _FieldOverrideInferenceResult(false, null, true);
153 }
154 }
155
156 return new _FieldOverrideInferenceResult(isCovariant, impliedType, false);
157 }
158
159 /**
131 * Compute the best type for the [parameter] at the given [index] that must be 160 * Compute the best type for the [parameter] at the given [index] that must be
132 * compatible with the types of the corresponding parameters of the given 161 * compatible with the types of the corresponding parameters of the given
133 * [overriddenMethods]. 162 * [overriddenTypes].
134 * 163 *
135 * At the moment, this method will only return a type other than 'dynamic' if 164 * At the moment, this method will only return a type other than 'dynamic' if
136 * the types of all of the parameters are the same. In the future we might 165 * the types of all of the parameters are the same. In the future we might
137 * want to be smarter about it, such as by returning the least upper bound of 166 * want to be smarter about it, such as by returning the least upper bound of
138 * the parameter types. 167 * the parameter types.
139 */ 168 */
140 DartType _computeParameterType(ParameterElement parameter, int index, 169 DartType _computeParameterType(ParameterElement parameter, int index,
141 List<FunctionType> overriddenTypes) { 170 List<FunctionType> overriddenTypes) {
142 DartType parameterType = null; 171 DartType parameterType = null;
143 int length = overriddenTypes.length; 172 int length = overriddenTypes.length;
144 for (int i = 0; i < length; i++) { 173 for (int i = 0; i < length; i++) {
145 ParameterElement matchingParam = _getCorrespondingParameter( 174 ParameterElement matchingParameter = _getCorrespondingParameter(
146 parameter, index, overriddenTypes[i].parameters); 175 parameter, index, overriddenTypes[i].parameters);
147 var type = matchingParam?.type ?? typeProvider.dynamicType; 176 DartType type = matchingParameter?.type ?? typeProvider.dynamicType;
148 if (parameterType == null) { 177 if (parameterType == null) {
149 parameterType = type; 178 parameterType = type;
150 } else if (parameterType != type) { 179 } else if (parameterType != type) {
151 return typeProvider.dynamicType; 180 return typeProvider.dynamicType;
152 } 181 }
153 } 182 }
154 return parameterType ?? typeProvider.dynamicType; 183 return parameterType ?? typeProvider.dynamicType;
155 } 184 }
156 185
157 /** 186 /**
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
206 if (index < methodParameters.length) { 235 if (index < methodParameters.length) {
207 var matchingParameter = methodParameters[index]; 236 var matchingParameter = methodParameters[index];
208 if (matchingParameter.parameterKind != ParameterKind.NAMED) { 237 if (matchingParameter.parameterKind != ParameterKind.NAMED) {
209 return matchingParameter; 238 return matchingParameter;
210 } 239 }
211 } 240 }
212 return null; 241 return null;
213 } 242 }
214 243
215 /** 244 /**
245 * If the given [element] represents a non-synthetic instance property
246 * accessor for which no type was provided, infer its types.
247 */
248 void _inferAccessor(PropertyAccessorElement element) {
249 if (element.isSynthetic || element.isStatic) {
250 return;
251 }
252
253 if (element.kind == ElementKind.GETTER && !element.hasImplicitReturnType) {
254 return;
255 }
256
257 _FieldOverrideInferenceResult typeResult =
258 _computeFieldOverrideType(element);
259 if (typeResult.isError == null || typeResult.type == null) {
260 return;
261 }
262
263 if (element.kind == ElementKind.GETTER) {
264 (element as ExecutableElementImpl).returnType = typeResult.type;
265 } else if (element.kind == ElementKind.SETTER) {
266 var parameter = element.parameters[0] as ParameterElementImpl;
267 if (parameter.hasImplicitType) {
268 parameter.type = typeResult.type;
269 }
270 parameter.inheritsCovariant = typeResult.isCovariant;
271 }
272 setFieldType(element.variable, typeResult.type);
273 }
274
275 /**
216 * Infer type information for all of the instance members in the given 276 * Infer type information for all of the instance members in the given
217 * [classElement]. 277 * [classElement].
218 */ 278 */
219 void _inferClass(ClassElement classElement) { 279 void _inferClass(ClassElement classElement) {
220 if (classElement is ClassElementImpl) { 280 if (classElement is ClassElementImpl) {
221 if (classElement.hasBeenInferred) { 281 if (classElement.hasBeenInferred) {
222 return; 282 return;
223 } 283 }
224 if (!elementsBeingInferred.add(classElement)) { 284 if (!elementsBeingInferred.add(classElement)) {
225 // We have found a circularity in the class hierarchy. For now we just 285 // We have found a circularity in the class hierarchy. For now we just
226 // stop trying to infer any type information for any classes that 286 // stop trying to infer any type information for any classes that
227 // inherit from any class in the cycle. We could potentially limit the 287 // inherit from any class in the cycle. We could potentially limit the
228 // algorithm to only not inferring types in the classes in the cycle, 288 // algorithm to only not inferring types in the classes in the cycle,
229 // but it isn't clear that the results would be significantly better. 289 // but it isn't clear that the results would be significantly better.
230 throw new _CycleException(); 290 throw new _CycleException();
231 } 291 }
232 try { 292 try {
233 // 293 //
234 // Ensure that all of instance members in the supertypes have had types 294 // Ensure that all of instance members in the supertypes have had types
235 // inferred for them. 295 // inferred for them.
236 // 296 //
237 _inferType(classElement.supertype); 297 _inferType(classElement.supertype);
238 classElement.mixins.forEach(_inferType); 298 classElement.mixins.forEach(_inferType);
239 classElement.interfaces.forEach(_inferType); 299 classElement.interfaces.forEach(_inferType);
240 // 300 //
241 // Then infer the types for the members. 301 // Then infer the types for the members.
242 // 302 //
243 classElement.fields.forEach(_inferField); 303 classElement.fields.forEach(_inferField);
244 classElement.accessors.forEach(_inferExecutable); 304 classElement.accessors.forEach(_inferAccessor);
245 classElement.methods.forEach(_inferExecutable); 305 classElement.methods.forEach(_inferExecutable);
246 // 306 //
247 // Infer initializing formal parameter types. This must happen after 307 // Infer initializing formal parameter types. This must happen after
248 // field types are inferred. 308 // field types are inferred.
249 // 309 //
250 classElement.constructors.forEach(_inferConstructorFieldFormals); 310 classElement.constructors.forEach(_inferConstructorFieldFormals);
251 classElement.hasBeenInferred = true; 311 classElement.hasBeenInferred = true;
252 } finally { 312 } finally {
253 elementsBeingInferred.remove(classElement); 313 elementsBeingInferred.remove(classElement);
254 } 314 }
255 } 315 }
256 } 316 }
257 317
258 void _inferConstructorFieldFormals(ConstructorElement element) { 318 void _inferConstructorFieldFormals(ConstructorElement constructor) {
259 for (ParameterElement p in element.parameters) { 319 for (ParameterElement parameter in constructor.parameters) {
260 if (p is FieldFormalParameterElementImpl) { 320 if (parameter.hasImplicitType &&
261 _inferFieldFormalParameter(p); 321 parameter is FieldFormalParameterElementImpl) {
322 FieldElement field = parameter.field;
323 if (field != null) {
324 parameter.type = field.type;
325 }
262 } 326 }
263 } 327 }
264 } 328 }
265 329
266 /** 330 /**
267 * If the given [element] represents a non-synthetic instance method, 331 * If the given [element] represents a non-synthetic instance method,
268 * getter or setter, infer the return type and any parameter type(s) where 332 * getter or setter, infer the return type and any parameter type(s) where
269 * they were not provided. 333 * they were not provided.
270 */ 334 */
271 void _inferExecutable(ExecutableElement element) { 335 void _inferExecutable(ExecutableElement element) {
272 if (element.isSynthetic || element.isStatic) { 336 if (element.isSynthetic || element.isStatic) {
273 return; 337 return;
274 } 338 }
275 List<ExecutableElement> overriddenMethods = inheritanceManager 339 List<ExecutableElement> overriddenElements = inheritanceManager
276 .lookupOverrides(element.enclosingElement, element.name); 340 .lookupOverrides(element.enclosingElement, element.displayName);
277 if (overriddenMethods.isEmpty || 341 if (overriddenElements.isEmpty ||
278 !_allSameElementKind(element, overriddenMethods)) { 342 !_allSameElementKind(element, overriddenElements)) {
343 return;
344 }
345
346 List<FunctionType> overriddenTypes =
347 _toOverriddenFunctionTypes(element, overriddenElements);
348 if (overriddenTypes.isEmpty) {
279 return; 349 return;
280 } 350 }
281 351
282 // 352 //
283 // Overridden methods must have the same number of generic type parameters
284 // as this method, or none.
285 //
286 // If we do have generic type parameters on the element we're inferring,
287 // we must express its parameter and return types in terms of its own
288 // parameters. For example, given `m<T>(t)` overriding `m<S>(S s)` we
289 // should infer this as `m<T>(T t)`.
290 //
291 List<DartType> typeFormals =
292 TypeParameterTypeImpl.getTypes(element.type.typeFormals);
293
294 List<FunctionType> overriddenTypes = new List<FunctionType>();
295 for (ExecutableElement overriddenMethod in overriddenMethods) {
296 FunctionType overriddenType = overriddenMethod.type;
297 if (overriddenType == null) {
298 // TODO(brianwilkerson) I think the overridden method should always have
299 // a type, but there appears to be a bug that causes it to sometimes be
300 // null, we guard against that case by not performing inference.
301 return;
302 }
303 if (overriddenType.typeFormals.isNotEmpty) {
304 if (overriddenType.typeFormals.length != typeFormals.length) {
305 return;
306 }
307 overriddenType = overriddenType.instantiate(typeFormals);
308 }
309 overriddenTypes.add(overriddenType);
310 }
311
312 //
313 // Infer the return type. 353 // Infer the return type.
314 // 354 //
315 if (element.hasImplicitReturnType) { 355 if (element.hasImplicitReturnType) {
316 (element as ExecutableElementImpl).returnType = 356 (element as ExecutableElementImpl).returnType =
317 _computeReturnType(overriddenTypes.map((t) => t.returnType)); 357 _computeReturnType(overriddenTypes.map((t) => t.returnType));
318 if (element is PropertyAccessorElement) { 358 if (element is PropertyAccessorElement) {
319 _updateSyntheticVariableType(element); 359 _updateSyntheticVariableType(element);
320 } 360 }
321 } 361 }
322 // 362 //
(...skipping 10 matching lines...) Expand all
333 parameter.type = _computeParameterType(parameter, i, overriddenTypes); 373 parameter.type = _computeParameterType(parameter, i, overriddenTypes);
334 if (element is PropertyAccessorElement) { 374 if (element is PropertyAccessorElement) {
335 _updateSyntheticVariableType(element); 375 _updateSyntheticVariableType(element);
336 } 376 }
337 } 377 }
338 } 378 }
339 } 379 }
340 } 380 }
341 381
342 /** 382 /**
343 * If the given [fieldElement] represents a non-synthetic instance field for 383 * If the given [field] represents a non-synthetic instance field for
344 * which no type was provided, infer the type of the field. 384 * which no type was provided, infer the type of the field.
345 */ 385 */
346 void _inferField(FieldElement fieldElement) { 386 void _inferField(FieldElement field) {
347 if (fieldElement.isSynthetic || fieldElement.isStatic) { 387 if (field.isSynthetic || field.isStatic) {
348 return; 388 return;
349 } 389 }
350 List<ExecutableElement> overriddenSetters = 390
351 inheritanceManager.lookupOverrides( 391 _FieldOverrideInferenceResult typeResult =
352 fieldElement.enclosingElement, fieldElement.name + '='); 392 _computeFieldOverrideType(field.getter);
353 var setter = fieldElement.setter; 393 if (typeResult.isError) {
354 if (setter != null && overriddenSetters.isNotEmpty) { 394 return;
355 _inferParameterCovariance(
356 setter.parameters[0], 0, overriddenSetters.map((s) => s.type));
357 } 395 }
358 396
359 if (fieldElement.hasImplicitType) { 397 if (field.hasImplicitType) {
360 // 398 DartType newType = typeResult.type;
361 // First look for overridden getters with the same name as the field. 399 if (newType == null &&
362 // 400 field.initializer != null &&
363 List<ExecutableElement> overriddenGetters = inheritanceManager 401 !fieldsWithDisabledInitializerInference.contains(field)) {
364 .lookupOverrides(fieldElement.enclosingElement, fieldElement.name); 402 newType = field.initializer.returnType;
365 DartType newType = null; 403 }
366 if (overriddenGetters.isNotEmpty && _onlyGetters(overriddenGetters)) {
367 newType =
368 _computeReturnType(overriddenGetters.map((e) => e.returnType));
369 404
370 if (!_isCompatible(newType, overriddenSetters)) {
371 newType = null;
372 }
373 }
374 //
375 // If there is no overridden getter or if the overridden getter's type is
376 // dynamic, then we can infer the type from the initialization expression
377 // without breaking subtype rules. We could potentially infer a consistent
378 // return type even if the overridden getter's type was not dynamic, but
379 // choose not to for simplicity. The field is required to be final to
380 // prevent choosing a type that is inconsistent with assignments we cannot
381 // analyze.
382 //
383 if (newType == null || newType.isDynamic) {
384 FunctionElement initializer = fieldElement.initializer;
385 if (initializer != null &&
386 (fieldElement.isFinal || overriddenGetters.isEmpty)) {
387 if (!fieldsWithDisabledInitializerInference.contains(fieldElement)) {
388 newType = initializer.returnType;
389 }
390 }
391 }
392 if (newType == null || newType.isBottom || newType.isDartCoreNull) { 405 if (newType == null || newType.isBottom || newType.isDartCoreNull) {
393 newType = typeProvider.dynamicType; 406 newType = typeProvider.dynamicType;
394 } 407 }
395 setFieldType(fieldElement, newType); 408
409 setFieldType(field, newType);
410 }
411
412 if (field.setter != null) {
413 var parameter = field.setter.parameters[0] as ParameterElementImpl;
414 parameter.inheritsCovariant = typeResult.isCovariant;
396 } 415 }
397 } 416 }
398 417
399 void _inferFieldFormalParameter(FieldFormalParameterElementImpl element) {
400 FieldElement field = element.field;
401 if (field != null && element.hasImplicitType) {
402 element.type = field.type;
403 }
404 }
405
406 /** 418 /**
407 * If a parameter is covariant, any parameters that override it are too. 419 * If a parameter is covariant, any parameters that override it are too.
408 */ 420 */
409 void _inferParameterCovariance(ParameterElementImpl parameter, int index, 421 void _inferParameterCovariance(ParameterElementImpl parameter, int index,
410 Iterable<FunctionType> overriddenTypes) { 422 Iterable<FunctionType> overriddenTypes) {
411 parameter.inheritsCovariant = overriddenTypes.any((f) { 423 parameter.inheritsCovariant = overriddenTypes.any((f) {
412 var param = _getCorrespondingParameter(parameter, index, f.parameters); 424 var param = _getCorrespondingParameter(parameter, index, f.parameters);
413 return param != null && param.isCovariant; 425 return param != null && param.isCovariant;
414 }); 426 });
415 } 427 }
416 428
417 /** 429 /**
418 * Infer type information for all of the instance members in the given 430 * Infer type information for all of the instance members in the given
419 * interface [type]. 431 * interface [type].
420 */ 432 */
421 void _inferType(InterfaceType type) { 433 void _inferType(InterfaceType type) {
422 if (type != null) { 434 if (type != null) {
423 ClassElement element = type.element; 435 ClassElement element = type.element;
424 if (element != null) { 436 if (element != null) {
425 _inferClass(element); 437 _inferClass(element);
426 } 438 }
427 } 439 }
428 } 440 }
429 441
430 /** 442 /**
431 * Return `true` if the given [type] is compatible with the argument types of 443 * TODO
432 * all of the given [setters]. 444 *
445 * Return [FunctionType]s of the [overriddenElement] that [element] overrides.
446 * Return `null`, in case of type parameters inconsistency.
447 *
448 * Overridden elements must have the same number of generic type parameters
449 * as the target element, or none.
450 *
451 * If we do have generic type parameters on the element we're inferring,
452 * we must express its parameter and return types in terms of its own
453 * parameters. For example, given `m<T>(t)` overriding `m<S>(S s)` we
454 * should infer this as `m<T>(T t)`.
433 */ 455 */
434 bool _isCompatible(DartType type, List<ExecutableElement> setters) { 456 FunctionType _toOverriddenFunctionType(
435 for (ExecutableElement setter in setters) { 457 ExecutableElement element, ExecutableElement overriddenElement) {
436 ParameterElement parameter = _getParameter(setter); 458 List<DartType> typeFormals =
437 if (parameter != null && !typeSystem.isSubtypeOf(parameter.type, type)) { 459 TypeParameterTypeImpl.getTypes(element.type.typeFormals);
438 return false; 460
461 FunctionType overriddenType = overriddenElement.type;
462 if (overriddenType == null) {
463 // TODO(brianwilkerson) I think the overridden method should always have
464 // a type, but there appears to be a bug that causes it to sometimes be
465 // null, we guard against that case by not performing inference.
466 return null;
467 }
468 if (overriddenType.typeFormals.isNotEmpty) {
469 if (overriddenType.typeFormals.length != typeFormals.length) {
470 return null;
439 } 471 }
472 overriddenType = overriddenType.instantiate(typeFormals);
440 } 473 }
441 return true; 474 return overriddenType;
442 } 475 }
443 476
444 /** 477 /**
445 * Return `true` if the list of [elements] contains only getters. 478 * Return [FunctionType]s of [overriddenElements] that override [element].
479 * Return the empty list, in case of type parameters inconsistency.
446 */ 480 */
447 bool _onlyGetters(List<ExecutableElement> elements) { 481 List<FunctionType> _toOverriddenFunctionTypes(
448 for (ExecutableElement element in elements) { 482 ExecutableElement element, List<ExecutableElement> overriddenElements) {
449 if (!(element is PropertyAccessorElement && element.isGetter)) { 483 var overriddenTypes = <FunctionType>[];
450 return false; 484 for (ExecutableElement overriddenElement in overriddenElements) {
485 FunctionType overriddenType =
486 _toOverriddenFunctionType(element, overriddenElement);
487 if (overriddenType == null) {
488 return const <FunctionType>[];
451 } 489 }
490 overriddenTypes.add(overriddenType);
452 } 491 }
453 return true; 492 return overriddenTypes;
454 } 493 }
455 494
456 /** 495 /**
457 * If the given [element] is a non-synthetic getter or setter, update its 496 * If the given [element] is a non-synthetic getter or setter, update its
458 * synthetic variable's type to match the getter's return type, or if no 497 * synthetic variable's type to match the getter's return type, or if no
459 * corresponding getter exists, use the setter's parameter type. 498 * corresponding getter exists, use the setter's parameter type.
460 * 499 *
461 * In general, the type of the synthetic variable should not be used, because 500 * In general, the type of the synthetic variable should not be used, because
462 * getters and setters are independent methods. But this logic matches what 501 * getters and setters are independent methods. But this logic matches what
463 * `TypeResolverVisitor.visitMethodDeclaration` would fill in there. 502 * `TypeResolverVisitor.visitMethodDeclaration` would fill in there.
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
508 void visitSimpleIdentifier(SimpleIdentifier node) { 547 void visitSimpleIdentifier(SimpleIdentifier node) {
509 if (!node.inDeclarationContext()) { 548 if (!node.inDeclarationContext()) {
510 Element nonAccessor(Element element) { 549 Element nonAccessor(Element element) {
511 if (element is PropertyAccessorElement && element.isSynthetic) { 550 if (element is PropertyAccessorElement && element.isSynthetic) {
512 return element.variable; 551 return element.variable;
513 } 552 }
514 return element; 553 return element;
515 } 554 }
516 555
517 Element element = nonAccessor(node.staticElement); 556 Element element = nonAccessor(node.staticElement);
518 if (element is VariableElement) { 557 if (element is VariableElement && (filter == null || filter(element))) {
519 if (filter == null || filter(element)) { 558 results.add(element);
520 results.add(element);
521 }
522 } 559 }
523 } 560 }
524 } 561 }
525 } 562 }
526 563
527 /** 564 /**
528 * A class of exception that is not used anywhere else. 565 * A class of exception that is not used anywhere else.
529 */ 566 */
530 class _CycleException implements Exception {} 567 class _CycleException implements Exception {}
531 568
532 /** 569 /**
570 * The result of field type inference.
571 */
572 class _FieldOverrideInferenceResult {
573 final bool isCovariant;
574 final DartType type;
575 final bool isError;
576
577 _FieldOverrideInferenceResult(this.isCovariant, this.type, this.isError);
578 }
579
580 /**
533 * The visitor for [isValidForTypeInference]. 581 * The visitor for [isValidForTypeInference].
534 */ 582 */
535 class _IsValidForTypeInferenceVisitor extends RecursiveAstVisitor { 583 class _IsValidForTypeInferenceVisitor extends RecursiveAstVisitor {
536 bool isValid = true; 584 bool isValid = true;
537 585
538 @override 586 @override
539 void visitAssignmentExpression(AssignmentExpression node) { 587 void visitAssignmentExpression(AssignmentExpression node) {
540 isValid = false; 588 isValid = false;
541 } 589 }
542 590
543 @override 591 @override
544 void visitCascadeExpression(CascadeExpression node) { 592 void visitCascadeExpression(CascadeExpression node) {
545 node.target.accept(this); 593 node.target.accept(this);
546 } 594 }
547 595
548 @override 596 @override
549 void visitSimpleIdentifier(SimpleIdentifier node) { 597 void visitSimpleIdentifier(SimpleIdentifier node) {
550 Element element = node.staticElement; 598 Element element = node.staticElement;
551 if (element == null) { 599 if (element == null) {
552 AstNode parent = node.parent; 600 AstNode parent = node.parent;
553 if (parent is PropertyAccess && parent.propertyName == node || 601 if (parent is PropertyAccess && parent.propertyName == node ||
554 parent is PrefixedIdentifier && parent.identifier == node) { 602 parent is PrefixedIdentifier && parent.identifier == node) {
555 isValid = false; 603 isValid = false;
556 } 604 }
557 } else if (element is PropertyAccessorElement && !element.isStatic) { 605 } else if (element is PropertyAccessorElement && !element.isStatic) {
558 isValid = false; 606 isValid = false;
559 } 607 }
560 } 608 }
561 } 609 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/test/generated/strong_mode_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698