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

Side by Side Diff: pkg/compiler/lib/src/typechecker.dart

Issue 1859343004: dartfmt pkg/compiler (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart ('k') | pkg/compiler/lib/src/types/abstract_value_domain.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698