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 |