| 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 class TypeCheckerTask extends CompilerTask { | 5 class TypeCheckerTask extends CompilerTask { |
| 6 TypeCheckerTask(Compiler compiler) : super(compiler); | 6 TypeCheckerTask(Compiler compiler) : super(compiler); |
| 7 String get name => "Type checker"; | 7 String get name => "Type checker"; |
| 8 | 8 |
| 9 static const bool LOG_FAILURES = false; | 9 static const bool LOG_FAILURES = false; |
| 10 | 10 |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 125 const InterfaceType(this.element, | 125 const InterfaceType(this.element, |
| 126 [this.arguments = const Link<DartType>()]); | 126 [this.arguments = const Link<DartType>()]); |
| 127 | 127 |
| 128 SourceString get name => element.name; | 128 SourceString get name => element.name; |
| 129 | 129 |
| 130 DartType unalias(Compiler compiler) => this; | 130 DartType unalias(Compiler compiler) => this; |
| 131 | 131 |
| 132 String toString() { | 132 String toString() { |
| 133 StringBuffer sb = new StringBuffer(); | 133 StringBuffer sb = new StringBuffer(); |
| 134 sb.add(name.slowToString()); | 134 sb.add(name.slowToString()); |
| 135 if (!arguments.isEmpty()) { | 135 if (!arguments.isEmpty) { |
| 136 sb.add('<'); | 136 sb.add('<'); |
| 137 arguments.printOn(sb, ', '); | 137 arguments.printOn(sb, ', '); |
| 138 sb.add('>'); | 138 sb.add('>'); |
| 139 } | 139 } |
| 140 return sb.toString(); | 140 return sb.toString(); |
| 141 } | 141 } |
| 142 | 142 |
| 143 int get hashCode { | 143 int get hashCode { |
| 144 int hash = element.hashCode; | 144 int hash = element.hashCode; |
| 145 for (Link<DartType> arguments = this.arguments; | 145 for (Link<DartType> arguments = this.arguments; |
| 146 !arguments.isEmpty(); | 146 !arguments.isEmpty; |
| 147 arguments = arguments.tail) { | 147 arguments = arguments.tail) { |
| 148 int argumentHash = arguments.head != null ? arguments.head.hashCode : 0; | 148 int argumentHash = arguments.head != null ? arguments.head.hashCode : 0; |
| 149 hash = 17 * hash + 3 * argumentHash; | 149 hash = 17 * hash + 3 * argumentHash; |
| 150 } | 150 } |
| 151 return hash; | 151 return hash; |
| 152 } | 152 } |
| 153 | 153 |
| 154 bool operator ==(other) { | 154 bool operator ==(other) { |
| 155 if (other is !InterfaceType) return false; | 155 if (other is !InterfaceType) return false; |
| 156 if (!identical(element, other.element)) return false; | 156 if (!identical(element, other.element)) return false; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 void initializeFrom(FunctionType other) { | 190 void initializeFrom(FunctionType other) { |
| 191 assert(returnType == null); | 191 assert(returnType == null); |
| 192 assert(parameterTypes == null); | 192 assert(parameterTypes == null); |
| 193 returnType = other.returnType; | 193 returnType = other.returnType; |
| 194 parameterTypes = other.parameterTypes; | 194 parameterTypes = other.parameterTypes; |
| 195 } | 195 } |
| 196 | 196 |
| 197 int get hashCode { | 197 int get hashCode { |
| 198 int hash = 17 * element.hashCode + 3 * returnType.hashCode; | 198 int hash = 17 * element.hashCode + 3 * returnType.hashCode; |
| 199 for (Link<DartType> parameters = parameterTypes; | 199 for (Link<DartType> parameters = parameterTypes; |
| 200 !parameters.isEmpty(); | 200 !parameters.isEmpty; |
| 201 parameters = parameters.tail) { | 201 parameters = parameters.tail) { |
| 202 hash = 17 * hash + 3 * parameters.head.hashCode; | 202 hash = 17 * hash + 3 * parameters.head.hashCode; |
| 203 } | 203 } |
| 204 return hash; | 204 return hash; |
| 205 } | 205 } |
| 206 | 206 |
| 207 bool operator ==(other) { | 207 bool operator ==(other) { |
| 208 if (other is !FunctionType) return false; | 208 if (other is !FunctionType) return false; |
| 209 return returnType == other.returnType | 209 return returnType == other.returnType |
| 210 && parameterTypes == other.parameterTypes; | 210 && parameterTypes == other.parameterTypes; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 222 | 222 |
| 223 DartType unalias(Compiler compiler) { | 223 DartType unalias(Compiler compiler) { |
| 224 // TODO(ahe): This should be [ensureResolved]. | 224 // TODO(ahe): This should be [ensureResolved]. |
| 225 compiler.resolveTypedef(element); | 225 compiler.resolveTypedef(element); |
| 226 return element.alias.unalias(compiler); | 226 return element.alias.unalias(compiler); |
| 227 } | 227 } |
| 228 | 228 |
| 229 String toString() { | 229 String toString() { |
| 230 StringBuffer sb = new StringBuffer(); | 230 StringBuffer sb = new StringBuffer(); |
| 231 sb.add(name.slowToString()); | 231 sb.add(name.slowToString()); |
| 232 if (!typeArguments.isEmpty()) { | 232 if (!typeArguments.isEmpty) { |
| 233 sb.add('<'); | 233 sb.add('<'); |
| 234 typeArguments.printOn(sb, ', '); | 234 typeArguments.printOn(sb, ', '); |
| 235 sb.add('>'); | 235 sb.add('>'); |
| 236 } | 236 } |
| 237 return sb.toString(); | 237 return sb.toString(); |
| 238 } | 238 } |
| 239 | 239 |
| 240 int get hashCode => 17 * element.hashCode; | 240 int get hashCode => 17 * element.hashCode; |
| 241 | 241 |
| 242 bool operator ==(other) { | 242 bool operator ==(other) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 274 t = t.unalias(compiler); | 274 t = t.unalias(compiler); |
| 275 s = s.unalias(compiler); | 275 s = s.unalias(compiler); |
| 276 | 276 |
| 277 if (t is VoidType) { | 277 if (t is VoidType) { |
| 278 return false; | 278 return false; |
| 279 } else if (t is InterfaceType) { | 279 } else if (t is InterfaceType) { |
| 280 if (s is !InterfaceType) return false; | 280 if (s is !InterfaceType) return false; |
| 281 ClassElement tc = t.element; | 281 ClassElement tc = t.element; |
| 282 if (identical(tc, s.element)) return true; | 282 if (identical(tc, s.element)) return true; |
| 283 for (Link<DartType> supertypes = tc.allSupertypes; | 283 for (Link<DartType> supertypes = tc.allSupertypes; |
| 284 supertypes != null && !supertypes.isEmpty(); | 284 supertypes != null && !supertypes.isEmpty; |
| 285 supertypes = supertypes.tail) { | 285 supertypes = supertypes.tail) { |
| 286 DartType supertype = supertypes.head; | 286 DartType supertype = supertypes.head; |
| 287 if (identical(supertype.element, s.element)) return true; | 287 if (identical(supertype.element, s.element)) return true; |
| 288 } | 288 } |
| 289 return false; | 289 return false; |
| 290 } else if (t is FunctionType) { | 290 } else if (t is FunctionType) { |
| 291 if (identical(s.element, compiler.functionClass)) return true; | 291 if (identical(s.element, compiler.functionClass)) return true; |
| 292 if (s is !FunctionType) return false; | 292 if (s is !FunctionType) return false; |
| 293 FunctionType tf = t; | 293 FunctionType tf = t; |
| 294 FunctionType sf = s; | 294 FunctionType sf = s; |
| 295 Link<DartType> tps = tf.parameterTypes; | 295 Link<DartType> tps = tf.parameterTypes; |
| 296 Link<DartType> sps = sf.parameterTypes; | 296 Link<DartType> sps = sf.parameterTypes; |
| 297 while (!tps.isEmpty() && !sps.isEmpty()) { | 297 while (!tps.isEmpty && !sps.isEmpty) { |
| 298 if (!isAssignable(tps.head, sps.head)) return false; | 298 if (!isAssignable(tps.head, sps.head)) return false; |
| 299 tps = tps.tail; | 299 tps = tps.tail; |
| 300 sps = sps.tail; | 300 sps = sps.tail; |
| 301 } | 301 } |
| 302 if (!tps.isEmpty() || !sps.isEmpty()) return false; | 302 if (!tps.isEmpty || !sps.isEmpty) return false; |
| 303 if (!isAssignable(sf.returnType, tf.returnType)) return false; | 303 if (!isAssignable(sf.returnType, tf.returnType)) return false; |
| 304 return true; | 304 return true; |
| 305 } else if (t is TypeVariableType) { | 305 } else if (t is TypeVariableType) { |
| 306 if (s is !TypeVariableType) return false; | 306 if (s is !TypeVariableType) return false; |
| 307 return (identical(t.element, s.element)); | 307 return (identical(t.element, s.element)); |
| 308 } else { | 308 } else { |
| 309 throw 'internal error: unknown type kind'; | 309 throw 'internal error: unknown type kind'; |
| 310 } | 310 } |
| 311 } | 311 } |
| 312 | 312 |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 517 DartType visitLoop(Loop node) { | 517 DartType visitLoop(Loop node) { |
| 518 return unhandledStatement(); | 518 return unhandledStatement(); |
| 519 } | 519 } |
| 520 | 520 |
| 521 DartType lookupMethodType(Node node, ClassElement classElement, | 521 DartType lookupMethodType(Node node, ClassElement classElement, |
| 522 SourceString name) { | 522 SourceString name) { |
| 523 Element member = classElement.lookupLocalMember(name); | 523 Element member = classElement.lookupLocalMember(name); |
| 524 if (member == null) { | 524 if (member == null) { |
| 525 classElement.ensureResolved(compiler); | 525 classElement.ensureResolved(compiler); |
| 526 for (Link<DartType> supertypes = classElement.allSupertypes; | 526 for (Link<DartType> supertypes = classElement.allSupertypes; |
| 527 !supertypes.isEmpty() && member == null; | 527 !supertypes.isEmpty && member == null; |
| 528 supertypes = supertypes.tail) { | 528 supertypes = supertypes.tail) { |
| 529 ClassElement lookupTarget = supertypes.head.element; | 529 ClassElement lookupTarget = supertypes.head.element; |
| 530 member = lookupTarget.lookupLocalMember(name); | 530 member = lookupTarget.lookupLocalMember(name); |
| 531 } | 531 } |
| 532 } | 532 } |
| 533 if (member != null && member.kind == ElementKind.FUNCTION) { | 533 if (member != null && member.kind == ElementKind.FUNCTION) { |
| 534 return computeType(member); | 534 return computeType(member); |
| 535 } | 535 } |
| 536 reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND, | 536 reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND, |
| 537 [classElement.name, name]); | 537 [classElement.name, name]); |
| 538 return types.dynamicType; | 538 return types.dynamicType; |
| 539 } | 539 } |
| 540 | 540 |
| 541 void analyzeArguments(Send send, DartType type) { | 541 void analyzeArguments(Send send, DartType type) { |
| 542 Link<Node> arguments = send.arguments; | 542 Link<Node> arguments = send.arguments; |
| 543 if (type == null || identical(type, types.dynamicType)) { | 543 if (type == null || identical(type, types.dynamicType)) { |
| 544 while(!arguments.isEmpty()) { | 544 while(!arguments.isEmpty) { |
| 545 analyze(arguments.head); | 545 analyze(arguments.head); |
| 546 arguments = arguments.tail; | 546 arguments = arguments.tail; |
| 547 } | 547 } |
| 548 } else { | 548 } else { |
| 549 FunctionType funType = type; | 549 FunctionType funType = type; |
| 550 Link<DartType> parameterTypes = funType.parameterTypes; | 550 Link<DartType> parameterTypes = funType.parameterTypes; |
| 551 while (!arguments.isEmpty() && !parameterTypes.isEmpty()) { | 551 while (!arguments.isEmpty && !parameterTypes.isEmpty) { |
| 552 checkAssignable(arguments.head, parameterTypes.head, | 552 checkAssignable(arguments.head, parameterTypes.head, |
| 553 analyze(arguments.head)); | 553 analyze(arguments.head)); |
| 554 arguments = arguments.tail; | 554 arguments = arguments.tail; |
| 555 parameterTypes = parameterTypes.tail; | 555 parameterTypes = parameterTypes.tail; |
| 556 } | 556 } |
| 557 if (!arguments.isEmpty()) { | 557 if (!arguments.isEmpty) { |
| 558 reportTypeWarning(arguments.head, MessageKind.ADDITIONAL_ARGUMENT); | 558 reportTypeWarning(arguments.head, MessageKind.ADDITIONAL_ARGUMENT); |
| 559 } else if (!parameterTypes.isEmpty()) { | 559 } else if (!parameterTypes.isEmpty) { |
| 560 reportTypeWarning(send, MessageKind.MISSING_ARGUMENT, | 560 reportTypeWarning(send, MessageKind.MISSING_ARGUMENT, |
| 561 [parameterTypes.head]); | 561 [parameterTypes.head]); |
| 562 } | 562 } |
| 563 } | 563 } |
| 564 } | 564 } |
| 565 | 565 |
| 566 DartType visitSend(Send node) { | 566 DartType visitSend(Send node) { |
| 567 Element element = elements[node]; | 567 Element element = elements[node]; |
| 568 | 568 |
| 569 if (Elements.isClosureSend(node, element)) { | 569 if (Elements.isClosureSend(node, element)) { |
| 570 // TODO(karlklose): Finish implementation. | 570 // TODO(karlklose): Finish implementation. |
| 571 return types.dynamicType; | 571 return types.dynamicType; |
| 572 } | 572 } |
| 573 | 573 |
| 574 Identifier selector = node.selector.asIdentifier(); | 574 Identifier selector = node.selector.asIdentifier(); |
| 575 String name = selector.source.stringValue; | 575 String name = selector.source.stringValue; |
| 576 | 576 |
| 577 if (node.isOperator && identical(name, 'is')) { | 577 if (node.isOperator && identical(name, 'is')) { |
| 578 analyze(node.receiver); | 578 analyze(node.receiver); |
| 579 return boolType; | 579 return boolType; |
| 580 } else if (node.isOperator) { | 580 } else if (node.isOperator) { |
| 581 final Node firstArgument = node.receiver; | 581 final Node firstArgument = node.receiver; |
| 582 final DartType firstArgumentType = analyze(node.receiver); | 582 final DartType firstArgumentType = analyze(node.receiver); |
| 583 final arguments = node.arguments; | 583 final arguments = node.arguments; |
| 584 final Node secondArgument = arguments.isEmpty() ? null : arguments.head; | 584 final Node secondArgument = arguments.isEmpty ? null : arguments.head; |
| 585 final DartType secondArgumentType = | 585 final DartType secondArgumentType = |
| 586 analyzeWithDefault(secondArgument, null); | 586 analyzeWithDefault(secondArgument, null); |
| 587 | 587 |
| 588 if (identical(name, '+') || identical(name, '=') || identical(name, '-') | 588 if (identical(name, '+') || identical(name, '=') || identical(name, '-') |
| 589 || identical(name, '*') || identical(name, '/') || identical(name, '%'
) | 589 || identical(name, '*') || identical(name, '/') || identical(name, '%'
) |
| 590 || identical(name, '~/') || identical(name, '|') || identical(name, '&
') | 590 || identical(name, '~/') || identical(name, '|') || identical(name, '&
') |
| 591 || identical(name, '^') || identical(name, '~')|| identical(name, '<<'
) | 591 || identical(name, '^') || identical(name, '~')|| identical(name, '<<'
) |
| 592 || identical(name, '>>') || identical(name, '[]')) { | 592 || identical(name, '>>') || identical(name, '[]')) { |
| 593 return types.dynamicType; | 593 return types.dynamicType; |
| 594 } else if (identical(name, '<') || identical(name, '>') || identical(name,
'<=') | 594 } else if (identical(name, '<') || identical(name, '>') || identical(name,
'<=') |
| 595 || identical(name, '>=') || identical(name, '==') || identical(
name, '!=') | 595 || identical(name, '>=') || identical(name, '==') || identical(
name, '!=') |
| 596 || identical(name, '===') || identical(name, '!==')) { | 596 || identical(name, '===') || identical(name, '!==')) { |
| 597 return boolType; | 597 return boolType; |
| 598 } else if (identical(name, '||') || identical(name, '&&') || identical(nam
e, '!')) { | 598 } else if (identical(name, '||') || identical(name, '&&') || identical(nam
e, '!')) { |
| 599 checkAssignable(firstArgument, boolType, firstArgumentType); | 599 checkAssignable(firstArgument, boolType, firstArgumentType); |
| 600 if (!arguments.isEmpty()) { | 600 if (!arguments.isEmpty) { |
| 601 // TODO(karlklose): check number of arguments in validator. | 601 // TODO(karlklose): check number of arguments in validator. |
| 602 checkAssignable(secondArgument, boolType, secondArgumentType); | 602 checkAssignable(secondArgument, boolType, secondArgumentType); |
| 603 } | 603 } |
| 604 return boolType; | 604 return boolType; |
| 605 } | 605 } |
| 606 fail(selector, 'unexpected operator ${name}'); | 606 fail(selector, 'unexpected operator ${name}'); |
| 607 | 607 |
| 608 } else if (node.isPropertyAccess) { | 608 } else if (node.isPropertyAccess) { |
| 609 if (node.receiver != null) { | 609 if (node.receiver != null) { |
| 610 // TODO(karlklose): we cannot handle fields. | 610 // TODO(karlklose): we cannot handle fields. |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 716 return analyze(node.send.selector); | 716 return analyze(node.send.selector); |
| 717 } | 717 } |
| 718 | 718 |
| 719 DartType visitLiteralList(LiteralList node) { | 719 DartType visitLiteralList(LiteralList node) { |
| 720 return listType; | 720 return listType; |
| 721 } | 721 } |
| 722 | 722 |
| 723 DartType visitNodeList(NodeList node) { | 723 DartType visitNodeList(NodeList node) { |
| 724 DartType type = StatementType.NOT_RETURNING; | 724 DartType type = StatementType.NOT_RETURNING; |
| 725 bool reportedDeadCode = false; | 725 bool reportedDeadCode = false; |
| 726 for (Link<Node> link = node.nodes; !link.isEmpty(); link = link.tail) { | 726 for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) { |
| 727 DartType nextType = analyze(link.head); | 727 DartType nextType = analyze(link.head); |
| 728 if (type == StatementType.RETURNING) { | 728 if (type == StatementType.RETURNING) { |
| 729 if (!reportedDeadCode) { | 729 if (!reportedDeadCode) { |
| 730 reportTypeWarning(link.head, MessageKind.UNREACHABLE_CODE); | 730 reportTypeWarning(link.head, MessageKind.UNREACHABLE_CODE); |
| 731 reportedDeadCode = true; | 731 reportedDeadCode = true; |
| 732 } | 732 } |
| 733 } else if (type == StatementType.MAYBE_RETURNING){ | 733 } else if (type == StatementType.MAYBE_RETURNING){ |
| 734 if (nextType == StatementType.RETURNING) { | 734 if (nextType == StatementType.RETURNING) { |
| 735 type = nextType; | 735 type = nextType; |
| 736 } | 736 } |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 801 visitTypeVariable(TypeVariable node) { | 801 visitTypeVariable(TypeVariable node) { |
| 802 return types.dynamicType; | 802 return types.dynamicType; |
| 803 } | 803 } |
| 804 | 804 |
| 805 DartType visitVariableDefinitions(VariableDefinitions node) { | 805 DartType visitVariableDefinitions(VariableDefinitions node) { |
| 806 DartType type = analyzeWithDefault(node.type, types.dynamicType); | 806 DartType type = analyzeWithDefault(node.type, types.dynamicType); |
| 807 if (type == types.voidType) { | 807 if (type == types.voidType) { |
| 808 reportTypeWarning(node.type, MessageKind.VOID_VARIABLE); | 808 reportTypeWarning(node.type, MessageKind.VOID_VARIABLE); |
| 809 type = types.dynamicType; | 809 type = types.dynamicType; |
| 810 } | 810 } |
| 811 for (Link<Node> link = node.definitions.nodes; !link.isEmpty(); | 811 for (Link<Node> link = node.definitions.nodes; !link.isEmpty; |
| 812 link = link.tail) { | 812 link = link.tail) { |
| 813 Node initialization = link.head; | 813 Node initialization = link.head; |
| 814 compiler.ensure(initialization is Identifier | 814 compiler.ensure(initialization is Identifier |
| 815 || initialization is Send); | 815 || initialization is Send); |
| 816 if (initialization is Send) { | 816 if (initialization is Send) { |
| 817 DartType initializer = analyzeNonVoid(link.head); | 817 DartType initializer = analyzeNonVoid(link.head); |
| 818 checkAssignable(node, type, initializer); | 818 checkAssignable(node, type, initializer); |
| 819 } | 819 } |
| 820 } | 820 } |
| 821 return StatementType.NOT_RETURNING; | 821 return StatementType.NOT_RETURNING; |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 987 } | 987 } |
| 988 | 988 |
| 989 DartType visitStringNode(StringNode node) { | 989 DartType visitStringNode(StringNode node) { |
| 990 compiler.unimplemented('visitNode', node: node); | 990 compiler.unimplemented('visitNode', node: node); |
| 991 } | 991 } |
| 992 | 992 |
| 993 DartType visitLibraryDependency(LibraryDependency node) { | 993 DartType visitLibraryDependency(LibraryDependency node) { |
| 994 compiler.unimplemented('visitNode', node: node); | 994 compiler.unimplemented('visitNode', node: node); |
| 995 } | 995 } |
| 996 } | 996 } |
| OLD | NEW |