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 final bool LOG_FAILURES = false; | 9 static final bool LOG_FAILURES = false; |
10 | 10 |
(...skipping 15 matching lines...) Expand all Loading... |
26 | 26 |
27 interface Type { | 27 interface Type { |
28 SourceString get name(); | 28 SourceString get name(); |
29 Element get element(); | 29 Element get element(); |
30 } | 30 } |
31 | 31 |
32 class TypeVariableType implements Type { | 32 class TypeVariableType implements Type { |
33 final SourceString name; | 33 final SourceString name; |
34 Element element; | 34 Element element; |
35 TypeVariableType(this.name, [this.element]); | 35 TypeVariableType(this.name, [this.element]); |
| 36 |
| 37 toString() => name.toString(); |
36 } | 38 } |
37 | 39 |
38 /** | 40 /** |
39 * A statement type tracks whether a statement returns or may return. | 41 * A statement type tracks whether a statement returns or may return. |
40 */ | 42 */ |
41 class StatementType implements Type { | 43 class StatementType implements Type { |
42 final String stringName; | 44 final String stringName; |
43 Element get element() => null; | 45 Element get element() => null; |
44 | 46 |
45 SourceString get name() => new SourceString(stringName); | 47 SourceString get name() => new SourceString(stringName); |
46 | 48 |
47 const StatementType(this.stringName); | 49 const StatementType(this.stringName); |
48 | 50 |
49 static final RETURNING = const StatementType('<returning>'); | 51 static final RETURNING = const StatementType('<returning>'); |
50 static final NOT_RETURNING = const StatementType('<not returning>'); | 52 static final NOT_RETURNING = const StatementType('<not returning>'); |
51 static final MAYBE_RETURNING = const StatementType('<maybe returning>'); | 53 static final MAYBE_RETURNING = const StatementType('<maybe returning>'); |
52 | 54 |
53 /** Combine the information about two control-flow edges that are joined. */ | 55 /** Combine the information about two control-flow edges that are joined. */ |
54 StatementType join(StatementType other) { | 56 StatementType join(StatementType other) { |
55 return (this === other) ? this : MAYBE_RETURNING; | 57 return (this === other) ? this : MAYBE_RETURNING; |
56 } | 58 } |
57 | 59 |
58 String toString() => stringName; | 60 String toString() => stringName; |
59 } | 61 } |
60 | 62 |
61 class SimpleType implements Type { | 63 class InterfaceType implements Type { |
62 final SourceString name; | 64 final SourceString name; |
63 final Element element; | 65 final ClassElement element; |
| 66 final Link<Type> arguments; |
64 | 67 |
65 const SimpleType(SourceString this.name, Element this.element); | 68 const InterfaceType(this.name, this.element, this.arguments); |
66 | 69 |
| 70 toString() { |
| 71 StringBuffer sb = new StringBuffer(); |
| 72 sb.add(name.slowToString()); |
| 73 if (!arguments.isEmpty()) { |
| 74 sb.add('<'); |
| 75 arguments.printOn(sb); |
| 76 sb.add('>'); |
| 77 } |
| 78 return sb.toString(); |
| 79 } |
| 80 } |
| 81 |
| 82 // TODO(karlklose): merge into InterfaceType as a named constructor. |
| 83 class SimpleType extends InterfaceType { |
| 84 const SimpleType(SourceString name, Element element) |
| 85 : super(name, element, const EmptyLink<Type>()); |
67 String toString() => name.slowToString(); | 86 String toString() => name.slowToString(); |
68 } | 87 } |
69 | 88 |
70 class FunctionType implements Type { | 89 class FunctionType implements Type { |
71 final Element element; | 90 final Element element; |
72 final Type returnType; | 91 final Type returnType; |
73 final Link<Type> parameterTypes; | 92 final Link<Type> parameterTypes; |
74 | 93 |
75 const FunctionType(Type this.returnType, Link<Type> this.parameterTypes, | 94 const FunctionType(Type this.returnType, Link<Type> this.parameterTypes, |
76 Element this.element); | 95 Element this.element); |
(...skipping 17 matching lines...) Expand all Loading... |
94 static final DYNAMIC = const SourceString('Dynamic'); | 113 static final DYNAMIC = const SourceString('Dynamic'); |
95 static final STRING = const SourceString('String'); | 114 static final STRING = const SourceString('String'); |
96 static final BOOL = const SourceString('bool'); | 115 static final BOOL = const SourceString('bool'); |
97 static final OBJECT = const SourceString('Object'); | 116 static final OBJECT = const SourceString('Object'); |
98 static final LIST = const SourceString('List'); | 117 static final LIST = const SourceString('List'); |
99 | 118 |
100 final SimpleType voidType; | 119 final SimpleType voidType; |
101 final SimpleType dynamicType; | 120 final SimpleType dynamicType; |
102 | 121 |
103 Types() : this.with(new LibraryElement(new Script(null, null))); | 122 Types() : this.with(new LibraryElement(new Script(null, null))); |
| 123 |
104 Types.with(LibraryElement library) | 124 Types.with(LibraryElement library) |
105 : voidType = new SimpleType(VOID, new ClassElement(VOID, library)), | 125 : voidType = new SimpleType(VOID, new ClassElement(VOID, library)), |
106 dynamicType = new SimpleType(DYNAMIC, new ClassElement(DYNAMIC, library)); | 126 dynamicType = new SimpleType(DYNAMIC, new ClassElement(DYNAMIC, library)); |
107 | 127 |
108 Type lookup(SourceString s) { | 128 Type lookup(SourceString s) { |
109 if (VOID == s) { | 129 if (VOID == s) { |
110 return voidType; | 130 return voidType; |
111 } else if (DYNAMIC == s || s.stringValue === 'var') { | 131 } else if (DYNAMIC == s || s.stringValue === 'var') { |
112 return dynamicType; | 132 return dynamicType; |
113 } | 133 } |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
165 Element element = compiler.coreLibrary.find(name); | 185 Element element = compiler.coreLibrary.find(name); |
166 if (element !== null && element.kind === ElementKind.CLASS) { | 186 if (element !== null && element.kind === ElementKind.CLASS) { |
167 return element.computeType(compiler); | 187 return element.computeType(compiler); |
168 } | 188 } |
169 return null; | 189 return null; |
170 } | 190 } |
171 | 191 |
172 class TypeCheckerVisitor implements Visitor<Type> { | 192 class TypeCheckerVisitor implements Visitor<Type> { |
173 final Compiler compiler; | 193 final Compiler compiler; |
174 final TreeElements elements; | 194 final TreeElements elements; |
175 Node lastSeenNode; | |
176 final Types types; | 195 final Types types; |
177 | 196 |
| 197 Node lastSeenNode; |
178 Type expectedReturnType; | 198 Type expectedReturnType; |
179 ClassElement currentClass; | 199 ClassElement currentClass; |
180 | 200 |
181 Link<Type> cascadeTypes = const EmptyLink<Type>(); | 201 Link<Type> cascadeTypes = const EmptyLink<Type>(); |
182 | 202 |
183 Type intType; | 203 Type intType; |
184 Type doubleType; | 204 Type doubleType; |
185 Type boolType; | 205 Type boolType; |
186 Type stringType; | 206 Type stringType; |
187 Type objectType; | 207 Type objectType; |
188 Type listType; | 208 Type listType; |
189 | 209 |
190 TypeCheckerVisitor(Compiler this.compiler, TreeElements this.elements, | 210 TypeCheckerVisitor(this.compiler, this.elements, this.types) { |
191 Types this.types) { | |
192 intType = lookupType(Types.INT, compiler, types); | 211 intType = lookupType(Types.INT, compiler, types); |
193 doubleType = lookupType(Types.DOUBLE, compiler, types); | 212 doubleType = lookupType(Types.DOUBLE, compiler, types); |
194 boolType = lookupType(Types.BOOL, compiler, types); | 213 boolType = lookupType(Types.BOOL, compiler, types); |
195 stringType = lookupType(Types.STRING, compiler, types); | 214 stringType = lookupType(Types.STRING, compiler, types); |
196 objectType = lookupType(Types.OBJECT, compiler, types); | 215 objectType = lookupType(Types.OBJECT, compiler, types); |
197 listType = lookupType(Types.LIST, compiler, types); | 216 listType = lookupType(Types.LIST, compiler, types); |
198 } | 217 } |
199 | 218 |
200 Type fail(node, [reason]) { | 219 Type fail(node, [reason]) { |
201 String message = 'cannot type-check'; | 220 String message = 'cannot type-check'; |
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
449 if (element === null) fail(node.selector, 'unresolved property'); | 468 if (element === null) fail(node.selector, 'unresolved property'); |
450 return computeType(element); | 469 return computeType(element); |
451 | 470 |
452 } else if (node.isFunctionObjectInvocation) { | 471 } else if (node.isFunctionObjectInvocation) { |
453 fail(node.receiver, 'function object invocation unimplemented'); | 472 fail(node.receiver, 'function object invocation unimplemented'); |
454 | 473 |
455 } else { | 474 } else { |
456 FunctionType computeFunType() { | 475 FunctionType computeFunType() { |
457 if (node.receiver !== null) { | 476 if (node.receiver !== null) { |
458 Type receiverType = analyze(node.receiver); | 477 Type receiverType = analyze(node.receiver); |
459 if (receiverType === types.dynamicType) return null; | 478 if (receiverType.element == compiler.dynamicClass) return null; |
460 if (receiverType === null) { | 479 if (receiverType === null) { |
461 fail(node.receiver, 'receivertype is null'); | 480 fail(node.receiver, 'receivertype is null'); |
462 } | 481 } |
463 if (receiverType.element.kind !== ElementKind.CLASS) { | 482 if (receiverType.element.kind !== ElementKind.CLASS) { |
464 fail(node.receiver, 'receivertype is not a class'); | 483 fail(node.receiver, 'receivertype is not a class'); |
465 } | 484 } |
466 ClassElement classElement = receiverType.element; | 485 ClassElement classElement = receiverType.element; |
467 // TODO(karlklose): substitute type arguments. | 486 // TODO(karlklose): substitute type arguments. |
468 Type memberType = | 487 Type memberType = |
469 lookupMethodType(selector, classElement, selector.source); | 488 lookupMethodType(selector, classElement, selector.source); |
470 if (memberType === types.dynamicType) return null; | 489 if (memberType.element === compiler.dynamicClass) return null; |
471 return memberType; | 490 return memberType; |
472 } else { | 491 } else { |
473 Element element = elements[node]; | 492 Element element = elements[node]; |
474 if (element === null) { | 493 if (element === null) { |
475 fail(node, 'unresolved ${node.selector}'); | 494 fail(node, 'unresolved ${node.selector}'); |
476 } else if (element.kind === ElementKind.FUNCTION) { | 495 } else if (element.kind === ElementKind.FUNCTION) { |
477 return computeType(element); | 496 return computeType(element); |
478 } else if (element.kind === ElementKind.FOREIGN) { | 497 } else if (element.kind === ElementKind.FOREIGN) { |
479 return null; | 498 return null; |
480 } else { | 499 } else { |
481 fail(node, 'unexpected element kind ${element.kind}'); | 500 fail(node, 'unexpected element kind ${element.kind}'); |
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
730 } | 749 } |
731 | 750 |
732 visitCatchBlock(CatchBlock node) { | 751 visitCatchBlock(CatchBlock node) { |
733 fail(node); | 752 fail(node); |
734 } | 753 } |
735 | 754 |
736 visitTypedef(Typedef node) { | 755 visitTypedef(Typedef node) { |
737 fail(node); | 756 fail(node); |
738 } | 757 } |
739 } | 758 } |
OLD | NEW |