| 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 |