OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 dart2js.typechecker; | 5 library dart2js.typechecker; |
6 | 6 |
7 import 'common.dart'; | 7 import 'common.dart'; |
8 import 'common/names.dart' show | 8 import 'common/names.dart' show Identifiers; |
9 Identifiers; | 9 import 'common/resolution.dart' show Resolution; |
10 import 'common/resolution.dart' show | 10 import 'common/tasks.dart' show CompilerTask; |
11 Resolution; | 11 import 'compiler.dart' show Compiler; |
12 import 'common/tasks.dart' show | |
13 CompilerTask; | |
14 import 'compiler.dart' show | |
15 Compiler; | |
16 import 'constants/expressions.dart'; | 12 import 'constants/expressions.dart'; |
17 import 'constants/values.dart'; | 13 import 'constants/values.dart'; |
18 import 'core_types.dart'; | 14 import 'core_types.dart'; |
19 import 'dart_types.dart'; | 15 import 'dart_types.dart'; |
20 import 'elements/elements.dart' show | 16 import 'elements/elements.dart' |
21 AbstractFieldElement, | 17 show |
22 AstElement, | 18 AbstractFieldElement, |
23 AsyncMarker, | 19 AstElement, |
24 ClassElement, | 20 AsyncMarker, |
25 ConstructorElement, | 21 ClassElement, |
26 Element, | 22 ConstructorElement, |
27 Elements, | 23 Element, |
28 EnumClassElement, | 24 Elements, |
29 ExecutableElement, | 25 EnumClassElement, |
30 FieldElement, | 26 ExecutableElement, |
31 FunctionElement, | 27 FieldElement, |
32 GetterElement, | 28 FunctionElement, |
33 InitializingFormalElement, | 29 GetterElement, |
34 LibraryElement, | 30 InitializingFormalElement, |
35 Member, | 31 LibraryElement, |
36 MemberSignature, | 32 Member, |
37 Name, | 33 MemberSignature, |
38 ParameterElement, | 34 Name, |
39 PrivateName, | 35 ParameterElement, |
40 PublicName, | 36 PrivateName, |
41 ResolvedAst, | 37 PublicName, |
42 SetterElement, | 38 ResolvedAst, |
43 TypeDeclarationElement, | 39 SetterElement, |
44 TypedElement, | 40 TypeDeclarationElement, |
45 TypedefElement, | 41 TypedElement, |
46 VariableElement; | 42 TypedefElement, |
47 import 'resolution/tree_elements.dart' show | 43 VariableElement; |
48 TreeElements; | 44 import 'resolution/tree_elements.dart' show TreeElements; |
49 import 'resolution/class_members.dart' show | 45 import 'resolution/class_members.dart' show MembersCreator; |
50 MembersCreator; | |
51 import 'tree/tree.dart'; | 46 import 'tree/tree.dart'; |
52 import 'util/util.dart' show | 47 import 'util/util.dart' show Link, LinkBuilder; |
53 Link, | |
54 LinkBuilder; | |
55 | 48 |
56 class TypeCheckerTask extends CompilerTask { | 49 class TypeCheckerTask extends CompilerTask { |
57 TypeCheckerTask(Compiler compiler) : super(compiler); | 50 TypeCheckerTask(Compiler compiler) : super(compiler); |
58 String get name => "Type checker"; | 51 String get name => "Type checker"; |
59 | 52 |
60 void check(AstElement element) { | 53 void check(AstElement element) { |
61 if (element.isClass) return; | 54 if (element.isClass) return; |
62 if (element.isTypedef) return; | 55 if (element.isTypedef) return; |
63 ResolvedAst resolvedAst = element.resolvedAst; | 56 ResolvedAst resolvedAst = element.resolvedAst; |
64 reporter.withCurrentElement(element.implementation, () { | 57 reporter.withCurrentElement(element.implementation, () { |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 | 219 |
227 Element get element => type.element; | 220 Element get element => type.element; |
228 | 221 |
229 String get name => type.name; | 222 String get name => type.name; |
230 | 223 |
231 DartType computeType(Resolution resolution) => resolution.coreTypes.typeType; | 224 DartType computeType(Resolution resolution) => resolution.coreTypes.typeType; |
232 | 225 |
233 String toString() => 'TypeLiteralAccess($type)'; | 226 String toString() => 'TypeLiteralAccess($type)'; |
234 } | 227 } |
235 | 228 |
236 | |
237 /// An access to the 'call' method of a function type. | 229 /// An access to the 'call' method of a function type. |
238 class FunctionCallAccess implements ElementAccess { | 230 class FunctionCallAccess implements ElementAccess { |
239 final Element element; | 231 final Element element; |
240 final DartType type; | 232 final DartType type; |
241 | 233 |
242 const FunctionCallAccess(this.element, this.type); | 234 const FunctionCallAccess(this.element, this.type); |
243 | 235 |
244 String get name => 'call'; | 236 String get name => 'call'; |
245 | 237 |
246 DartType computeType(Resolution resolution) => type; | 238 DartType computeType(Resolution resolution) => type; |
247 | 239 |
248 bool isCallable(Compiler compiler) => true; | 240 bool isCallable(Compiler compiler) => true; |
249 | 241 |
250 String toString() => 'FunctionAccess($element, $type)'; | 242 String toString() => 'FunctionAccess($element, $type)'; |
251 } | 243 } |
252 | 244 |
253 | |
254 /// An is-expression that potentially promotes a variable. | 245 /// An is-expression that potentially promotes a variable. |
255 class TypePromotion { | 246 class TypePromotion { |
256 final Send node; | 247 final Send node; |
257 final VariableElement variable; | 248 final VariableElement variable; |
258 final DartType type; | 249 final DartType type; |
259 final List<TypePromotionMessage> messages = <TypePromotionMessage>[]; | 250 final List<TypePromotionMessage> messages = <TypePromotionMessage>[]; |
260 | 251 |
261 TypePromotion(this.node, this.variable, this.type); | 252 TypePromotion(this.node, this.variable, this.type); |
262 | 253 |
263 bool get isValid => messages.isEmpty; | 254 bool get isValid => messages.isEmpty; |
264 | 255 |
265 TypePromotion copy() { | 256 TypePromotion copy() { |
266 return new TypePromotion(node, variable, type)..messages.addAll(messages); | 257 return new TypePromotion(node, variable, type)..messages.addAll(messages); |
267 } | 258 } |
268 | 259 |
269 void addHint(DiagnosticMessage hint, | 260 void addHint(DiagnosticMessage hint, |
270 [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) { | 261 [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) { |
271 messages.add(new TypePromotionMessage(hint, infos)); | 262 messages.add(new TypePromotionMessage(hint, infos)); |
272 } | 263 } |
273 | 264 |
274 String toString() { | 265 String toString() { |
275 return 'Promote ${variable} to ${type}${isValid ? '' : ' (invalid)'}'; | 266 return 'Promote ${variable} to ${type}${isValid ? '' : ' (invalid)'}'; |
276 } | 267 } |
277 } | 268 } |
278 | 269 |
279 /// A hint or info message attached to a type promotion. | 270 /// A hint or info message attached to a type promotion. |
280 class TypePromotionMessage { | 271 class TypePromotionMessage { |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
325 Set<TypePromotion> reportedTypePromotions = new Set<TypePromotion>(); | 316 Set<TypePromotion> reportedTypePromotions = new Set<TypePromotion>(); |
326 | 317 |
327 void showTypePromotion(Node node, TypePromotion typePromotion) { | 318 void showTypePromotion(Node node, TypePromotion typePromotion) { |
328 List<TypePromotion> shownTypePromotions = | 319 List<TypePromotion> shownTypePromotions = |
329 shownTypePromotionsMap.putIfAbsent(node, () => <TypePromotion>[]); | 320 shownTypePromotionsMap.putIfAbsent(node, () => <TypePromotion>[]); |
330 shownTypePromotions.add(typePromotion); | 321 shownTypePromotions.add(typePromotion); |
331 } | 322 } |
332 | 323 |
333 void registerKnownTypePromotion(TypePromotion typePromotion) { | 324 void registerKnownTypePromotion(TypePromotion typePromotion) { |
334 VariableElement variable = typePromotion.variable; | 325 VariableElement variable = typePromotion.variable; |
335 Link<TypePromotion> knownTypes = | 326 Link<TypePromotion> knownTypes = typePromotionsMap.putIfAbsent( |
336 typePromotionsMap.putIfAbsent(variable, | 327 variable, () => const Link<TypePromotion>()); |
337 () => const Link<TypePromotion>()); | |
338 typePromotionsMap[variable] = knownTypes.prepend(typePromotion); | 328 typePromotionsMap[variable] = knownTypes.prepend(typePromotion); |
339 } | 329 } |
340 | 330 |
341 void unregisterKnownTypePromotion(TypePromotion typePromotion) { | 331 void unregisterKnownTypePromotion(TypePromotion typePromotion) { |
342 VariableElement variable = typePromotion.variable; | 332 VariableElement variable = typePromotion.variable; |
343 Link<TypePromotion> knownTypes = typePromotionsMap[variable].tail; | 333 Link<TypePromotion> knownTypes = typePromotionsMap[variable].tail; |
344 if (knownTypes.isEmpty) { | 334 if (knownTypes.isEmpty) { |
345 typePromotionsMap.remove(variable); | 335 typePromotionsMap.remove(variable); |
346 } else { | 336 } else { |
347 typePromotionsMap[variable] = knownTypes; | 337 typePromotionsMap[variable] = knownTypes; |
(...skipping 22 matching lines...) Expand all Loading... |
370 DartType getKnownType(VariableElement element) { | 360 DartType getKnownType(VariableElement element) { |
371 TypePromotion typePromotion = getKnownTypePromotion(element); | 361 TypePromotion typePromotion = getKnownTypePromotion(element); |
372 if (typePromotion != null) return typePromotion.type; | 362 if (typePromotion != null) return typePromotion.type; |
373 return element.type; | 363 return element.type; |
374 } | 364 } |
375 | 365 |
376 TypeCheckerVisitor(this.compiler, TreeElements elements, this.types) | 366 TypeCheckerVisitor(this.compiler, TreeElements elements, this.types) |
377 : this.elements = elements, | 367 : this.elements = elements, |
378 this.executableContext = elements.analyzedElement, | 368 this.executableContext = elements.analyzedElement, |
379 this.currentClass = elements.analyzedElement != null | 369 this.currentClass = elements.analyzedElement != null |
380 ? elements.analyzedElement.enclosingClass : null { | 370 ? elements.analyzedElement.enclosingClass |
381 | 371 : null { |
382 if (currentClass != null) { | 372 if (currentClass != null) { |
383 thisType = currentClass.thisType; | 373 thisType = currentClass.thisType; |
384 superType = currentClass.supertype; | 374 superType = currentClass.supertype; |
385 } else { | 375 } else { |
386 // If these are used, an error should have been reported by the resolver. | 376 // If these are used, an error should have been reported by the resolver. |
387 thisType = const DynamicType(); | 377 thisType = const DynamicType(); |
388 superType = const DynamicType(); | 378 superType = const DynamicType(); |
389 } | 379 } |
390 } | 380 } |
391 | 381 |
392 LibraryElement get currentLibrary => elements.analyzedElement.library; | 382 LibraryElement get currentLibrary => elements.analyzedElement.library; |
393 | 383 |
394 reportTypeWarning(Spannable spannable, MessageKind kind, | 384 reportTypeWarning(Spannable spannable, MessageKind kind, |
395 [Map arguments = const {}]) { | 385 [Map arguments = const {}]) { |
396 reporter.reportWarningMessage(spannable, kind, arguments); | 386 reporter.reportWarningMessage(spannable, kind, arguments); |
397 } | 387 } |
398 | 388 |
399 reportMessage(Spannable spannable, MessageKind kind, | 389 reportMessage(Spannable spannable, MessageKind kind, Map arguments, |
400 Map arguments, | 390 {bool isHint: false}) { |
401 {bool isHint: false}) { | |
402 if (isHint) { | 391 if (isHint) { |
403 reporter.reportHintMessage(spannable, kind, arguments); | 392 reporter.reportHintMessage(spannable, kind, arguments); |
404 } else { | 393 } else { |
405 reporter.reportWarningMessage(spannable, kind, arguments); | 394 reporter.reportWarningMessage(spannable, kind, arguments); |
406 } | 395 } |
407 } | 396 } |
408 | 397 |
409 reportTypePromotionHint(TypePromotion typePromotion) { | 398 reportTypePromotionHint(TypePromotion typePromotion) { |
410 if (!reportedTypePromotions.contains(typePromotion)) { | 399 if (!reportedTypePromotions.contains(typePromotion)) { |
411 reportedTypePromotions.add(typePromotion); | 400 reportedTypePromotions.add(typePromotion); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
447 analyzingInitializer = inInitializer; | 436 analyzingInitializer = inInitializer; |
448 DartType result = node.accept(this); | 437 DartType result = node.accept(this); |
449 analyzingInitializer = previouslyInitializer; | 438 analyzingInitializer = previouslyInitializer; |
450 if (result == null) { | 439 if (result == null) { |
451 reporter.internalError(node, 'Type is null.'); | 440 reporter.internalError(node, 'Type is null.'); |
452 } | 441 } |
453 return _record(node, result); | 442 return _record(node, result); |
454 } | 443 } |
455 | 444 |
456 void checkTypePromotion(Node node, TypePromotion typePromotion, | 445 void checkTypePromotion(Node node, TypePromotion typePromotion, |
457 {bool checkAccesses: false}) { | 446 {bool checkAccesses: false}) { |
458 VariableElement variable = typePromotion.variable; | 447 VariableElement variable = typePromotion.variable; |
459 String variableName = variable.name; | 448 String variableName = variable.name; |
460 List<Node> potentialMutationsIn = | 449 List<Node> potentialMutationsIn = |
461 elements.getPotentialMutationsIn(node, variable); | 450 elements.getPotentialMutationsIn(node, variable); |
462 if (!potentialMutationsIn.isEmpty) { | 451 if (!potentialMutationsIn.isEmpty) { |
463 DiagnosticMessage hint = reporter.createMessage( | 452 DiagnosticMessage hint = reporter.createMessage( |
464 typePromotion.node, | 453 typePromotion.node, |
465 MessageKind.POTENTIAL_MUTATION, | 454 MessageKind.POTENTIAL_MUTATION, |
466 {'variableName': variableName, 'shownType': typePromotion.type}); | 455 {'variableName': variableName, 'shownType': typePromotion.type}); |
467 List<DiagnosticMessage> infos = <DiagnosticMessage>[]; | 456 List<DiagnosticMessage> infos = <DiagnosticMessage>[]; |
468 for (Node mutation in potentialMutationsIn) { | 457 for (Node mutation in potentialMutationsIn) { |
469 infos.add(reporter.createMessage(mutation, | 458 infos.add(reporter.createMessage( |
| 459 mutation, |
470 MessageKind.POTENTIAL_MUTATION_HERE, | 460 MessageKind.POTENTIAL_MUTATION_HERE, |
471 {'variableName': variableName})); | 461 {'variableName': variableName})); |
472 } | 462 } |
473 typePromotion.addHint(hint, infos); | 463 typePromotion.addHint(hint, infos); |
474 } | 464 } |
475 List<Node> potentialMutationsInClosures = | 465 List<Node> potentialMutationsInClosures = |
476 elements.getPotentialMutationsInClosure(variable); | 466 elements.getPotentialMutationsInClosure(variable); |
477 if (!potentialMutationsInClosures.isEmpty) { | 467 if (!potentialMutationsInClosures.isEmpty) { |
478 DiagnosticMessage hint = reporter.createMessage( | 468 DiagnosticMessage hint = reporter.createMessage( |
479 typePromotion.node, | 469 typePromotion.node, |
(...skipping 30 matching lines...) Expand all Loading... |
510 {'variableName': variableName})); | 500 {'variableName': variableName})); |
511 } | 501 } |
512 typePromotion.addHint(hint, infos); | 502 typePromotion.addHint(hint, infos); |
513 } | 503 } |
514 } | 504 } |
515 } | 505 } |
516 | 506 |
517 /// Show type promotions from [left] and [right] in [node] given that the | 507 /// Show type promotions from [left] and [right] in [node] given that the |
518 /// promoted variables are not potentially mutated in [right]. | 508 /// promoted variables are not potentially mutated in [right]. |
519 void reshowTypePromotions(Node node, Node left, Node right) { | 509 void reshowTypePromotions(Node node, Node left, Node right) { |
520 for (TypePromotion typePromotion in getShownTypePromotionsFor(left)) { | 510 for (TypePromotion typePromotion in getShownTypePromotionsFor(left)) { |
521 typePromotion = typePromotion.copy(); | 511 typePromotion = typePromotion.copy(); |
522 checkTypePromotion(right, typePromotion); | 512 checkTypePromotion(right, typePromotion); |
523 showTypePromotion(node, typePromotion); | 513 showTypePromotion(node, typePromotion); |
524 } | 514 } |
525 | 515 |
526 for (TypePromotion typePromotion in getShownTypePromotionsFor(right)) { | 516 for (TypePromotion typePromotion in getShownTypePromotionsFor(right)) { |
527 typePromotion = typePromotion.copy(); | 517 typePromotion = typePromotion.copy(); |
528 checkTypePromotion(right, typePromotion); | 518 checkTypePromotion(right, typePromotion); |
529 showTypePromotion(node, typePromotion); | 519 showTypePromotion(node, typePromotion); |
530 } | 520 } |
531 } | 521 } |
532 | 522 |
533 /// Analyze [node] in the context of the known types shown in [context]. | 523 /// Analyze [node] in the context of the known types shown in [context]. |
534 DartType analyzeInPromotedContext(Node context, Node node) { | 524 DartType analyzeInPromotedContext(Node context, Node node) { |
535 Link<TypePromotion> knownForNode = const Link<TypePromotion>(); | 525 Link<TypePromotion> knownForNode = const Link<TypePromotion>(); |
536 for (TypePromotion typePromotion in getShownTypePromotionsFor(context)) { | 526 for (TypePromotion typePromotion in getShownTypePromotionsFor(context)) { |
537 typePromotion = typePromotion.copy(); | 527 typePromotion = typePromotion.copy(); |
538 checkTypePromotion(node, typePromotion, checkAccesses: true); | 528 checkTypePromotion(node, typePromotion, checkAccesses: true); |
539 knownForNode = knownForNode.prepend(typePromotion); | 529 knownForNode = knownForNode.prepend(typePromotion); |
540 registerKnownTypePromotion(typePromotion); | 530 registerKnownTypePromotion(typePromotion); |
541 } | 531 } |
542 | 532 |
543 final DartType type = analyze(node); | 533 final DartType type = analyze(node); |
544 | 534 |
545 while (!knownForNode.isEmpty) { | 535 while (!knownForNode.isEmpty) { |
546 unregisterKnownTypePromotion(knownForNode.head); | 536 unregisterKnownTypePromotion(knownForNode.head); |
547 knownForNode = knownForNode.tail; | 537 knownForNode = knownForNode.tail; |
548 } | 538 } |
549 | 539 |
550 return type; | 540 return type; |
551 } | 541 } |
552 | 542 |
553 /** | 543 /** |
554 * Check if a value of type [from] can be assigned to a variable, parameter or | 544 * Check if a value of type [from] can be assigned to a variable, parameter or |
555 * return value of type [to]. If `isConst == true`, an error is emitted in | 545 * return value of type [to]. If `isConst == true`, an error is emitted in |
556 * checked mode, otherwise a warning is issued. | 546 * checked mode, otherwise a warning is issued. |
557 */ | 547 */ |
558 bool checkAssignable(Spannable spannable, DartType from, DartType to, | 548 bool checkAssignable(Spannable spannable, DartType from, DartType to, |
559 {bool isConst: false}) { | 549 {bool isConst: false}) { |
560 if (!types.isAssignable(from, to)) { | 550 if (!types.isAssignable(from, to)) { |
561 if (compiler.options.enableTypeAssertions && isConst) { | 551 if (compiler.options.enableTypeAssertions && isConst) { |
562 reporter.reportErrorMessage( | 552 reporter.reportErrorMessage(spannable, MessageKind.NOT_ASSIGNABLE, |
563 spannable, | |
564 MessageKind.NOT_ASSIGNABLE, | |
565 {'fromType': from, 'toType': to}); | 553 {'fromType': from, 'toType': to}); |
566 } else { | 554 } else { |
567 reporter.reportWarningMessage( | 555 reporter.reportWarningMessage(spannable, MessageKind.NOT_ASSIGNABLE, |
568 spannable, | |
569 MessageKind.NOT_ASSIGNABLE, | |
570 {'fromType': from, 'toType': to}); | 556 {'fromType': from, 'toType': to}); |
571 } | 557 } |
572 return false; | 558 return false; |
573 } | 559 } |
574 return true; | 560 return true; |
575 } | 561 } |
576 | 562 |
577 checkCondition(Expression condition) { | 563 checkCondition(Expression condition) { |
578 checkAssignable(condition, analyze(condition), boolType); | 564 checkAssignable(condition, analyze(condition), boolType); |
579 } | 565 } |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
638 DartType visitFunctionDeclaration(FunctionDeclaration node) { | 624 DartType visitFunctionDeclaration(FunctionDeclaration node) { |
639 analyze(node.function); | 625 analyze(node.function); |
640 return const StatementType(); | 626 return const StatementType(); |
641 } | 627 } |
642 | 628 |
643 DartType visitFunctionExpression(FunctionExpression node) { | 629 DartType visitFunctionExpression(FunctionExpression node) { |
644 DartType type; | 630 DartType type; |
645 DartType returnType; | 631 DartType returnType; |
646 final FunctionElement element = elements.getFunctionDefinition(node); | 632 final FunctionElement element = elements.getFunctionDefinition(node); |
647 assert(invariant(node, element != null, | 633 assert(invariant(node, element != null, |
648 message: 'FunctionExpression with no element')); | 634 message: 'FunctionExpression with no element')); |
649 if (Elements.isUnresolved(element)) return const DynamicType(); | 635 if (Elements.isUnresolved(element)) return const DynamicType(); |
650 if (element.isGenerativeConstructor) { | 636 if (element.isGenerativeConstructor) { |
651 type = const DynamicType(); | 637 type = const DynamicType(); |
652 returnType = const VoidType(); | 638 returnType = const VoidType(); |
653 | 639 |
654 element.functionSignature.forEachParameter((ParameterElement parameter) { | 640 element.functionSignature.forEachParameter((ParameterElement parameter) { |
655 if (parameter.isInitializingFormal) { | 641 if (parameter.isInitializingFormal) { |
656 InitializingFormalElement fieldParameter = parameter; | 642 InitializingFormalElement fieldParameter = parameter; |
657 checkAssignable(parameter, parameter.type, | 643 checkAssignable(parameter, parameter.type, |
658 fieldParameter.fieldElement.computeType(resolution)); | 644 fieldParameter.fieldElement.computeType(resolution)); |
(...skipping 24 matching lines...) Expand all Loading... |
683 | 669 |
684 DartType visitIdentifier(Identifier node) { | 670 DartType visitIdentifier(Identifier node) { |
685 if (node.isThis()) { | 671 if (node.isThis()) { |
686 return thisType; | 672 return thisType; |
687 } else if (node.isSuper()) { | 673 } else if (node.isSuper()) { |
688 return superType; | 674 return superType; |
689 } else { | 675 } else { |
690 TypedElement element = elements[node]; | 676 TypedElement element = elements[node]; |
691 assert(invariant(node, element != null, | 677 assert(invariant(node, element != null, |
692 message: 'Missing element for identifier')); | 678 message: 'Missing element for identifier')); |
693 assert(invariant(node, element.isVariable || | 679 assert(invariant( |
694 element.isParameter || | 680 node, element.isVariable || element.isParameter || element.isField, |
695 element.isField, | |
696 message: 'Unexpected context element ${element}')); | 681 message: 'Unexpected context element ${element}')); |
697 return element.computeType(resolution); | 682 return element.computeType(resolution); |
698 } | 683 } |
699 } | 684 } |
700 | 685 |
701 DartType visitIf(If node) { | 686 DartType visitIf(If node) { |
702 Expression condition = node.condition.expression; | 687 Expression condition = node.condition.expression; |
703 Statement thenPart = node.thenPart; | 688 Statement thenPart = node.thenPart; |
704 | 689 |
705 checkCondition(node.condition); | 690 checkCondition(node.condition); |
706 analyzeInPromotedContext(condition, thenPart); | 691 analyzeInPromotedContext(condition, thenPart); |
707 if (node.elsePart != null) { | 692 if (node.elsePart != null) { |
708 analyze(node.elsePart); | 693 analyze(node.elsePart); |
709 } | 694 } |
710 return const StatementType(); | 695 return const StatementType(); |
711 } | 696 } |
712 | 697 |
713 void checkPrivateAccess(Node node, Element element, String name) { | 698 void checkPrivateAccess(Node node, Element element, String name) { |
714 if (name != null && | 699 if (name != null && |
715 Name.isPrivateName(name) && | 700 Name.isPrivateName(name) && |
716 element.library != currentLibrary) { | 701 element.library != currentLibrary) { |
717 reportTypeWarning( | 702 reportTypeWarning(node, MessageKind.PRIVATE_ACCESS, |
718 node, | 703 {'name': name, 'libraryName': element.library.libraryOrScriptName}); |
719 MessageKind.PRIVATE_ACCESS, | |
720 {'name': name, | |
721 'libraryName': element.library.libraryOrScriptName}); | |
722 } | 704 } |
723 | |
724 } | 705 } |
725 | 706 |
726 ElementAccess lookupMember(Node node, DartType receiverType, String name, | 707 ElementAccess lookupMember(Node node, DartType receiverType, String name, |
727 MemberKind memberKind, Element receiverElement, | 708 MemberKind memberKind, Element receiverElement, |
728 {bool lookupClassMember: false, | 709 {bool lookupClassMember: false, bool isHint: false}) { |
729 bool isHint: false}) { | |
730 if (receiverType.treatAsDynamic) { | 710 if (receiverType.treatAsDynamic) { |
731 return const DynamicAccess(); | 711 return const DynamicAccess(); |
732 } | 712 } |
733 | 713 |
734 Name memberName = new Name(name, currentLibrary, | 714 Name memberName = new Name(name, currentLibrary, |
735 isSetter: memberKind == MemberKind.SETTER); | 715 isSetter: memberKind == MemberKind.SETTER); |
736 | 716 |
737 // Lookup the class or interface member [name] in [interface]. | 717 // Lookup the class or interface member [name] in [interface]. |
738 MemberSignature lookupMemberSignature(Name name, InterfaceType interface) { | 718 MemberSignature lookupMemberSignature(Name name, InterfaceType interface) { |
739 MembersCreator.computeClassMembersByName( | 719 MembersCreator.computeClassMembersByName( |
740 compiler, interface.element, name.text); | 720 compiler, interface.element, name.text); |
741 return lookupClassMember || analyzingInitializer | 721 return lookupClassMember || analyzingInitializer |
742 ? interface.lookupClassMember(name) | 722 ? interface.lookupClassMember(name) |
743 : interface.lookupInterfaceMember(name); | 723 : interface.lookupInterfaceMember(name); |
744 } | 724 } |
745 | 725 |
746 // Compute the access of [name] on [type]. This function takes the special | 726 // Compute the access of [name] on [type]. This function takes the special |
747 // 'call' method into account. | 727 // 'call' method into account. |
748 ElementAccess getAccess(Name name, | 728 ElementAccess getAccess( |
749 DartType unaliasedBound, InterfaceType interface) { | 729 Name name, DartType unaliasedBound, InterfaceType interface) { |
750 MemberSignature member = lookupMemberSignature(memberName, interface); | 730 MemberSignature member = lookupMemberSignature(memberName, interface); |
751 if (member != null) { | 731 if (member != null) { |
752 return new MemberAccess(member); | 732 return new MemberAccess(member); |
753 } | 733 } |
754 if (name == const PublicName('call')) { | 734 if (name == const PublicName('call')) { |
755 if (unaliasedBound.isFunctionType) { | 735 if (unaliasedBound.isFunctionType) { |
756 // This is an access the implicit 'call' method of a function type. | 736 // This is an access the implicit 'call' method of a function type. |
757 return new FunctionCallAccess(receiverElement, unaliasedBound); | 737 return new FunctionCallAccess(receiverElement, unaliasedBound); |
758 } | 738 } |
759 if (types.isSubtype(interface, coreTypes.functionType)) { | 739 if (types.isSubtype(interface, coreTypes.functionType)) { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
802 // super or redirecting initializer, the resolver has already emitted an | 782 // super or redirecting initializer, the resolver has already emitted an |
803 // error message. If the target is a proxy, no warning needs to be emitted. | 783 // error message. If the target is a proxy, no warning needs to be emitted. |
804 // Otherwise, try to emit the most precise warning. | 784 // Otherwise, try to emit the most precise warning. |
805 if (!interface.element.isProxy && !analyzingInitializer) { | 785 if (!interface.element.isProxy && !analyzingInitializer) { |
806 bool foundPrivateMember = false; | 786 bool foundPrivateMember = false; |
807 if (memberName.isPrivate) { | 787 if (memberName.isPrivate) { |
808 void findPrivateMember(MemberSignature member) { | 788 void findPrivateMember(MemberSignature member) { |
809 if (memberName.isSimilarTo(member.name)) { | 789 if (memberName.isSimilarTo(member.name)) { |
810 PrivateName privateName = member.name; | 790 PrivateName privateName = member.name; |
811 reportMessage( | 791 reportMessage( |
812 node, | 792 node, |
813 MessageKind.PRIVATE_ACCESS, | 793 MessageKind.PRIVATE_ACCESS, |
814 {'name': name, | 794 { |
815 'libraryName': privateName.library.libraryOrScriptName}, | 795 'name': name, |
816 isHint: isHint); | 796 'libraryName': privateName.library.libraryOrScriptName |
| 797 }, |
| 798 isHint: isHint); |
817 foundPrivateMember = true; | 799 foundPrivateMember = true; |
818 } | 800 } |
819 } | 801 } |
820 // TODO(johnniwinther): Avoid computation of all class members. | 802 // TODO(johnniwinther): Avoid computation of all class members. |
821 MembersCreator.computeAllClassMembers(compiler, interface.element); | 803 MembersCreator.computeAllClassMembers(compiler, interface.element); |
822 if (lookupClassMember) { | 804 if (lookupClassMember) { |
823 interface.element.forEachClassMember(findPrivateMember); | 805 interface.element.forEachClassMember(findPrivateMember); |
824 } else { | 806 } else { |
825 interface.element.forEachInterfaceMember(findPrivateMember); | 807 interface.element.forEachInterfaceMember(findPrivateMember); |
826 } | 808 } |
827 | |
828 } | 809 } |
829 if (!foundPrivateMember) { | 810 if (!foundPrivateMember) { |
830 switch (memberKind) { | 811 switch (memberKind) { |
831 case MemberKind.METHOD: | 812 case MemberKind.METHOD: |
832 reportMessage(node, MessageKind.UNDEFINED_METHOD, | 813 reportMessage(node, MessageKind.UNDEFINED_METHOD, |
833 {'className': receiverType.name, 'memberName': name}, | 814 {'className': receiverType.name, 'memberName': name}, |
834 isHint: isHint); | 815 isHint: isHint); |
835 break; | 816 break; |
836 case MemberKind.OPERATOR: | 817 case MemberKind.OPERATOR: |
837 reportMessage(node, MessageKind.UNDEFINED_OPERATOR, | 818 reportMessage(node, MessageKind.UNDEFINED_OPERATOR, |
838 {'className': receiverType.name, 'memberName': name}, | 819 {'className': receiverType.name, 'memberName': name}, |
839 isHint: isHint); | 820 isHint: isHint); |
840 break; | 821 break; |
841 case MemberKind.GETTER: | 822 case MemberKind.GETTER: |
842 if (lookupMemberSignature(memberName.setter, interface) != null) { | 823 if (lookupMemberSignature(memberName.setter, interface) != null) { |
843 // A setter is present so warn explicitly about the missing | 824 // A setter is present so warn explicitly about the missing |
844 // getter. | 825 // getter. |
845 reportMessage(node, | 826 reportMessage( |
| 827 node, |
846 MessageKind.UNDEFINED_INSTANCE_GETTER_BUT_SETTER, | 828 MessageKind.UNDEFINED_INSTANCE_GETTER_BUT_SETTER, |
847 {'className': receiverType.name, 'memberName': name}, | 829 {'className': receiverType.name, 'memberName': name}, |
848 isHint: isHint); | 830 isHint: isHint); |
849 } else if (name == 'await') { | 831 } else if (name == 'await') { |
850 Map arguments = {'className': receiverType.name}; | 832 Map arguments = {'className': receiverType.name}; |
851 String functionName = executableContext.name; | 833 String functionName = executableContext.name; |
852 MessageKind kind; | 834 MessageKind kind; |
853 if (functionName == '') { | 835 if (functionName == '') { |
854 kind = MessageKind.AWAIT_MEMBER_NOT_FOUND_IN_CLOSURE; | 836 kind = MessageKind.AWAIT_MEMBER_NOT_FOUND_IN_CLOSURE; |
855 } else { | 837 } else { |
(...skipping 11 matching lines...) Expand all Loading... |
867 reportMessage(node, MessageKind.UNDEFINED_SETTER, | 849 reportMessage(node, MessageKind.UNDEFINED_SETTER, |
868 {'className': receiverType.name, 'memberName': name}, | 850 {'className': receiverType.name, 'memberName': name}, |
869 isHint: isHint); | 851 isHint: isHint); |
870 break; | 852 break; |
871 } | 853 } |
872 } | 854 } |
873 } | 855 } |
874 return const DynamicAccess(); | 856 return const DynamicAccess(); |
875 } | 857 } |
876 | 858 |
877 DartType lookupMemberType(Node node, DartType type, String name, | 859 DartType lookupMemberType( |
878 MemberKind memberKind, | 860 Node node, DartType type, String name, MemberKind memberKind, |
879 {bool isHint: false}) { | 861 {bool isHint: false}) { |
880 return lookupMember(node, type, name, memberKind, null, isHint: isHint) | 862 return lookupMember(node, type, name, memberKind, null, isHint: isHint) |
881 .computeType(resolution); | 863 .computeType(resolution); |
882 } | 864 } |
883 | 865 |
884 void analyzeArguments(Send send, Element element, DartType type, | 866 void analyzeArguments(Send send, Element element, DartType type, |
885 [LinkBuilder<DartType> argumentTypes]) { | 867 [LinkBuilder<DartType> argumentTypes]) { |
886 Link<Node> arguments = send.arguments; | 868 Link<Node> arguments = send.arguments; |
887 type.computeUnaliased(resolution); | 869 type.computeUnaliased(resolution); |
888 DartType unaliasedType = type.unaliased; | 870 DartType unaliasedType = type.unaliased; |
889 if (identical(unaliasedType.kind, TypeKind.FUNCTION)) { | 871 if (identical(unaliasedType.kind, TypeKind.FUNCTION)) { |
890 | |
891 /// Report [warning] including info(s) about the declaration of [element] | 872 /// Report [warning] including info(s) about the declaration of [element] |
892 /// or [type]. | 873 /// or [type]. |
893 void reportWarning(DiagnosticMessage warning) { | 874 void reportWarning(DiagnosticMessage warning) { |
894 // TODO(johnniwinther): Support pointing to individual parameters on | 875 // TODO(johnniwinther): Support pointing to individual parameters on |
895 // assignability warnings. | 876 // assignability warnings. |
896 List<DiagnosticMessage> infos = <DiagnosticMessage>[]; | 877 List<DiagnosticMessage> infos = <DiagnosticMessage>[]; |
897 Element declaration = element; | 878 Element declaration = element; |
898 if (declaration == null) { | 879 if (declaration == null) { |
899 declaration = type.element; | 880 declaration = type.element; |
900 } else if (type.isTypedef) { | 881 } else if (type.isTypedef) { |
901 infos.add(reporter.createMessage( | 882 infos.add(reporter.createMessage(declaration, |
902 declaration, | 883 MessageKind.THIS_IS_THE_DECLARATION, {'name': element.name})); |
903 MessageKind.THIS_IS_THE_DECLARATION, | |
904 {'name': element.name})); | |
905 declaration = type.element; | 884 declaration = type.element; |
906 } | 885 } |
907 if (declaration != null) { | 886 if (declaration != null) { |
908 infos.add(reporter.createMessage( | 887 infos.add(reporter.createMessage( |
909 declaration, MessageKind.THIS_IS_THE_METHOD)); | 888 declaration, MessageKind.THIS_IS_THE_METHOD)); |
910 } | 889 } |
911 reporter.reportWarning(warning, infos); | 890 reporter.reportWarning(warning, infos); |
912 } | 891 } |
913 | 892 |
914 /// Report a warning on [node] if [argumentType] is not assignable to | 893 /// Report a warning on [node] if [argumentType] is not assignable to |
915 /// [parameterType]. | 894 /// [parameterType]. |
916 void checkAssignable(Spannable node, | 895 void checkAssignable( |
917 DartType argumentType, | 896 Spannable node, DartType argumentType, DartType parameterType) { |
918 DartType parameterType) { | |
919 if (!types.isAssignable(argumentType, parameterType)) { | 897 if (!types.isAssignable(argumentType, parameterType)) { |
920 reportWarning(reporter.createMessage( | 898 reportWarning(reporter.createMessage(node, MessageKind.NOT_ASSIGNABLE, |
921 node, | |
922 MessageKind.NOT_ASSIGNABLE, | |
923 {'fromType': argumentType, 'toType': parameterType})); | 899 {'fromType': argumentType, 'toType': parameterType})); |
924 } | 900 } |
925 } | 901 } |
926 | 902 |
927 FunctionType funType = unaliasedType; | 903 FunctionType funType = unaliasedType; |
928 Iterator<DartType> parameterTypes = funType.parameterTypes.iterator; | 904 Iterator<DartType> parameterTypes = funType.parameterTypes.iterator; |
929 Iterator<DartType> optionalParameterTypes = | 905 Iterator<DartType> optionalParameterTypes = |
930 funType.optionalParameterTypes.iterator; | 906 funType.optionalParameterTypes.iterator; |
931 while (!arguments.isEmpty) { | 907 while (!arguments.isEmpty) { |
932 Node argument = arguments.head; | 908 Node argument = arguments.head; |
(...skipping 14 matching lines...) Expand all Loading... |
947 DartType argumentType = analyze(argument); | 923 DartType argumentType = analyze(argument); |
948 if (argumentTypes != null) argumentTypes.addLast(argumentType); | 924 if (argumentTypes != null) argumentTypes.addLast(argumentType); |
949 } else { | 925 } else { |
950 DartType argumentType = analyze(argument); | 926 DartType argumentType = analyze(argument); |
951 if (argumentTypes != null) argumentTypes.addLast(argumentType); | 927 if (argumentTypes != null) argumentTypes.addLast(argumentType); |
952 checkAssignable(argument, argumentType, namedParameterType); | 928 checkAssignable(argument, argumentType, namedParameterType); |
953 } | 929 } |
954 } else { | 930 } else { |
955 if (!parameterTypes.moveNext()) { | 931 if (!parameterTypes.moveNext()) { |
956 if (!optionalParameterTypes.moveNext()) { | 932 if (!optionalParameterTypes.moveNext()) { |
957 | |
958 // TODO(johnniwinther): Provide better information on the | 933 // TODO(johnniwinther): Provide better information on the |
959 // called function. | 934 // called function. |
960 reportWarning(reporter.createMessage( | 935 reportWarning(reporter.createMessage( |
961 argument, MessageKind.ADDITIONAL_ARGUMENT)); | 936 argument, MessageKind.ADDITIONAL_ARGUMENT)); |
962 | 937 |
963 DartType argumentType = analyze(argument); | 938 DartType argumentType = analyze(argument); |
964 if (argumentTypes != null) argumentTypes.addLast(argumentType); | 939 if (argumentTypes != null) argumentTypes.addLast(argumentType); |
965 } else { | 940 } else { |
966 DartType argumentType = analyze(argument); | 941 DartType argumentType = analyze(argument); |
967 if (argumentTypes != null) argumentTypes.addLast(argumentType); | 942 if (argumentTypes != null) argumentTypes.addLast(argumentType); |
968 checkAssignable( | 943 checkAssignable( |
969 argument, argumentType, optionalParameterTypes.current); | 944 argument, argumentType, optionalParameterTypes.current); |
970 } | 945 } |
971 } else { | 946 } else { |
972 DartType argumentType = analyze(argument); | 947 DartType argumentType = analyze(argument); |
973 if (argumentTypes != null) argumentTypes.addLast(argumentType); | 948 if (argumentTypes != null) argumentTypes.addLast(argumentType); |
974 checkAssignable(argument, argumentType, parameterTypes.current); | 949 checkAssignable(argument, argumentType, parameterTypes.current); |
975 } | 950 } |
976 } | 951 } |
977 arguments = arguments.tail; | 952 arguments = arguments.tail; |
978 } | 953 } |
979 if (parameterTypes.moveNext()) { | 954 if (parameterTypes.moveNext()) { |
980 // TODO(johnniwinther): Provide better information on the called | 955 // TODO(johnniwinther): Provide better information on the called |
981 // function. | 956 // function. |
982 reportWarning(reporter.createMessage( | 957 reportWarning(reporter.createMessage(send, MessageKind.MISSING_ARGUMENT, |
983 send, MessageKind.MISSING_ARGUMENT, | |
984 {'argumentType': parameterTypes.current})); | 958 {'argumentType': parameterTypes.current})); |
985 } | 959 } |
986 } else { | 960 } else { |
987 while(!arguments.isEmpty) { | 961 while (!arguments.isEmpty) { |
988 DartType argumentType = analyze(arguments.head); | 962 DartType argumentType = analyze(arguments.head); |
989 if (argumentTypes != null) argumentTypes.addLast(argumentType); | 963 if (argumentTypes != null) argumentTypes.addLast(argumentType); |
990 arguments = arguments.tail; | 964 arguments = arguments.tail; |
991 } | 965 } |
992 } | 966 } |
993 } | 967 } |
994 | 968 |
995 // Analyze the invocation [node] of [elementAccess]. | 969 // Analyze the invocation [node] of [elementAccess]. |
996 // | 970 // |
997 // If provided [argumentTypes] is filled with the argument types during | 971 // If provided [argumentTypes] is filled with the argument types during |
998 // analysis. | 972 // analysis. |
999 DartType analyzeInvocation(Send node, ElementAccess elementAccess, | 973 DartType analyzeInvocation(Send node, ElementAccess elementAccess, |
1000 [LinkBuilder<DartType> argumentTypes]) { | 974 [LinkBuilder<DartType> argumentTypes]) { |
1001 DartType type = elementAccess.computeType(resolution); | 975 DartType type = elementAccess.computeType(resolution); |
1002 if (elementAccess.isCallable(compiler)) { | 976 if (elementAccess.isCallable(compiler)) { |
1003 analyzeArguments(node, elementAccess.element, type, argumentTypes); | 977 analyzeArguments(node, elementAccess.element, type, argumentTypes); |
1004 } else { | 978 } else { |
1005 reportTypeWarning(node, MessageKind.NOT_CALLABLE, | 979 reportTypeWarning( |
1006 {'elementName': elementAccess.name}); | 980 node, MessageKind.NOT_CALLABLE, {'elementName': elementAccess.name}); |
1007 analyzeArguments(node, elementAccess.element, const DynamicType(), | 981 analyzeArguments( |
1008 argumentTypes); | 982 node, elementAccess.element, const DynamicType(), argumentTypes); |
1009 } | 983 } |
1010 type.computeUnaliased(resolution); | 984 type.computeUnaliased(resolution); |
1011 type = type.unaliased; | 985 type = type.unaliased; |
1012 if (type.isFunctionType) { | 986 if (type.isFunctionType) { |
1013 FunctionType funType = type; | 987 FunctionType funType = type; |
1014 return funType.returnType; | 988 return funType.returnType; |
1015 } else { | 989 } else { |
1016 return const DynamicType(); | 990 return const DynamicType(); |
1017 } | 991 } |
1018 } | 992 } |
1019 | 993 |
1020 /** | 994 /** |
1021 * Computes the [ElementAccess] for [name] on the [node] possibly using the | 995 * Computes the [ElementAccess] for [name] on the [node] possibly using the |
1022 * [element] provided for [node] by the resolver. | 996 * [element] provided for [node] by the resolver. |
1023 */ | 997 */ |
1024 ElementAccess computeAccess(Send node, String name, Element element, | 998 ElementAccess computeAccess( |
1025 MemberKind memberKind, | 999 Send node, String name, Element element, MemberKind memberKind, |
1026 {bool lookupClassMember: false}) { | 1000 {bool lookupClassMember: false}) { |
1027 if (Elements.isMalformed(element)) { | 1001 if (Elements.isMalformed(element)) { |
1028 return const DynamicAccess(); | 1002 return const DynamicAccess(); |
1029 } | 1003 } |
1030 if (node.receiver != null) { | 1004 if (node.receiver != null) { |
1031 Element receiverElement = elements[node.receiver]; | 1005 Element receiverElement = elements[node.receiver]; |
1032 if (receiverElement != null) { | 1006 if (receiverElement != null) { |
1033 if (receiverElement.isPrefix) { | 1007 if (receiverElement.isPrefix) { |
1034 if (node.isConditional) { | 1008 if (node.isConditional) { |
1035 // Skip cases like `prefix?.topLevel`. | 1009 // Skip cases like `prefix?.topLevel`. |
1036 return const DynamicAccess(); | 1010 return const DynamicAccess(); |
1037 } | 1011 } |
1038 assert(invariant(node, element != null, | 1012 assert(invariant(node, element != null, |
1039 message: 'Prefixed node has no element.')); | 1013 message: 'Prefixed node has no element.')); |
1040 return computeResolvedAccess(node, name, element, memberKind); | 1014 return computeResolvedAccess(node, name, element, memberKind); |
1041 } | 1015 } |
1042 } | 1016 } |
1043 // e.foo() for some expression e. | 1017 // e.foo() for some expression e. |
1044 DartType receiverType = analyze(node.receiver); | 1018 DartType receiverType = analyze(node.receiver); |
1045 if (receiverType.treatAsDynamic || receiverType.isVoid) { | 1019 if (receiverType.treatAsDynamic || receiverType.isVoid) { |
1046 return const DynamicAccess(); | 1020 return const DynamicAccess(); |
1047 } | 1021 } |
1048 return lookupMember(node, receiverType, name, memberKind, | 1022 return lookupMember( |
1049 elements[node.receiver], | 1023 node, receiverType, name, memberKind, elements[node.receiver], |
1050 lookupClassMember: lookupClassMember || | 1024 lookupClassMember: |
1051 element != null && element.isStatic); | 1025 lookupClassMember || element != null && element.isStatic); |
1052 } else { | 1026 } else { |
1053 return computeResolvedAccess(node, name, element, memberKind); | 1027 return computeResolvedAccess(node, name, element, memberKind); |
1054 } | 1028 } |
1055 } | 1029 } |
1056 | 1030 |
1057 /** | 1031 /** |
1058 * Computes the [ElementAccess] for [name] on the [node] using the [element] | 1032 * Computes the [ElementAccess] for [name] on the [node] using the [element] |
1059 * provided for [node] by the resolver. | 1033 * provided for [node] by the resolver. |
1060 */ | 1034 */ |
1061 ElementAccess computeResolvedAccess(Send node, String name, | 1035 ElementAccess computeResolvedAccess( |
1062 Element element, MemberKind memberKind) { | 1036 Send node, String name, Element element, MemberKind memberKind) { |
1063 if (element == null) { | 1037 if (element == null) { |
1064 // foo() where foo is unresolved. | 1038 // foo() where foo is unresolved. |
1065 return lookupMember(node, thisType, name, memberKind, null); | 1039 return lookupMember(node, thisType, name, memberKind, null); |
1066 } else if (element.isMalformed) { | 1040 } else if (element.isMalformed) { |
1067 // foo() where foo is erroneous. | 1041 // foo() where foo is erroneous. |
1068 return const DynamicAccess(); | 1042 return const DynamicAccess(); |
1069 } else if (element.impliesType) { | 1043 } else if (element.impliesType) { |
1070 // The literal `Foo` where Foo is a class, a typedef, or a type variable. | 1044 // The literal `Foo` where Foo is a class, a typedef, or a type variable. |
1071 if (elements.isTypeLiteral(node)) { | 1045 if (elements.isTypeLiteral(node)) { |
1072 return new TypeLiteralAccess(elements.getTypeLiteralType(node)); | 1046 return new TypeLiteralAccess(elements.getTypeLiteralType(node)); |
1073 } | 1047 } |
1074 return createResolvedAccess(node, name, element); | 1048 return createResolvedAccess(node, name, element); |
1075 } else if (element.isClassMember) { | 1049 } else if (element.isClassMember) { |
1076 // foo() where foo is a member. | 1050 // foo() where foo is a member. |
1077 return lookupMember(node, thisType, name, memberKind, null, | 1051 return lookupMember(node, thisType, name, memberKind, null, |
1078 lookupClassMember: element.isStatic); | 1052 lookupClassMember: element.isStatic); |
1079 } else if (element.isFunction) { | 1053 } else if (element.isFunction) { |
1080 // foo() where foo is a method in the same class. | 1054 // foo() where foo is a method in the same class. |
1081 return createResolvedAccess(node, name, element); | 1055 return createResolvedAccess(node, name, element); |
1082 } else if (element.isVariable || | 1056 } else if (element.isVariable || element.isParameter || element.isField) { |
1083 element.isParameter || | |
1084 element.isField) { | |
1085 // foo() where foo is a field in the same class. | 1057 // foo() where foo is a field in the same class. |
1086 return createResolvedAccess(node, name, element); | 1058 return createResolvedAccess(node, name, element); |
1087 } else if (element.isGetter || element.isSetter) { | 1059 } else if (element.isGetter || element.isSetter) { |
1088 return createResolvedAccess(node, name, element); | 1060 return createResolvedAccess(node, name, element); |
1089 } else { | 1061 } else { |
1090 reporter.internalError(element, | 1062 reporter.internalError( |
1091 'Unexpected element kind ${element.kind}.'); | 1063 element, 'Unexpected element kind ${element.kind}.'); |
1092 return null; | 1064 return null; |
1093 } | 1065 } |
1094 } | 1066 } |
1095 | 1067 |
1096 ElementAccess createResolvedAccess(Send node, String name, | 1068 ElementAccess createResolvedAccess(Send node, String name, Element element) { |
1097 Element element) { | |
1098 checkPrivateAccess(node, element, name); | 1069 checkPrivateAccess(node, element, name); |
1099 return createPromotedAccess(element); | 1070 return createPromotedAccess(element); |
1100 } | 1071 } |
1101 | 1072 |
1102 ElementAccess createPromotedAccess(Element element) { | 1073 ElementAccess createPromotedAccess(Element element) { |
1103 if (element.isVariable || element.isParameter) { | 1074 if (element.isVariable || element.isParameter) { |
1104 TypePromotion typePromotion = getKnownTypePromotion(element); | 1075 TypePromotion typePromotion = getKnownTypePromotion(element); |
1105 if (typePromotion != null) { | 1076 if (typePromotion != null) { |
1106 return new PromotedAccess(element, typePromotion.type); | 1077 return new PromotedAccess(element, typePromotion.type); |
1107 } | 1078 } |
1108 } | 1079 } |
1109 return new ResolvedAccess(element); | 1080 return new ResolvedAccess(element); |
1110 } | 1081 } |
1111 | 1082 |
1112 /** | 1083 /** |
1113 * Computes the type of the access of [name] on the [node] possibly using the | 1084 * Computes the type of the access of [name] on the [node] possibly using the |
1114 * [element] provided for [node] by the resolver. | 1085 * [element] provided for [node] by the resolver. |
1115 */ | 1086 */ |
1116 DartType computeAccessType(Send node, String name, Element element, | 1087 DartType computeAccessType( |
1117 MemberKind memberKind, | 1088 Send node, String name, Element element, MemberKind memberKind, |
1118 {bool lookupClassMember: false}) { | 1089 {bool lookupClassMember: false}) { |
1119 DartType type = | 1090 DartType type = computeAccess(node, name, element, memberKind, |
1120 computeAccess(node, name, element, memberKind, | 1091 lookupClassMember: lookupClassMember) |
1121 lookupClassMember: lookupClassMember).computeType(resolution); | 1092 .computeType(resolution); |
1122 if (type == null) { | 1093 if (type == null) { |
1123 reporter.internalError(node, 'Type is null on access of $name on $node.'); | 1094 reporter.internalError(node, 'Type is null on access of $name on $node.'); |
1124 } | 1095 } |
1125 return type; | 1096 return type; |
1126 } | 1097 } |
1127 | 1098 |
1128 /// Compute a version of [shownType] that is more specific that [knownType]. | 1099 /// Compute a version of [shownType] that is more specific that [knownType]. |
1129 /// This is used to provided better hints when trying to promote a supertype | 1100 /// This is used to provided better hints when trying to promote a supertype |
1130 /// to a raw subtype. For instance trying to promote `Iterable<int>` to `List` | 1101 /// to a raw subtype. For instance trying to promote `Iterable<int>` to `List` |
1131 /// we suggest the use of `List<int>`, which would make promotion valid. | 1102 /// we suggest the use of `List<int>`, which would make promotion valid. |
1132 DartType computeMoreSpecificType(DartType shownType, | 1103 DartType computeMoreSpecificType(DartType shownType, DartType knownType) { |
1133 DartType knownType) { | |
1134 if (knownType.isInterfaceType && | 1104 if (knownType.isInterfaceType && |
1135 shownType.isInterfaceType && | 1105 shownType.isInterfaceType && |
1136 types.isSubtype(shownType.asRaw(), knownType)) { | 1106 types.isSubtype(shownType.asRaw(), knownType)) { |
1137 // For the comments in the block, assume the hierarchy: | 1107 // For the comments in the block, assume the hierarchy: |
1138 // class A<T, V> {} | 1108 // class A<T, V> {} |
1139 // class B<S, U> extends A<S, int> {} | 1109 // class B<S, U> extends A<S, int> {} |
1140 // and a promotion from a [knownType] of `A<double, int>` to a | 1110 // and a promotion from a [knownType] of `A<double, int>` to a |
1141 // [shownType] of `B`. | 1111 // [shownType] of `B`. |
1142 InterfaceType knownInterfaceType = knownType; | 1112 InterfaceType knownInterfaceType = knownType; |
1143 ClassElement shownClass = shownType.element; | 1113 ClassElement shownClass = shownType.element; |
1144 | 1114 |
1145 // Compute `B<double, dynamic>` as the subtype of `A<double, int>` using | 1115 // Compute `B<double, dynamic>` as the subtype of `A<double, int>` using |
1146 // the relation between `A<S, int>` and `A<double, int>`. | 1116 // the relation between `A<S, int>` and `A<double, int>`. |
1147 MoreSpecificSubtypeVisitor visitor = | 1117 MoreSpecificSubtypeVisitor visitor = |
1148 new MoreSpecificSubtypeVisitor(types); | 1118 new MoreSpecificSubtypeVisitor(types); |
1149 InterfaceType shownTypeGeneric = visitor.computeMoreSpecific( | 1119 InterfaceType shownTypeGeneric = |
1150 shownClass, knownInterfaceType); | 1120 visitor.computeMoreSpecific(shownClass, knownInterfaceType); |
1151 | 1121 |
1152 if (shownTypeGeneric != null && | 1122 if (shownTypeGeneric != null && |
1153 types.isMoreSpecific(shownTypeGeneric, knownType)) { | 1123 types.isMoreSpecific(shownTypeGeneric, knownType)) { |
1154 // This should be the case but we double-check. | 1124 // This should be the case but we double-check. |
1155 // TODO(johnniwinther): Ensure that we don't suggest malbounded types. | 1125 // TODO(johnniwinther): Ensure that we don't suggest malbounded types. |
1156 return shownTypeGeneric; | 1126 return shownTypeGeneric; |
1157 } | 1127 } |
1158 } | 1128 } |
1159 return null; | 1129 return null; |
1160 | |
1161 } | 1130 } |
1162 | 1131 |
1163 static bool _fyiShown = false; | 1132 static bool _fyiShown = false; |
1164 DartType _record(Node node, DartType type) { | 1133 DartType _record(Node node, DartType type) { |
1165 if (node is! Expression) return type; | 1134 if (node is! Expression) return type; |
1166 if (const bool.fromEnvironment('send_stats') && | 1135 if (const bool.fromEnvironment('send_stats') && |
1167 executableContext != null && | 1136 executableContext != null && |
1168 // TODO(sigmund): enable also in core libs. | 1137 // TODO(sigmund): enable also in core libs. |
1169 !executableContext.library.isPlatformLibrary && !type.isDynamic) { | 1138 !executableContext.library.isPlatformLibrary && |
| 1139 !type.isDynamic) { |
1170 if (!_fyiShown) { | 1140 if (!_fyiShown) { |
1171 print('FYI experiment to collect send stats is on: ' | 1141 print('FYI experiment to collect send stats is on: ' |
1172 'caching types of expressions'); | 1142 'caching types of expressions'); |
1173 _fyiShown = true; | 1143 _fyiShown = true; |
1174 } | 1144 } |
1175 elements.typesCache[node] = type; | 1145 elements.typesCache[node] = type; |
1176 } | 1146 } |
1177 return type; | 1147 return type; |
1178 } | 1148 } |
1179 | 1149 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1229 // Look for the variable element within parenthesized expressions. | 1199 // Look for the variable element within parenthesized expressions. |
1230 ParenthesizedExpression parentheses = | 1200 ParenthesizedExpression parentheses = |
1231 node.receiver.asParenthesizedExpression(); | 1201 node.receiver.asParenthesizedExpression(); |
1232 while (parentheses != null) { | 1202 while (parentheses != null) { |
1233 variable = elements[parentheses.expression]; | 1203 variable = elements[parentheses.expression]; |
1234 if (variable != null) break; | 1204 if (variable != null) break; |
1235 parentheses = parentheses.expression.asParenthesizedExpression(); | 1205 parentheses = parentheses.expression.asParenthesizedExpression(); |
1236 } | 1206 } |
1237 } | 1207 } |
1238 | 1208 |
1239 if (variable != null && | 1209 if (variable != null && (variable.isVariable || variable.isParameter)) { |
1240 (variable.isVariable || variable.isParameter)) { | |
1241 DartType knownType = getKnownType(variable); | 1210 DartType knownType = getKnownType(variable); |
1242 if (!knownType.isDynamic) { | 1211 if (!knownType.isDynamic) { |
1243 DartType shownType = elements.getType(node.arguments.head); | 1212 DartType shownType = elements.getType(node.arguments.head); |
1244 TypePromotion typePromotion = | 1213 TypePromotion typePromotion = |
1245 new TypePromotion(node, variable, shownType); | 1214 new TypePromotion(node, variable, shownType); |
1246 if (!types.isMoreSpecific(shownType, knownType)) { | 1215 if (!types.isMoreSpecific(shownType, knownType)) { |
1247 String variableName = variable.name; | 1216 String variableName = variable.name; |
1248 if (!types.isSubtype(shownType, knownType)) { | 1217 if (!types.isSubtype(shownType, knownType)) { |
1249 typePromotion.addHint(reporter.createMessage( | 1218 typePromotion.addHint(reporter.createMessage( |
1250 node, | 1219 node, MessageKind.NOT_MORE_SPECIFIC_SUBTYPE, { |
1251 MessageKind.NOT_MORE_SPECIFIC_SUBTYPE, | 1220 'variableName': variableName, |
1252 {'variableName': variableName, | 1221 'shownType': shownType, |
1253 'shownType': shownType, | 1222 'knownType': knownType |
1254 'knownType': knownType})); | 1223 })); |
1255 } else { | 1224 } else { |
1256 DartType shownTypeSuggestion = | 1225 DartType shownTypeSuggestion = |
1257 computeMoreSpecificType(shownType, knownType); | 1226 computeMoreSpecificType(shownType, knownType); |
1258 if (shownTypeSuggestion != null) { | 1227 if (shownTypeSuggestion != null) { |
1259 typePromotion.addHint(reporter.createMessage( | 1228 typePromotion.addHint(reporter.createMessage( |
1260 node, | 1229 node, MessageKind.NOT_MORE_SPECIFIC_SUGGESTION, { |
1261 MessageKind.NOT_MORE_SPECIFIC_SUGGESTION, | 1230 'variableName': variableName, |
1262 {'variableName': variableName, | 1231 'shownType': shownType, |
1263 'shownType': shownType, | 1232 'shownTypeSuggestion': shownTypeSuggestion, |
1264 'shownTypeSuggestion': shownTypeSuggestion, | 1233 'knownType': knownType |
1265 'knownType': knownType})); | 1234 })); |
1266 } else { | 1235 } else { |
1267 typePromotion.addHint(reporter.createMessage( | 1236 typePromotion.addHint(reporter.createMessage( |
1268 node, | 1237 node, MessageKind.NOT_MORE_SPECIFIC, { |
1269 MessageKind.NOT_MORE_SPECIFIC, | 1238 'variableName': variableName, |
1270 {'variableName': variableName, | 1239 'shownType': shownType, |
1271 'shownType': shownType, | 1240 'knownType': knownType |
1272 'knownType': knownType})); | 1241 })); |
1273 } | 1242 } |
1274 } | 1243 } |
1275 } | 1244 } |
1276 showTypePromotion(node, typePromotion); | 1245 showTypePromotion(node, typePromotion); |
1277 } | 1246 } |
1278 } | 1247 } |
1279 } | 1248 } |
1280 return boolType; | 1249 return boolType; |
1281 } if (node.isOperator && identical(name, 'as')) { | 1250 } |
| 1251 if (node.isOperator && identical(name, 'as')) { |
1282 analyze(node.receiver); | 1252 analyze(node.receiver); |
1283 return elements.getType(node.arguments.head); | 1253 return elements.getType(node.arguments.head); |
1284 } else if (node.isOperator) { | 1254 } else if (node.isOperator) { |
1285 final Node receiver = node.receiver; | 1255 final Node receiver = node.receiver; |
1286 final DartType receiverType = analyze(receiver); | 1256 final DartType receiverType = analyze(receiver); |
1287 if (identical(name, '==') || identical(name, '!=') | 1257 if (identical(name, '==') || |
| 1258 identical(name, '!=') |
1288 // TODO(johnniwinther): Remove these. | 1259 // TODO(johnniwinther): Remove these. |
1289 || identical(name, '===') || identical(name, '!==')) { | 1260 || |
| 1261 identical(name, '===') || |
| 1262 identical(name, '!==')) { |
1290 // Analyze argument. | 1263 // Analyze argument. |
1291 analyze(node.arguments.head); | 1264 analyze(node.arguments.head); |
1292 return boolType; | 1265 return boolType; |
1293 } else if (identical(name, '||')) { | 1266 } else if (identical(name, '||')) { |
1294 checkAssignable(receiver, receiverType, boolType); | 1267 checkAssignable(receiver, receiverType, boolType); |
1295 final Node argument = node.arguments.head; | 1268 final Node argument = node.arguments.head; |
1296 final DartType argumentType = analyze(argument); | 1269 final DartType argumentType = analyze(argument); |
1297 checkAssignable(argument, argumentType, boolType); | 1270 checkAssignable(argument, argumentType, boolType); |
1298 return boolType; | 1271 return boolType; |
1299 } else if (identical(name, '&&')) { | 1272 } else if (identical(name, '&&')) { |
(...skipping 14 matching lines...) Expand all Loading... |
1314 return boolType; | 1287 return boolType; |
1315 } else if (identical(name, '??')) { | 1288 } else if (identical(name, '??')) { |
1316 final Node argument = node.arguments.head; | 1289 final Node argument = node.arguments.head; |
1317 final DartType argumentType = analyze(argument); | 1290 final DartType argumentType = analyze(argument); |
1318 return types.computeLeastUpperBound(receiverType, argumentType); | 1291 return types.computeLeastUpperBound(receiverType, argumentType); |
1319 } | 1292 } |
1320 String operatorName = selector.source; | 1293 String operatorName = selector.source; |
1321 if (identical(name, '-') && node.arguments.isEmpty) { | 1294 if (identical(name, '-') && node.arguments.isEmpty) { |
1322 operatorName = 'unary-'; | 1295 operatorName = 'unary-'; |
1323 } | 1296 } |
1324 assert(invariant(node, | 1297 assert(invariant( |
1325 identical(name, '+') || identical(name, '=') || | 1298 node, |
1326 identical(name, '-') || identical(name, '*') || | 1299 identical(name, '+') || |
1327 identical(name, '/') || identical(name, '%') || | 1300 identical(name, '=') || |
1328 identical(name, '~/') || identical(name, '|') || | 1301 identical(name, '-') || |
1329 identical(name, '&') || identical(name, '^') || | 1302 identical(name, '*') || |
1330 identical(name, '~')|| identical(name, '<<') || | 1303 identical(name, '/') || |
1331 identical(name, '>>') || | 1304 identical(name, '%') || |
1332 identical(name, '<') || identical(name, '>') || | 1305 identical(name, '~/') || |
1333 identical(name, '<=') || identical(name, '>=') || | 1306 identical(name, '|') || |
1334 identical(name, '[]'), | 1307 identical(name, '&') || |
1335 message: 'Unexpected operator $name')); | 1308 identical(name, '^') || |
| 1309 identical(name, '~') || |
| 1310 identical(name, '<<') || |
| 1311 identical(name, '>>') || |
| 1312 identical(name, '<') || |
| 1313 identical(name, '>') || |
| 1314 identical(name, '<=') || |
| 1315 identical(name, '>=') || |
| 1316 identical(name, '[]'), |
| 1317 message: 'Unexpected operator $name')); |
1336 | 1318 |
1337 // TODO(karlklose): handle `void` in expression context by calling | 1319 // TODO(karlklose): handle `void` in expression context by calling |
1338 // [analyzeNonVoid] instead of [analyze]. | 1320 // [analyzeNonVoid] instead of [analyze]. |
1339 ElementAccess access = receiverType.isVoid ? const DynamicAccess() | 1321 ElementAccess access = receiverType.isVoid |
1340 : lookupMember(node, receiverType, operatorName, | 1322 ? const DynamicAccess() |
1341 MemberKind.OPERATOR, null); | 1323 : lookupMember( |
| 1324 node, receiverType, operatorName, MemberKind.OPERATOR, null); |
1342 LinkBuilder<DartType> argumentTypesBuilder = new LinkBuilder<DartType>(); | 1325 LinkBuilder<DartType> argumentTypesBuilder = new LinkBuilder<DartType>(); |
1343 DartType resultType = | 1326 DartType resultType = |
1344 analyzeInvocation(node, access, argumentTypesBuilder); | 1327 analyzeInvocation(node, access, argumentTypesBuilder); |
1345 if (receiverType == intType) { | 1328 if (receiverType == intType) { |
1346 if (identical(name, '+') || | 1329 if (identical(name, '+') || |
1347 identical(operatorName, '-') || | 1330 identical(operatorName, '-') || |
1348 identical(name, '*') || | 1331 identical(name, '*') || |
1349 identical(name, '%')) { | 1332 identical(name, '%')) { |
1350 DartType argumentType = argumentTypesBuilder.toLink().head; | 1333 DartType argumentType = argumentTypesBuilder.toLink().head; |
1351 if (argumentType == intType) { | 1334 if (argumentType == intType) { |
(...skipping 28 matching lines...) Expand all Loading... |
1380 */ | 1363 */ |
1381 DartType secondType(List<DartType> list) { | 1364 DartType secondType(List<DartType> list) { |
1382 return list.length < 2 ? const DynamicType() : list[1]; | 1365 return list.length < 2 ? const DynamicType() : list[1]; |
1383 } | 1366 } |
1384 | 1367 |
1385 /** | 1368 /** |
1386 * Checks [: target o= value :] for some operator o, and returns the type | 1369 * Checks [: target o= value :] for some operator o, and returns the type |
1387 * of the result. This method also handles increment/decrement expressions | 1370 * of the result. This method also handles increment/decrement expressions |
1388 * like [: target++ :]. | 1371 * like [: target++ :]. |
1389 */ | 1372 */ |
1390 DartType checkAssignmentOperator(SendSet node, | 1373 DartType checkAssignmentOperator( |
1391 String operatorName, | 1374 SendSet node, String operatorName, Node valueNode, DartType value) { |
1392 Node valueNode, | |
1393 DartType value) { | |
1394 assert(invariant(node, !node.isIndex)); | 1375 assert(invariant(node, !node.isIndex)); |
1395 Element setterElement = elements[node]; | 1376 Element setterElement = elements[node]; |
1396 Element getterElement = elements[node.selector]; | 1377 Element getterElement = elements[node.selector]; |
1397 Identifier selector = node.selector; | 1378 Identifier selector = node.selector; |
1398 DartType getter = computeAccessType( | 1379 DartType getter = computeAccessType( |
1399 node, selector.source, getterElement, MemberKind.GETTER); | 1380 node, selector.source, getterElement, MemberKind.GETTER); |
1400 DartType setter = computeAccessType( | 1381 DartType setter = computeAccessType( |
1401 node, selector.source, setterElement, MemberKind.SETTER); | 1382 node, selector.source, setterElement, MemberKind.SETTER); |
1402 // [operator] is the type of operator+ or operator- on [target]. | 1383 // [operator] is the type of operator+ or operator- on [target]. |
1403 DartType operator = | 1384 DartType operator = |
(...skipping 12 matching lines...) Expand all Loading... |
1416 return node.isPostfix ? getter : result; | 1397 return node.isPostfix ? getter : result; |
1417 } | 1398 } |
1418 return const DynamicType(); | 1399 return const DynamicType(); |
1419 } | 1400 } |
1420 | 1401 |
1421 /** | 1402 /** |
1422 * Checks [: base[key] o= value :] for some operator o, and returns the type | 1403 * Checks [: base[key] o= value :] for some operator o, and returns the type |
1423 * of the result. This method also handles increment/decrement expressions | 1404 * of the result. This method also handles increment/decrement expressions |
1424 * like [: base[key]++ :]. | 1405 * like [: base[key]++ :]. |
1425 */ | 1406 */ |
1426 DartType checkIndexAssignmentOperator(SendSet node, | 1407 DartType checkIndexAssignmentOperator( |
1427 String operatorName, | 1408 SendSet node, String operatorName, Node valueNode, DartType value) { |
1428 Node valueNode, | |
1429 DartType value) { | |
1430 assert(invariant(node, node.isIndex)); | 1409 assert(invariant(node, node.isIndex)); |
1431 final DartType base = analyze(node.receiver); | 1410 final DartType base = analyze(node.receiver); |
1432 final Node keyNode = node.arguments.head; | 1411 final Node keyNode = node.arguments.head; |
1433 final DartType key = analyze(keyNode); | 1412 final DartType key = analyze(keyNode); |
1434 | 1413 |
1435 // [indexGet] is the type of operator[] on [base]. | 1414 // [indexGet] is the type of operator[] on [base]. |
1436 DartType indexGet = lookupMemberType( | 1415 DartType indexGet = lookupMemberType(node, base, '[]', MemberKind.OPERATOR); |
1437 node, base, '[]', MemberKind.OPERATOR); | |
1438 if (indexGet is FunctionType) { | 1416 if (indexGet is FunctionType) { |
1439 FunctionType indexGetType = indexGet; | 1417 FunctionType indexGetType = indexGet; |
1440 DartType indexGetKey = firstType(indexGetType.parameterTypes); | 1418 DartType indexGetKey = firstType(indexGetType.parameterTypes); |
1441 // Check base[key]. | 1419 // Check base[key]. |
1442 bool validKey = checkAssignable(keyNode, key, indexGetKey); | 1420 bool validKey = checkAssignable(keyNode, key, indexGetKey); |
1443 | 1421 |
1444 // [element] is the type of base[key]. | 1422 // [element] is the type of base[key]. |
1445 DartType element = indexGetType.returnType; | 1423 DartType element = indexGetType.returnType; |
1446 // [operator] is the type of operator o on [element]. | 1424 // [operator] is the type of operator o on [element]. |
1447 DartType operator = lookupMemberType( | 1425 DartType operator = |
1448 node, element, operatorName, MemberKind.OPERATOR); | 1426 lookupMemberType(node, element, operatorName, MemberKind.OPERATOR); |
1449 if (operator is FunctionType) { | 1427 if (operator is FunctionType) { |
1450 FunctionType operatorType = operator; | 1428 FunctionType operatorType = operator; |
1451 | 1429 |
1452 // Check base[key] o value. | 1430 // Check base[key] o value. |
1453 DartType operatorArgument = firstType(operatorType.parameterTypes); | 1431 DartType operatorArgument = firstType(operatorType.parameterTypes); |
1454 bool validValue = checkAssignable(valueNode, value, operatorArgument); | 1432 bool validValue = checkAssignable(valueNode, value, operatorArgument); |
1455 | 1433 |
1456 // [result] is the type of base[key] o value. | 1434 // [result] is the type of base[key] o value. |
1457 DartType result = operatorType.returnType; | 1435 DartType result = operatorType.returnType; |
1458 | 1436 |
1459 // [indexSet] is the type of operator[]= on [base]. | 1437 // [indexSet] is the type of operator[]= on [base]. |
1460 DartType indexSet = lookupMemberType( | 1438 DartType indexSet = |
1461 node, base, '[]=', MemberKind.OPERATOR); | 1439 lookupMemberType(node, base, '[]=', MemberKind.OPERATOR); |
1462 if (indexSet is FunctionType) { | 1440 if (indexSet is FunctionType) { |
1463 FunctionType indexSetType = indexSet; | 1441 FunctionType indexSetType = indexSet; |
1464 DartType indexSetKey = firstType(indexSetType.parameterTypes); | 1442 DartType indexSetKey = firstType(indexSetType.parameterTypes); |
1465 DartType indexSetValue = secondType(indexSetType.parameterTypes); | 1443 DartType indexSetValue = secondType(indexSetType.parameterTypes); |
1466 | 1444 |
1467 if (validKey || indexGetKey != indexSetKey) { | 1445 if (validKey || indexGetKey != indexSetKey) { |
1468 // Only check base[key] on []= if base[key] was valid for [] or | 1446 // Only check base[key] on []= if base[key] was valid for [] or |
1469 // if the key types differ. | 1447 // if the key types differ. |
1470 checkAssignable(keyNode, key, indexSetKey); | 1448 checkAssignable(keyNode, key, indexSetKey); |
1471 } | 1449 } |
1472 // Check base[key] = result | 1450 // Check base[key] = result |
1473 if (validValue || !(node.isPrefix || node.isPostfix)) { | 1451 if (validValue || !(node.isPrefix || node.isPostfix)) { |
1474 checkAssignable(node.assignmentOperator, result, indexSetValue); | 1452 checkAssignable(node.assignmentOperator, result, indexSetValue); |
1475 } | 1453 } |
1476 } | 1454 } |
1477 return node.isPostfix ? element : result; | 1455 return node.isPostfix ? element : result; |
1478 } | 1456 } |
1479 } | 1457 } |
1480 return const DynamicType(); | 1458 return const DynamicType(); |
1481 } | 1459 } |
1482 | 1460 |
1483 visitSendSet(SendSet node) { | 1461 visitSendSet(SendSet node) { |
1484 Element element = elements[node]; | 1462 Element element = elements[node]; |
1485 Identifier selector = node.selector; | 1463 Identifier selector = node.selector; |
1486 final name = node.assignmentOperator.source; | 1464 final name = node.assignmentOperator.source; |
1487 if (identical(name, '=') || identical(name, '??=')) { | 1465 if (identical(name, '=') || identical(name, '??=')) { |
1488 // e1 = value | 1466 // e1 = value |
1489 if (node.isIndex) { | 1467 if (node.isIndex) { |
1490 // base[key] = value | 1468 // base[key] = value |
1491 final DartType base = analyze(node.receiver); | 1469 final DartType base = analyze(node.receiver); |
1492 final Node keyNode = node.arguments.head; | 1470 final Node keyNode = node.arguments.head; |
1493 final DartType key = analyze(keyNode); | 1471 final DartType key = analyze(keyNode); |
1494 final Node valueNode = node.arguments.tail.head; | 1472 final Node valueNode = node.arguments.tail.head; |
1495 final DartType value = analyze(valueNode); | 1473 final DartType value = analyze(valueNode); |
1496 DartType indexSet = lookupMemberType( | 1474 DartType indexSet = |
1497 node, base, '[]=', MemberKind.OPERATOR); | 1475 lookupMemberType(node, base, '[]=', MemberKind.OPERATOR); |
1498 DartType indexSetValue = const DynamicType(); | 1476 DartType indexSetValue = const DynamicType(); |
1499 if (indexSet is FunctionType) { | 1477 if (indexSet is FunctionType) { |
1500 FunctionType indexSetType = indexSet; | 1478 FunctionType indexSetType = indexSet; |
1501 DartType indexSetKey = firstType(indexSetType.parameterTypes); | 1479 DartType indexSetKey = firstType(indexSetType.parameterTypes); |
1502 checkAssignable(keyNode, key, indexSetKey); | 1480 checkAssignable(keyNode, key, indexSetKey); |
1503 indexSetValue = secondType(indexSetType.parameterTypes); | 1481 indexSetValue = secondType(indexSetType.parameterTypes); |
1504 checkAssignable(node.assignmentOperator, value, indexSetValue); | 1482 checkAssignable(node.assignmentOperator, value, indexSetValue); |
1505 } | 1483 } |
1506 return identical(name, '=') ? value | 1484 return identical(name, '=') |
| 1485 ? value |
1507 : types.computeLeastUpperBound(value, indexSetValue); | 1486 : types.computeLeastUpperBound(value, indexSetValue); |
1508 } else { | 1487 } else { |
1509 // target = value | 1488 // target = value |
1510 DartType target; | 1489 DartType target; |
1511 if (analyzingInitializer) { | 1490 if (analyzingInitializer) { |
1512 // Field declaration `Foo target = value;` or initializer | 1491 // Field declaration `Foo target = value;` or initializer |
1513 // `this.target = value`. Lookup the getter `target` in the class | 1492 // `this.target = value`. Lookup the getter `target` in the class |
1514 // members. | 1493 // members. |
1515 target = computeAccessType(node, selector.source, element, | 1494 target = computeAccessType( |
1516 MemberKind.GETTER, lookupClassMember: true); | 1495 node, selector.source, element, MemberKind.GETTER, |
| 1496 lookupClassMember: true); |
1517 } else { | 1497 } else { |
1518 // Normal assignment `target = value`. | 1498 // Normal assignment `target = value`. |
1519 target = computeAccessType( | 1499 target = computeAccessType( |
1520 node, selector.source, element, MemberKind.SETTER); | 1500 node, selector.source, element, MemberKind.SETTER); |
1521 } | 1501 } |
1522 final Node valueNode = node.arguments.head; | 1502 final Node valueNode = node.arguments.head; |
1523 final DartType value = analyze(valueNode); | 1503 final DartType value = analyze(valueNode); |
1524 checkAssignable(node.assignmentOperator, value, target); | 1504 checkAssignable(node.assignmentOperator, value, target); |
1525 return identical(name, '=') ? value | 1505 return identical(name, '=') |
| 1506 ? value |
1526 : types.computeLeastUpperBound(value, target); | 1507 : types.computeLeastUpperBound(value, target); |
1527 } | 1508 } |
1528 } else if (identical(name, '++') || identical(name, '--')) { | 1509 } else if (identical(name, '++') || identical(name, '--')) { |
1529 // e++ or e-- | 1510 // e++ or e-- |
1530 String operatorName = identical(name, '++') ? '+' : '-'; | 1511 String operatorName = identical(name, '++') ? '+' : '-'; |
1531 if (node.isIndex) { | 1512 if (node.isIndex) { |
1532 // base[key]++, base[key]--, ++base[key], or --base[key] | 1513 // base[key]++, base[key]--, ++base[key], or --base[key] |
1533 return checkIndexAssignmentOperator( | 1514 return checkIndexAssignmentOperator( |
1534 node, operatorName, node.assignmentOperator, intType); | 1515 node, operatorName, node.assignmentOperator, intType); |
1535 } else { | 1516 } else { |
1536 // target++, target--, ++target, or --target | 1517 // target++, target--, ++target, or --target |
1537 return checkAssignmentOperator( | 1518 return checkAssignmentOperator( |
1538 node, operatorName, node.assignmentOperator, intType); | 1519 node, operatorName, node.assignmentOperator, intType); |
1539 } | 1520 } |
1540 } else { | 1521 } else { |
1541 // e1 o= e2 for some operator o. | 1522 // e1 o= e2 for some operator o. |
1542 String operatorName; | 1523 String operatorName; |
1543 switch (name) { | 1524 switch (name) { |
1544 case '+=': operatorName = '+'; break; | 1525 case '+=': |
1545 case '-=': operatorName = '-'; break; | 1526 operatorName = '+'; |
1546 case '*=': operatorName = '*'; break; | 1527 break; |
1547 case '/=': operatorName = '/'; break; | 1528 case '-=': |
1548 case '%=': operatorName = '%'; break; | 1529 operatorName = '-'; |
1549 case '~/=': operatorName = '~/'; break; | 1530 break; |
1550 case '&=': operatorName = '&'; break; | 1531 case '*=': |
1551 case '|=': operatorName = '|'; break; | 1532 operatorName = '*'; |
1552 case '^=': operatorName = '^'; break; | 1533 break; |
1553 case '<<=': operatorName = '<<'; break; | 1534 case '/=': |
1554 case '>>=': operatorName = '>>'; break; | 1535 operatorName = '/'; |
| 1536 break; |
| 1537 case '%=': |
| 1538 operatorName = '%'; |
| 1539 break; |
| 1540 case '~/=': |
| 1541 operatorName = '~/'; |
| 1542 break; |
| 1543 case '&=': |
| 1544 operatorName = '&'; |
| 1545 break; |
| 1546 case '|=': |
| 1547 operatorName = '|'; |
| 1548 break; |
| 1549 case '^=': |
| 1550 operatorName = '^'; |
| 1551 break; |
| 1552 case '<<=': |
| 1553 operatorName = '<<'; |
| 1554 break; |
| 1555 case '>>=': |
| 1556 operatorName = '>>'; |
| 1557 break; |
1555 default: | 1558 default: |
1556 reporter.internalError(node, 'Unexpected assignment operator $name.'); | 1559 reporter.internalError(node, 'Unexpected assignment operator $name.'); |
1557 } | 1560 } |
1558 if (node.isIndex) { | 1561 if (node.isIndex) { |
1559 // base[key] o= value for some operator o. | 1562 // base[key] o= value for some operator o. |
1560 final Node valueNode = node.arguments.tail.head; | 1563 final Node valueNode = node.arguments.tail.head; |
1561 final DartType value = analyze(valueNode); | 1564 final DartType value = analyze(valueNode); |
1562 return checkIndexAssignmentOperator( | 1565 return checkIndexAssignmentOperator( |
1563 node, operatorName, valueNode, value); | 1566 node, operatorName, valueNode, value); |
1564 } else { | 1567 } else { |
(...skipping 28 matching lines...) Expand all Loading... |
1593 } | 1596 } |
1594 | 1597 |
1595 DartType visitLiteralNull(LiteralNull node) { | 1598 DartType visitLiteralNull(LiteralNull node) { |
1596 return const DynamicType(); | 1599 return const DynamicType(); |
1597 } | 1600 } |
1598 | 1601 |
1599 DartType visitLiteralSymbol(LiteralSymbol node) { | 1602 DartType visitLiteralSymbol(LiteralSymbol node) { |
1600 return coreTypes.symbolType; | 1603 return coreTypes.symbolType; |
1601 } | 1604 } |
1602 | 1605 |
1603 DartType computeConstructorType(ConstructorElement constructor, | 1606 DartType computeConstructorType( |
1604 DartType type) { | 1607 ConstructorElement constructor, DartType type) { |
1605 if (Elements.isUnresolved(constructor)) return const DynamicType(); | 1608 if (Elements.isUnresolved(constructor)) return const DynamicType(); |
1606 DartType constructorType = constructor.computeType(resolution); | 1609 DartType constructorType = constructor.computeType(resolution); |
1607 if (identical(type.kind, TypeKind.INTERFACE)) { | 1610 if (identical(type.kind, TypeKind.INTERFACE)) { |
1608 if (constructor.isSynthesized) { | 1611 if (constructor.isSynthesized) { |
1609 // TODO(johnniwinther): Remove this when synthesized constructors handle | 1612 // TODO(johnniwinther): Remove this when synthesized constructors handle |
1610 // type variables correctly. | 1613 // type variables correctly. |
1611 InterfaceType interfaceType = type; | 1614 InterfaceType interfaceType = type; |
1612 ClassElement receiverElement = interfaceType.element; | 1615 ClassElement receiverElement = interfaceType.element; |
1613 while (receiverElement.isMixinApplication) { | 1616 while (receiverElement.isMixinApplication) { |
1614 receiverElement = receiverElement.supertype.element; | 1617 receiverElement = receiverElement.supertype.element; |
1615 } | 1618 } |
1616 constructorType = constructorType.substByContext( | 1619 constructorType = constructorType |
1617 interfaceType.asInstanceOf(receiverElement)); | 1620 .substByContext(interfaceType.asInstanceOf(receiverElement)); |
1618 } else { | 1621 } else { |
1619 constructorType = constructorType.substByContext(type); | 1622 constructorType = constructorType.substByContext(type); |
1620 } | 1623 } |
1621 } | 1624 } |
1622 return constructorType; | 1625 return constructorType; |
1623 } | 1626 } |
1624 | 1627 |
1625 DartType visitNewExpression(NewExpression node) { | 1628 DartType visitNewExpression(NewExpression node) { |
1626 Element element = elements[node.send]; | 1629 Element element = elements[node.send]; |
1627 if (Elements.isUnresolved(element)) return const DynamicType(); | 1630 if (Elements.isUnresolved(element)) return const DynamicType(); |
1628 | 1631 |
1629 checkPrivateAccess(node, element, element.name); | 1632 checkPrivateAccess(node, element, element.name); |
1630 | 1633 |
1631 DartType newType = elements.getType(node); | 1634 DartType newType = elements.getType(node); |
1632 DartType constructorType = computeConstructorType(element, newType); | 1635 DartType constructorType = computeConstructorType(element, newType); |
1633 analyzeArguments(node.send, element, constructorType); | 1636 analyzeArguments(node.send, element, constructorType); |
1634 return newType; | 1637 return newType; |
1635 } | 1638 } |
1636 | 1639 |
1637 DartType visitLiteralList(LiteralList node) { | 1640 DartType visitLiteralList(LiteralList node) { |
1638 InterfaceType listType = elements.getType(node); | 1641 InterfaceType listType = elements.getType(node); |
1639 DartType listElementType = firstType(listType.typeArguments); | 1642 DartType listElementType = firstType(listType.typeArguments); |
1640 for (Link<Node> link = node.elements.nodes; | 1643 for (Link<Node> link = node.elements.nodes; |
1641 !link.isEmpty; | 1644 !link.isEmpty; |
1642 link = link.tail) { | 1645 link = link.tail) { |
1643 Node element = link.head; | 1646 Node element = link.head; |
1644 DartType elementType = analyze(element); | 1647 DartType elementType = analyze(element); |
1645 checkAssignable(element, elementType, listElementType, | 1648 checkAssignable(element, elementType, listElementType, |
1646 isConst: node.isConst); | 1649 isConst: node.isConst); |
1647 } | 1650 } |
1648 return listType; | 1651 return listType; |
1649 } | 1652 } |
1650 | 1653 |
1651 DartType visitNodeList(NodeList node) { | 1654 DartType visitNodeList(NodeList node) { |
1652 for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) { | 1655 for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) { |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1692 } | 1695 } |
1693 } | 1696 } |
1694 } else if (currentAsyncMarker != AsyncMarker.SYNC) { | 1697 } else if (currentAsyncMarker != AsyncMarker.SYNC) { |
1695 // `return;` is allowed. | 1698 // `return;` is allowed. |
1696 } else if (!types.isAssignable(expectedReturnType, const VoidType())) { | 1699 } else if (!types.isAssignable(expectedReturnType, const VoidType())) { |
1697 // Let f be the function immediately enclosing a return statement of the | 1700 // Let f be the function immediately enclosing a return statement of the |
1698 // form 'return;' It is a static warning if both of the following | 1701 // form 'return;' It is a static warning if both of the following |
1699 // conditions hold: | 1702 // conditions hold: |
1700 // - f is not a generative constructor. | 1703 // - f is not a generative constructor. |
1701 // - The return type of f may not be assigned to void. | 1704 // - The return type of f may not be assigned to void. |
1702 reportTypeWarning(node, MessageKind.RETURN_NOTHING, | 1705 reportTypeWarning( |
1703 {'returnType': expectedReturnType}); | 1706 node, MessageKind.RETURN_NOTHING, {'returnType': expectedReturnType}); |
1704 } | 1707 } |
1705 return const StatementType(); | 1708 return const StatementType(); |
1706 } | 1709 } |
1707 | 1710 |
1708 DartType visitThrow(Throw node) { | 1711 DartType visitThrow(Throw node) { |
1709 // TODO(johnniwinther): Handle reachability. | 1712 // TODO(johnniwinther): Handle reachability. |
1710 analyze(node.expression); | 1713 analyze(node.expression); |
1711 return const DynamicType(); | 1714 return const DynamicType(); |
1712 } | 1715 } |
1713 | 1716 |
(...skipping 27 matching lines...) Expand all Loading... |
1741 DartType visitTypeAnnotation(TypeAnnotation node) { | 1744 DartType visitTypeAnnotation(TypeAnnotation node) { |
1742 return elements.getType(node); | 1745 return elements.getType(node); |
1743 } | 1746 } |
1744 | 1747 |
1745 DartType visitVariableDefinitions(VariableDefinitions node) { | 1748 DartType visitVariableDefinitions(VariableDefinitions node) { |
1746 DartType type = analyzeWithDefault(node.type, const DynamicType()); | 1749 DartType type = analyzeWithDefault(node.type, const DynamicType()); |
1747 if (type.isVoid) { | 1750 if (type.isVoid) { |
1748 reportTypeWarning(node.type, MessageKind.VOID_VARIABLE); | 1751 reportTypeWarning(node.type, MessageKind.VOID_VARIABLE); |
1749 type = const DynamicType(); | 1752 type = const DynamicType(); |
1750 } | 1753 } |
1751 for (Link<Node> link = node.definitions.nodes; !link.isEmpty; | 1754 for (Link<Node> link = node.definitions.nodes; |
1752 link = link.tail) { | 1755 !link.isEmpty; |
| 1756 link = link.tail) { |
1753 Node definition = link.head; | 1757 Node definition = link.head; |
1754 invariant(definition, definition is Identifier || definition is SendSet, | 1758 invariant(definition, definition is Identifier || definition is SendSet, |
1755 message: 'expected identifier or initialization'); | 1759 message: 'expected identifier or initialization'); |
1756 if (definition is SendSet) { | 1760 if (definition is SendSet) { |
1757 SendSet initialization = definition; | 1761 SendSet initialization = definition; |
1758 DartType initializer = analyzeNonVoid(initialization.arguments.head); | 1762 DartType initializer = analyzeNonVoid(initialization.arguments.head); |
1759 checkAssignable(initialization.assignmentOperator, initializer, type); | 1763 checkAssignable(initialization.assignmentOperator, initializer, type); |
1760 // TODO(sigmund): explore inferring a type for `var` using the RHS (like | 1764 // TODO(sigmund): explore inferring a type for `var` using the RHS (like |
1761 // DDC does), for example: | 1765 // DDC does), for example: |
1762 // if (node.type == null && node.modifiers.isVar && | 1766 // if (node.type == null && node.modifiers.isVar && |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1819 } | 1823 } |
1820 | 1824 |
1821 visitContinueStatement(ContinueStatement node) { | 1825 visitContinueStatement(ContinueStatement node) { |
1822 return const StatementType(); | 1826 return const StatementType(); |
1823 } | 1827 } |
1824 | 1828 |
1825 DartType computeForInElementType(ForIn node) { | 1829 DartType computeForInElementType(ForIn node) { |
1826 VariableDefinitions declaredIdentifier = | 1830 VariableDefinitions declaredIdentifier = |
1827 node.declaredIdentifier.asVariableDefinitions(); | 1831 node.declaredIdentifier.asVariableDefinitions(); |
1828 if (declaredIdentifier != null) { | 1832 if (declaredIdentifier != null) { |
1829 return | 1833 return analyzeWithDefault(declaredIdentifier.type, const DynamicType()); |
1830 analyzeWithDefault(declaredIdentifier.type, const DynamicType()); | |
1831 } else { | 1834 } else { |
1832 return analyze(node.declaredIdentifier); | 1835 return analyze(node.declaredIdentifier); |
1833 } | 1836 } |
1834 } | 1837 } |
1835 | 1838 |
1836 visitAsyncForIn(AsyncForIn node) { | 1839 visitAsyncForIn(AsyncForIn node) { |
1837 DartType elementType = computeForInElementType(node); | 1840 DartType elementType = computeForInElementType(node); |
1838 DartType expressionType = analyze(node.expression); | 1841 DartType expressionType = analyze(node.expression); |
1839 DartType streamOfDynamic = coreTypes.streamType(); | 1842 DartType streamOfDynamic = coreTypes.streamType(); |
1840 if (!types.isAssignable(expressionType, streamOfDynamic)) { | 1843 if (!types.isAssignable(expressionType, streamOfDynamic)) { |
1841 reportMessage(node.expression, | 1844 reportMessage(node.expression, MessageKind.NOT_ASSIGNABLE, |
1842 MessageKind.NOT_ASSIGNABLE, | |
1843 {'fromType': expressionType, 'toType': streamOfDynamic}, | 1845 {'fromType': expressionType, 'toType': streamOfDynamic}, |
1844 isHint: true); | 1846 isHint: true); |
1845 } else { | 1847 } else { |
1846 InterfaceType interfaceType = | 1848 InterfaceType interfaceType = |
1847 Types.computeInterfaceType(resolution, expressionType); | 1849 Types.computeInterfaceType(resolution, expressionType); |
1848 if (interfaceType != null) { | 1850 if (interfaceType != null) { |
1849 InterfaceType streamType = | 1851 InterfaceType streamType = |
1850 interfaceType.asInstanceOf(streamOfDynamic.element); | 1852 interfaceType.asInstanceOf(streamOfDynamic.element); |
1851 if (streamType != null) { | 1853 if (streamType != null) { |
1852 DartType streamElementType = streamType.typeArguments.first; | 1854 DartType streamElementType = streamType.typeArguments.first; |
1853 if (!types.isAssignable(streamElementType, elementType)) { | 1855 if (!types.isAssignable(streamElementType, elementType)) { |
1854 reportMessage(node.expression, | 1856 reportMessage( |
| 1857 node.expression, |
1855 MessageKind.FORIN_NOT_ASSIGNABLE, | 1858 MessageKind.FORIN_NOT_ASSIGNABLE, |
1856 {'currentType': streamElementType, | 1859 { |
1857 'expressionType': expressionType, | 1860 'currentType': streamElementType, |
1858 'elementType': elementType}, | 1861 'expressionType': expressionType, |
| 1862 'elementType': elementType |
| 1863 }, |
1859 isHint: true); | 1864 isHint: true); |
1860 } | 1865 } |
1861 } | 1866 } |
1862 } | 1867 } |
1863 } | 1868 } |
1864 analyze(node.body); | 1869 analyze(node.body); |
1865 return const StatementType(); | 1870 return const StatementType(); |
1866 } | 1871 } |
1867 | 1872 |
1868 visitSyncForIn(SyncForIn node) { | 1873 visitSyncForIn(SyncForIn node) { |
1869 DartType elementType = computeForInElementType(node); | 1874 DartType elementType = computeForInElementType(node); |
1870 DartType expressionType = analyze(node.expression); | 1875 DartType expressionType = analyze(node.expression); |
1871 DartType iteratorType = lookupMemberType(node.expression, | 1876 DartType iteratorType = lookupMemberType(node.expression, expressionType, |
1872 expressionType, Identifiers.iterator, MemberKind.GETTER); | 1877 Identifiers.iterator, MemberKind.GETTER); |
1873 DartType currentType = lookupMemberType(node.expression, | 1878 DartType currentType = lookupMemberType( |
1874 iteratorType, Identifiers.current, MemberKind.GETTER, | 1879 node.expression, iteratorType, Identifiers.current, MemberKind.GETTER, |
1875 isHint: true); | 1880 isHint: true); |
1876 if (!types.isAssignable(currentType, elementType)) { | 1881 if (!types.isAssignable(currentType, elementType)) { |
1877 reportMessage(node.expression, | 1882 reportMessage( |
| 1883 node.expression, |
1878 MessageKind.FORIN_NOT_ASSIGNABLE, | 1884 MessageKind.FORIN_NOT_ASSIGNABLE, |
1879 {'currentType': currentType, | 1885 { |
1880 'expressionType': expressionType, | 1886 'currentType': currentType, |
1881 'elementType': elementType}, | 1887 'expressionType': expressionType, |
| 1888 'elementType': elementType |
| 1889 }, |
1882 isHint: true); | 1890 isHint: true); |
1883 } | 1891 } |
1884 analyze(node.body); | 1892 analyze(node.body); |
1885 return const StatementType(); | 1893 return const StatementType(); |
1886 } | 1894 } |
1887 | 1895 |
1888 visitLabeledStatement(LabeledStatement node) { | 1896 visitLabeledStatement(LabeledStatement node) { |
1889 return analyze(node.statement); | 1897 return analyze(node.statement); |
1890 } | 1898 } |
1891 | 1899 |
1892 visitLiteralMap(LiteralMap node) { | 1900 visitLiteralMap(LiteralMap node) { |
1893 InterfaceType mapType = elements.getType(node); | 1901 InterfaceType mapType = elements.getType(node); |
1894 DartType mapKeyType = firstType(mapType.typeArguments); | 1902 DartType mapKeyType = firstType(mapType.typeArguments); |
1895 DartType mapValueType = secondType(mapType.typeArguments); | 1903 DartType mapValueType = secondType(mapType.typeArguments); |
1896 bool isConst = node.isConst; | 1904 bool isConst = node.isConst; |
1897 for (Link<Node> link = node.entries.nodes; | 1905 for (Link<Node> link = node.entries.nodes; |
1898 !link.isEmpty; | 1906 !link.isEmpty; |
1899 link = link.tail) { | 1907 link = link.tail) { |
1900 LiteralMapEntry entry = link.head; | 1908 LiteralMapEntry entry = link.head; |
1901 DartType keyType = analyze(entry.key); | 1909 DartType keyType = analyze(entry.key); |
1902 checkAssignable(entry.key, keyType, mapKeyType, isConst: isConst); | 1910 checkAssignable(entry.key, keyType, mapKeyType, isConst: isConst); |
1903 DartType valueType = analyze(entry.value); | 1911 DartType valueType = analyze(entry.value); |
1904 checkAssignable(entry.value, valueType, mapValueType, isConst: isConst); | 1912 checkAssignable(entry.value, valueType, mapValueType, isConst: isConst); |
1905 } | 1913 } |
1906 return mapType; | 1914 return mapType; |
1907 } | 1915 } |
1908 | 1916 |
1909 visitNamedArgument(NamedArgument node) { | 1917 visitNamedArgument(NamedArgument node) { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1953 unreferencedFields.add(field); | 1961 unreferencedFields.add(field); |
1954 } else { | 1962 } else { |
1955 enumValues[constantValue] = field; | 1963 enumValues[constantValue] = field; |
1956 } | 1964 } |
1957 }); | 1965 }); |
1958 | 1966 |
1959 for (SwitchCase switchCase in node.cases) { | 1967 for (SwitchCase switchCase in node.cases) { |
1960 for (Node labelOrCase in switchCase.labelsAndCases) { | 1968 for (Node labelOrCase in switchCase.labelsAndCases) { |
1961 CaseMatch caseMatch = labelOrCase.asCaseMatch(); | 1969 CaseMatch caseMatch = labelOrCase.asCaseMatch(); |
1962 if (caseMatch != null) { | 1970 if (caseMatch != null) { |
1963 ConstantExpression caseConstant = | 1971 ConstantExpression caseConstant = compiler |
1964 compiler.resolver.constantCompiler.compileNode( | 1972 .resolver.constantCompiler |
1965 caseMatch.expression, elements); | 1973 .compileNode(caseMatch.expression, elements); |
1966 enumValues.remove( | 1974 enumValues |
1967 compiler.constants.getConstantValue(caseConstant)); | 1975 .remove(compiler.constants.getConstantValue(caseConstant)); |
1968 } | 1976 } |
1969 } | 1977 } |
1970 } | 1978 } |
1971 unreferencedFields.addAll(enumValues.values); | 1979 unreferencedFields.addAll(enumValues.values); |
1972 if (!unreferencedFields.isEmpty) { | 1980 if (!unreferencedFields.isEmpty) { |
1973 reporter.reportWarningMessage( | 1981 reporter.reportWarningMessage(node, MessageKind.MISSING_ENUM_CASES, { |
1974 node, MessageKind.MISSING_ENUM_CASES, | 1982 'enumType': expressionType, |
1975 {'enumType': expressionType, | 1983 'enumValues': unreferencedFields.map((e) => e.name).join(', ') |
1976 'enumValues': unreferencedFields.map( | 1984 }); |
1977 (e) => e.name).join(', ')}); | |
1978 } | 1985 } |
1979 }); | 1986 }); |
1980 } | 1987 } |
1981 | 1988 |
1982 return const StatementType(); | 1989 return const StatementType(); |
1983 } | 1990 } |
1984 | 1991 |
1985 visitSwitchCase(SwitchCase node) { | 1992 visitSwitchCase(SwitchCase node) { |
1986 return analyze(node.statements); | 1993 return analyze(node.statements); |
1987 } | 1994 } |
(...skipping 16 matching lines...) Expand all Loading... |
2004 | 2011 |
2005 visitTypedef(Typedef node) { | 2012 visitTypedef(Typedef node) { |
2006 // Do not typecheck [Typedef] nodes. | 2013 // Do not typecheck [Typedef] nodes. |
2007 } | 2014 } |
2008 | 2015 |
2009 visitNode(Node node) { | 2016 visitNode(Node node) { |
2010 reporter.internalError(node, | 2017 reporter.internalError(node, |
2011 'Unexpected node ${node.getObjectDescription()} in the type checker.'); | 2018 'Unexpected node ${node.getObjectDescription()} in the type checker.'); |
2012 } | 2019 } |
2013 } | 2020 } |
OLD | NEW |