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

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

Issue 1668683002: fixes #25668, correctly infer generic method override (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 10 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/src/task/strong/inferred_type_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';
11 import 'package:analyzer/dart/element/element.dart'; 11 import 'package:analyzer/dart/element/element.dart';
12 import 'package:analyzer/dart/element/type.dart'; 12 import 'package:analyzer/dart/element/type.dart';
13 import 'package:analyzer/src/dart/element/element.dart'; 13 import 'package:analyzer/src/dart/element/element.dart';
14 import 'package:analyzer/src/generated/resolver.dart' 14 import 'package:analyzer/src/generated/resolver.dart'
15 show TypeProvider, InheritanceManager; 15 show TypeProvider, InheritanceManager;
16 import 'package:analyzer/src/generated/type_system.dart'; 16 import 'package:analyzer/src/generated/type_system.dart';
17 import 'package:analyzer/src/generated/utilities_dart.dart'; 17 import 'package:analyzer/src/generated/utilities_dart.dart';
18 import 'package:analyzer/src/dart/element/type.dart';
18 19
19 /** 20 /**
20 * Sets the type of the field. This is stored in the field itself, and the 21 * Sets the type of the field. This is stored in the field itself, and the
21 * synthetic getter/setter types. 22 * synthetic getter/setter types.
22 */ 23 */
23 void setFieldType(VariableElement field, DartType newType) { 24 void setFieldType(VariableElement field, DartType newType) {
24 (field as VariableElementImpl).type = newType; 25 (field as VariableElementImpl).type = newType;
25 if (field.initializer != null) { 26 if (field.initializer != null) {
26 (field.initializer as ExecutableElementImpl).returnType = newType; 27 (field.initializer as ExecutableElementImpl).returnType = newType;
27 } 28 }
28 if (field is PropertyInducingElementImpl) { 29 if (field is PropertyInducingElementImpl) {
29 (field.getter as ExecutableElementImpl).returnType = newType; 30 (field.getter as ExecutableElementImpl).returnType = newType;
30 if (!field.isFinal && !field.isConst) { 31 if (!field.isFinal && !field.isConst) {
31 (field.setter.parameters[0] as ParameterElementImpl).type = 32 (field.setter.parameters[0] as ParameterElementImpl).type = newType;
32 newType;
33 } 33 }
34 } 34 }
35 } 35 }
36 36
37 /** 37 /**
38 * Return the element for the single parameter of the given [setter], or `null` 38 * Return the element for the single parameter of the given [setter], or `null`
39 * if the executable element is not a setter or does not have a single 39 * if the executable element is not a setter or does not have a single
40 * parameter. 40 * parameter.
41 */ 41 */
42 ParameterElement _getParameter(ExecutableElement setter) { 42 ParameterElement _getParameter(ExecutableElement setter) {
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 * Compute the best type for the [parameter] at the given [index] that must be 115 * Compute the best type for the [parameter] at the given [index] that must be
116 * compatible with the types of the corresponding parameters of the given 116 * compatible with the types of the corresponding parameters of the given
117 * [overriddenMethods]. 117 * [overriddenMethods].
118 * 118 *
119 * At the moment, this method will only return a type other than 'dynamic' if 119 * At the moment, this method will only return a type other than 'dynamic' if
120 * the types of all of the parameters are the same. In the future we might 120 * the types of all of the parameters are the same. In the future we might
121 * want to be smarter about it, such as by returning the least upper bound of 121 * want to be smarter about it, such as by returning the least upper bound of
122 * the parameter types. 122 * the parameter types.
123 */ 123 */
124 DartType _computeParameterType(ParameterElement parameter, int index, 124 DartType _computeParameterType(ParameterElement parameter, int index,
125 List<ExecutableElement> overriddenMethods) { 125 List<FunctionType> overriddenTypes) {
126 DartType parameterType = null; 126 DartType parameterType = null;
127 int length = overriddenMethods.length; 127 int length = overriddenTypes.length;
128 for (int i = 0; i < length; i++) { 128 for (int i = 0; i < length; i++) {
129 DartType type = _getTypeOfCorrespondingParameter( 129 DartType type = _getTypeOfCorrespondingParameter(
130 parameter, index, overriddenMethods[i]); 130 parameter, index, overriddenTypes[i].parameters);
131 if (parameterType == null) { 131 if (parameterType == null) {
132 parameterType = type; 132 parameterType = type;
133 } else if (parameterType != type) { 133 } else if (parameterType != type) {
134 return typeProvider.dynamicType; 134 return typeProvider.dynamicType;
135 } 135 }
136 } 136 }
137 return parameterType == null ? typeProvider.dynamicType : parameterType; 137 return parameterType ?? typeProvider.dynamicType;
138 } 138 }
139 139
140 /** 140 /**
141 * Compute the best return type for a method that must be compatible with the 141 * Compute the best return type for a method that must be compatible with the
142 * return types of each of the given [overriddenMethods]. 142 * return types of each of the given [overriddenTypes].
vsm 2016/02/03 23:16:15 s/overriddenTypes/overriddenReturnTypes/ to match
Jennifer Messerly 2016/02/04 18:18:51 Done.
143 * 143 *
144 * At the moment, this method will only return a type other than 'dynamic' if 144 * At the moment, this method will only return a type other than 'dynamic' if
145 * the return types of all of the methods are the same. In the future we might 145 * the return types of all of the methods are the same. In the future we might
146 * want to be smarter about it. 146 * want to be smarter about it.
147 */ 147 */
148 DartType _computeReturnType(List<ExecutableElement> overriddenMethods) { 148 DartType _computeReturnType(Iterable<DartType> overriddenReturnTypes) {
149 DartType returnType = null; 149 DartType returnType = null;
150 int length = overriddenMethods.length; 150 for (DartType type in overriddenReturnTypes) {
151 for (int i = 0; i < length; i++) { 151 if (type == null) {
152 DartType type = _getReturnType(overriddenMethods[i]); 152 type = typeProvider.dynamicType;
153 }
153 if (returnType == null) { 154 if (returnType == null) {
154 returnType = type; 155 returnType = type;
155 } else if (returnType != type) { 156 } else if (returnType != type) {
156 return typeProvider.dynamicType; 157 return typeProvider.dynamicType;
157 } 158 }
158 } 159 }
159 return returnType == null ? typeProvider.dynamicType : returnType; 160 return returnType ?? typeProvider.dynamicType;
160 }
161
162 DartType _getReturnType(ExecutableElement element) {
163 DartType returnType = element.returnType;
164 if (returnType == null) {
165 return typeProvider.dynamicType;
166 }
167 return returnType;
168 } 161 }
169 162
170 /** 163 /**
171 * Given a [method], return the type of the parameter in the method that 164 * Given a [method], return the type of the parameter in the method that
172 * corresponds to the given [parameter]. If the parameter is positional, then 165 * corresponds to the given [parameter]. If the parameter is positional, then
173 * it appears at the given [index] in its enclosing element's list of 166 * it appears at the given [index] in its enclosing element's list of
174 * parameters. 167 * parameters.
175 */ 168 */
176 DartType _getTypeOfCorrespondingParameter( 169 DartType _getTypeOfCorrespondingParameter(ParameterElement parameter,
177 ParameterElement parameter, int index, ExecutableElement method) { 170 int index, List<ParameterElement> methodParameters) {
178 // 171 //
179 // Find the corresponding parameter. 172 // Find the corresponding parameter.
180 // 173 //
181 List<ParameterElement> methodParameters = method.parameters;
182 ParameterElement matchingParameter = null; 174 ParameterElement matchingParameter = null;
183 if (parameter.parameterKind == ParameterKind.NAMED) { 175 if (parameter.parameterKind == ParameterKind.NAMED) {
184 // 176 //
185 // If we're looking for a named parameter, only a named parameter with 177 // If we're looking for a named parameter, only a named parameter with
186 // the same name will be matched. 178 // the same name will be matched.
187 // 179 //
188 matchingParameter = methodParameters.lastWhere( 180 matchingParameter = methodParameters.lastWhere(
189 (ParameterElement methodParameter) => 181 (ParameterElement methodParameter) =>
190 methodParameter.parameterKind == ParameterKind.NAMED && 182 methodParameter.parameterKind == ParameterKind.NAMED &&
191 methodParameter.name == parameter.name, 183 methodParameter.name == parameter.name,
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
263 255
264 /** 256 /**
265 * If the given [element] represents a non-synthetic instance method, 257 * If the given [element] represents a non-synthetic instance method,
266 * getter or setter, infer the return type and any parameter type(s) where 258 * getter or setter, infer the return type and any parameter type(s) where
267 * they were not provided. 259 * they were not provided.
268 */ 260 */
269 void _inferExecutable(ExecutableElement element) { 261 void _inferExecutable(ExecutableElement element) {
270 if (element.isSynthetic || element.isStatic) { 262 if (element.isSynthetic || element.isStatic) {
271 return; 263 return;
272 } 264 }
273 List<ExecutableElement> overriddenMethods = null; 265 List<ExecutableElement> overriddenMethods = inheritanceManager
266 .lookupOverrides(element.enclosingElement, element.name);
267 if (overriddenMethods.isEmpty ||
268 !_allSameElementKind(element, overriddenMethods)) {
269 return;
270 }
271
272 //
273 // Overridden methods must have the same number of generic type parameters
274 // as this method, or none.
275 //
276 // If we do have generic type parameters on the element we're inferring,
277 // we must express its parameter and return types in terms of its own
278 // parameters. For example, given `m<T>(t)` overriding `m<S>(S s)` we
279 // should infer this as `m<T>(T t)`.
280 //
281 List<DartType> typeFormals =
282 TypeParameterTypeImpl.getTypes(element.type.typeFormals);
283
284 List<FunctionType> overriddenTypes = new List<FunctionType>();
285 for (ExecutableElement overriddenMethod in overriddenMethods) {
286 FunctionType overriddenType = overriddenMethod.type;
287 if (overriddenType.typeFormals.isNotEmpty &&
288 overriddenType.typeFormals.length != typeFormals.length) {
289 return;
290 }
291 overriddenTypes.add(overriddenType.instantiate(typeFormals));
292 }
293
274 // 294 //
275 // Infer the return type. 295 // Infer the return type.
276 // 296 //
277 if (element.hasImplicitReturnType) { 297 if (element.hasImplicitReturnType) {
278 overriddenMethods = inheritanceManager.lookupOverrides(
279 element.enclosingElement, element.name);
280 if (overriddenMethods.isEmpty ||
281 !_allSameElementKind(element, overriddenMethods)) {
282 return;
283 }
284 (element as ExecutableElementImpl).returnType = 298 (element as ExecutableElementImpl).returnType =
285 _computeReturnType(overriddenMethods); 299 _computeReturnType(overriddenTypes.map((t) => t.returnType));
286 if (element is PropertyAccessorElement) { 300 if (element is PropertyAccessorElement) {
287 _updateSyntheticVariableType(element); 301 _updateSyntheticVariableType(element);
288 } 302 }
289 } 303 }
290 // 304 //
291 // Infer the parameter types. 305 // Infer the parameter types.
292 // 306 //
293 List<ParameterElement> parameters = element.parameters; 307 List<ParameterElement> parameters = element.parameters;
294 int length = parameters.length; 308 int length = parameters.length;
295 for (int i = 0; i < length; ++i) { 309 for (int i = 0; i < length; ++i) {
296 ParameterElement parameter = parameters[i]; 310 ParameterElement parameter = parameters[i];
297 if (parameter is ParameterElementImpl && parameter.hasImplicitType) { 311 if (parameter is ParameterElementImpl && parameter.hasImplicitType) {
298 if (overriddenMethods == null) { 312 parameter.type = _computeParameterType(parameter, i, overriddenTypes);
299 overriddenMethods = inheritanceManager.lookupOverrides(
300 element.enclosingElement, element.name);
301 }
302 if (overriddenMethods.isEmpty ||
303 !_allSameElementKind(element, overriddenMethods)) {
304 return;
305 }
306 parameter.type = _computeParameterType(parameter, i, overriddenMethods);
307 if (element is PropertyAccessorElement) { 313 if (element is PropertyAccessorElement) {
308 _updateSyntheticVariableType(element); 314 _updateSyntheticVariableType(element);
309 } 315 }
310 } 316 }
311 } 317 }
312 } 318 }
313 319
314 /** 320 /**
315 * If the given [fieldElement] represents a non-synthetic instance field for 321 * If the given [fieldElement] represents a non-synthetic instance field for
316 * which no type was provided, infer the type of the field. 322 * which no type was provided, infer the type of the field.
317 */ 323 */
318 void _inferField(FieldElement fieldElement) { 324 void _inferField(FieldElement fieldElement) {
319 if (!fieldElement.isSynthetic && 325 if (!fieldElement.isSynthetic &&
320 !fieldElement.isStatic && 326 !fieldElement.isStatic &&
321 fieldElement.hasImplicitType) { 327 fieldElement.hasImplicitType) {
322 // 328 //
323 // First look for overridden getters with the same name as the field. 329 // First look for overridden getters with the same name as the field.
324 // 330 //
325 List<ExecutableElement> overriddenGetters = inheritanceManager 331 List<ExecutableElement> overriddenGetters = inheritanceManager
326 .lookupOverrides(fieldElement.enclosingElement, fieldElement.name); 332 .lookupOverrides(fieldElement.enclosingElement, fieldElement.name);
327 DartType newType = null; 333 DartType newType = null;
328 if (overriddenGetters.isNotEmpty && _onlyGetters(overriddenGetters)) { 334 if (overriddenGetters.isNotEmpty && _onlyGetters(overriddenGetters)) {
329 newType = _computeReturnType(overriddenGetters); 335 newType =
336 _computeReturnType(overriddenGetters.map((e) => e.returnType));
330 List<ExecutableElement> overriddenSetters = 337 List<ExecutableElement> overriddenSetters =
331 inheritanceManager.lookupOverrides( 338 inheritanceManager.lookupOverrides(
332 fieldElement.enclosingElement, fieldElement.name + '='); 339 fieldElement.enclosingElement, fieldElement.name + '=');
333 if (!_isCompatible(newType, overriddenSetters)) { 340 if (!_isCompatible(newType, overriddenSetters)) {
334 newType = null; 341 newType = null;
335 } 342 }
336 } 343 }
337 // 344 //
338 // If there is no overridden getter or if the overridden getter's type is 345 // If there is no overridden getter or if the overridden getter's type is
339 // dynamic, then we can infer the type from the initialization expression 346 // dynamic, then we can infer the type from the initialization expression
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
464 results.add(element); 471 results.add(element);
465 } 472 }
466 } 473 }
467 } 474 }
468 } 475 }
469 476
470 /** 477 /**
471 * A class of exception that is not used anywhere else. 478 * A class of exception that is not used anywhere else.
472 */ 479 */
473 class _CycleException implements Exception {} 480 class _CycleException implements Exception {}
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/test/src/task/strong/inferred_type_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698