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

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

Issue 1359243003: Infer setter parameter types in strong mode (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: 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 | « no previous file | pkg/analyzer/test/src/task/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/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';
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
224 } 224 }
225 // 225 //
226 // Then return the type of the parameter. 226 // Then return the type of the parameter.
227 // 227 //
228 return matchingParameter == null 228 return matchingParameter == null
229 ? typeProvider.dynamicType 229 ? typeProvider.dynamicType
230 : matchingParameter.type; 230 : matchingParameter.type;
231 } 231 }
232 232
233 /** 233 /**
234 * If the given [accessorElement] represents a non-synthetic instance getter
235 * for which no return type was provided, infer the return type of the getter.
236 */
237 void _inferAccessor(PropertyAccessorElement accessorElement) {
238 if (!accessorElement.isSynthetic &&
239 accessorElement.isGetter &&
240 !accessorElement.isStatic &&
241 accessorElement.hasImplicitReturnType) {
242 List<ExecutableElement> overriddenGetters = inheritanceManager
243 .lookupOverrides(
244 accessorElement.enclosingElement, accessorElement.name);
245 if (overriddenGetters.isNotEmpty && _onlyGetters(overriddenGetters)) {
246 DartType newType = _computeReturnType(overriddenGetters);
247 List<ExecutableElement> overriddenSetters = inheritanceManager
248 .lookupOverrides(
249 accessorElement.enclosingElement, accessorElement.name + '=');
250 PropertyAccessorElement setter = (accessorElement.enclosingElement
251 as ClassElement).getSetter(accessorElement.name);
252 if (setter != null) {
253 overriddenSetters.add(setter);
254 }
255 if (!_isCompatible(newType, overriddenSetters)) {
256 newType = typeProvider.dynamicType;
257 }
258 setReturnType(accessorElement, newType);
259 (accessorElement.variable as FieldElementImpl).type = newType;
260 }
261 }
262 }
263
264 /**
265 * Infer type information for all of the instance members in the given 234 * Infer type information for all of the instance members in the given
266 * [classElement]. 235 * [classElement].
267 */ 236 */
268 void _inferClass(ClassElement classElement) { 237 void _inferClass(ClassElement classElement) {
269 if (classElement is ClassElementImpl) { 238 if (classElement is ClassElementImpl) {
270 if (classElement.hasBeenInferred) { 239 if (classElement.hasBeenInferred) {
271 return; 240 return;
272 } 241 }
273 if (!elementsBeingInferred.add(classElement)) { 242 if (!elementsBeingInferred.add(classElement)) {
274 // We have found a circularity in the class hierarchy. For now we just 243 // We have found a circularity in the class hierarchy. For now we just
275 // stop trying to infer any type information for any classes that 244 // stop trying to infer any type information for any classes that
276 // inherit from any class in the cycle. We could potentially limit the 245 // inherit from any class in the cycle. We could potentially limit the
277 // algorithm to only not inferring types in the classes in the cycle, 246 // algorithm to only not inferring types in the classes in the cycle,
278 // but it isn't clear that the results would be significantly better. 247 // but it isn't clear that the results would be significantly better.
279 throw new _CycleException(); 248 throw new _CycleException();
280 } 249 }
281 try { 250 try {
282 // 251 //
283 // Ensure that all of instance members in the supertypes have had types 252 // Ensure that all of instance members in the supertypes have had types
284 // inferred for them. 253 // inferred for them.
285 // 254 //
286 _inferType(classElement.supertype); 255 _inferType(classElement.supertype);
287 classElement.mixins.forEach(_inferType); 256 classElement.mixins.forEach(_inferType);
288 classElement.interfaces.forEach(_inferType); 257 classElement.interfaces.forEach(_inferType);
289 // 258 //
290 // Then infer the types for the members. 259 // Then infer the types for the members.
291 // 260 //
292 classElement.fields.forEach(_inferField); 261 classElement.fields.forEach(_inferField);
293 classElement.accessors.forEach(_inferAccessor); 262 classElement.accessors.forEach(_inferExecutable);
294 classElement.methods.forEach(_inferMethod); 263 classElement.methods.forEach(_inferExecutable);
295 classElement.hasBeenInferred = true; 264 classElement.hasBeenInferred = true;
296 } finally { 265 } finally {
297 elementsBeingInferred.remove(classElement); 266 elementsBeingInferred.remove(classElement);
298 } 267 }
299 } 268 }
300 } 269 }
301 270
302 /** 271 /**
303 * If the given [fieldElement] represents a non-synthetic instance field for 272 * If the given [fieldElement] represents a non-synthetic instance field for
304 * which no type was provided, infer the type of the field. 273 * which no type was provided, infer the type of the field.
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
337 } 306 }
338 (fieldElement as FieldElementImpl).type = newType; 307 (fieldElement as FieldElementImpl).type = newType;
339 setReturnType(fieldElement.getter, newType); 308 setReturnType(fieldElement.getter, newType);
340 if (!fieldElement.isFinal && !fieldElement.isConst) { 309 if (!fieldElement.isFinal && !fieldElement.isConst) {
341 setParameterType(fieldElement.setter, newType); 310 setParameterType(fieldElement.setter, newType);
342 } 311 }
343 } 312 }
344 } 313 }
345 314
346 /** 315 /**
347 * If the given [methodElement] represents a non-synthetic instance method 316 * If the given [element] represents a non-synthetic instance method,
348 * for which no return type was provided, infer the return type of the method. 317 * getter or setter, infer the return type and any parameter type(s) where
318 * they were not provided.
349 */ 319 */
350 void _inferMethod(MethodElement methodElement) { 320 void _inferExecutable(ExecutableElement element) {
351 if (methodElement.isSynthetic || methodElement.isStatic) { 321 if (element.isSynthetic || element.isStatic) {
352 return; 322 return;
353 } 323 }
354 List<ExecutableElement> overriddenMethods = null; 324 List<ExecutableElement> overriddenMethods = null;
355 // 325 //
356 // Infer the return type. 326 // Infer the return type.
357 // 327 //
358 if (methodElement.hasImplicitReturnType) { 328 if (element.hasImplicitReturnType) {
359 overriddenMethods = inheritanceManager.lookupOverrides( 329 overriddenMethods = inheritanceManager.lookupOverrides(
360 methodElement.enclosingElement, methodElement.name); 330 element.enclosingElement, element.name);
361 if (overriddenMethods.isEmpty || !_onlyMethods(overriddenMethods)) { 331 if (overriddenMethods.isEmpty ||
332 !_allSameElementKind(element, overriddenMethods)) {
362 return; 333 return;
363 } 334 }
364 MethodElementImpl element = methodElement as MethodElementImpl;
365 setReturnType(element, _computeReturnType(overriddenMethods)); 335 setReturnType(element, _computeReturnType(overriddenMethods));
336 if (element is PropertyAccessorElement) {
337 _updateSyntheticVariableType(element);
338 }
366 } 339 }
367 // 340 //
368 // Infer the parameter types. 341 // Infer the parameter types.
369 // 342 //
370 List<ParameterElement> parameters = methodElement.parameters; 343 List<ParameterElement> parameters = element.parameters;
371 int length = parameters.length; 344 int length = parameters.length;
372 for (int i = 0; i < length; ++i) { 345 for (int i = 0; i < length; ++i) {
373 ParameterElement parameter = parameters[i]; 346 ParameterElement parameter = parameters[i];
374 if (parameter is ParameterElementImpl && parameter.hasImplicitType) { 347 if (parameter is ParameterElementImpl && parameter.hasImplicitType) {
375 if (overriddenMethods == null) { 348 if (overriddenMethods == null) {
376 overriddenMethods = inheritanceManager.lookupOverrides( 349 overriddenMethods = inheritanceManager.lookupOverrides(
377 methodElement.enclosingElement, methodElement.name); 350 element.enclosingElement, element.name);
378 } 351 }
379 if (overriddenMethods.isEmpty || !_onlyMethods(overriddenMethods)) { 352 if (overriddenMethods.isEmpty ||
353 !_allSameElementKind(element, overriddenMethods)) {
380 return; 354 return;
381 } 355 }
382 parameter.type = _computeParameterType(parameter, i, overriddenMethods); 356 parameter.type = _computeParameterType(parameter, i, overriddenMethods);
357 if (element is PropertyAccessorElement) {
358 _updateSyntheticVariableType(element);
359 }
383 } 360 }
384 } 361 }
385 } 362 }
386 363
387 /** 364 /**
365 * If the given [element] is a non-synthetic getter or setter, update its
366 * synthetic variable's type to match the getter's return type, or if no
367 * corresponding getter exists, use the setter's parameter type.
368 *
369 * In general, the type of the synthetic variable should not be used, because
370 * getters and setters are independent methods. But this logic matches what
371 * `TypeResolverVisitor.visitMethodDeclaration` would fill in there.
372 */
373 void _updateSyntheticVariableType(PropertyAccessorElement element) {
374 assert(!element.isSynthetic);
375 PropertyAccessorElement getter = element;
376 if (element.isSetter) {
377 // See if we can find any getter.
378 getter = element.correspondingGetter;
379 }
380 DartType newType;
381 if (getter != null) {
382 newType = getter.returnType;
383 } else if (element.isSetter && element.parameters.isNotEmpty) {
384 newType = element.parameters[0].type;
385 }
386 if (newType != null) {
387 (element.variable as VariableElementImpl).type = newType;
388 }
389 }
390
391 /**
388 * Infer type information for all of the instance members in the given 392 * Infer type information for all of the instance members in the given
389 * interface [type]. 393 * interface [type].
390 */ 394 */
391 void _inferType(InterfaceType type) { 395 void _inferType(InterfaceType type) {
392 if (type != null) { 396 if (type != null) {
393 ClassElement element = type.element; 397 ClassElement element = type.element;
394 if (element != null) { 398 if (element != null) {
395 _inferClass(element); 399 _inferClass(element);
396 } 400 }
397 } 401 }
(...skipping 21 matching lines...) Expand all
419 if (!(element is PropertyAccessorElement && element.isGetter)) { 423 if (!(element is PropertyAccessorElement && element.isGetter)) {
420 return false; 424 return false;
421 } 425 }
422 } 426 }
423 return true; 427 return true;
424 } 428 }
425 429
426 /** 430 /**
427 * Return `true` if the list of [elements] contains only methods. 431 * Return `true` if the list of [elements] contains only methods.
428 */ 432 */
429 bool _onlyMethods(List<ExecutableElement> elements) { 433 bool _allSameElementKind(
430 for (ExecutableElement element in elements) { 434 ExecutableElement element, List<ExecutableElement> elements) {
431 if (element is! MethodElement) { 435 return elements.every((e) => e.kind == element.kind);
432 return false;
433 }
434 }
435 return true;
436 } 436 }
437 } 437 }
438 438
439 /** 439 /**
440 * A visitor that will gather all of the variables referenced within a given 440 * A visitor that will gather all of the variables referenced within a given
441 * AST structure. The collection can be restricted to contain only those 441 * AST structure. The collection can be restricted to contain only those
442 * variables that pass a specified filter. 442 * variables that pass a specified filter.
443 */ 443 */
444 class VariableGatherer extends RecursiveAstVisitor { 444 class VariableGatherer extends RecursiveAstVisitor {
445 /** 445 /**
(...skipping 24 matching lines...) Expand all
470 results.add(element); 470 results.add(element);
471 } 471 }
472 } 472 }
473 } 473 }
474 } 474 }
475 475
476 /** 476 /**
477 * A class of exception that is not used anywhere else. 477 * A class of exception that is not used anywhere else.
478 */ 478 */
479 class _CycleException implements Exception {} 479 class _CycleException implements Exception {}
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/test/src/task/strong_mode_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698