Chromium Code Reviews| 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 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 112 static final DOUBLE = const SourceString('double'); | 112 static final DOUBLE = const SourceString('double'); |
| 113 static final DYNAMIC = const SourceString('Dynamic'); | 113 static final DYNAMIC = const SourceString('Dynamic'); |
| 114 static final STRING = const SourceString('String'); | 114 static final STRING = const SourceString('String'); |
| 115 static final BOOL = const SourceString('bool'); | 115 static final BOOL = const SourceString('bool'); |
| 116 static final OBJECT = const SourceString('Object'); | 116 static final OBJECT = const SourceString('Object'); |
| 117 static final LIST = const SourceString('List'); | 117 static final LIST = const SourceString('List'); |
| 118 | 118 |
| 119 final SimpleType voidType; | 119 final SimpleType voidType; |
| 120 final SimpleType dynamicType; | 120 final SimpleType dynamicType; |
| 121 | 121 |
| 122 Types() : this.with(new LibraryElement(new Script(null, null))); | 122 Types(Element dynamicElement) |
| 123 : this.with(dynamicElement, new LibraryElement(new Script(null, null))); | |
| 123 | 124 |
| 124 Types.with(LibraryElement library) | 125 Types.with(Element dynamicElement, LibraryElement library) |
| 125 : voidType = new SimpleType(VOID, new ClassElement(VOID, library)), | 126 : voidType = new SimpleType(VOID, new ClassElement(VOID, library)), |
|
ahe
2012/04/17 16:14:47
Perhaps we should have a Void class as well.
karlklose
2012/04/18 08:19:08
I am not sure, I added a TODO for now.
ahe
2012/04/18 08:49:04
Good plan.
| |
| 126 dynamicType = new SimpleType(DYNAMIC, new ClassElement(DYNAMIC, library)); | 127 dynamicType = new SimpleType(DYNAMIC, dynamicElement); |
| 127 | 128 |
| 128 Type lookup(SourceString s) { | 129 Type lookup(SourceString s) { |
| 129 if (VOID == s) { | 130 if (VOID == s) { |
| 130 return voidType; | 131 return voidType; |
| 131 } else if (DYNAMIC == s || s.stringValue === 'var') { | 132 } else if (DYNAMIC == s || s.stringValue === 'var') { |
| 132 return dynamicType; | 133 return dynamicType; |
| 133 } | 134 } |
| 134 return null; | 135 return null; |
| 135 } | 136 } |
| 136 | 137 |
| 137 /** Returns true if t is a subtype of s */ | 138 /** Returns true if t is a subtype of s */ |
| 138 bool isSubtype(Type t, Type s) { | 139 bool isSubtype(Type t, Type s) { |
| 139 if (t === s || t === dynamicType || s === dynamicType || | 140 if (t === s || t === dynamicType || s === dynamicType || |
| 140 s.name == OBJECT) return true; | 141 s.name == OBJECT) return true; |
| 141 if (t is SimpleType) { | 142 if (t is InterfaceType) { |
| 142 if (s is !SimpleType) return false; | 143 if (s is !InterfaceType) return false; |
| 143 ClassElement tc = t.element; | 144 ClassElement tc = t.element; |
| 145 if (tc === s.element) return true; | |
| 144 for (Link<Type> supertypes = tc.allSupertypes; | 146 for (Link<Type> supertypes = tc.allSupertypes; |
| 145 supertypes != null && !supertypes.isEmpty(); | 147 supertypes != null && !supertypes.isEmpty(); |
| 146 supertypes = supertypes.tail) { | 148 supertypes = supertypes.tail) { |
| 147 Type supertype = supertypes.head; | 149 Type supertype = supertypes.head; |
| 148 if (supertype.element === s.element) return true; | 150 if (supertype.element === s.element) return true; |
| 149 } | 151 } |
| 150 return false; | 152 return false; |
| 151 } else if (t is FunctionType) { | 153 } else if (t is FunctionType) { |
| 152 if (s is !FunctionType) return false; | 154 if (s is !FunctionType) return false; |
| 153 FunctionType tf = t; | 155 FunctionType tf = t; |
| 154 FunctionType sf = s; | 156 FunctionType sf = s; |
| 155 Link<Type> tps = tf.parameterTypes; | 157 Link<Type> tps = tf.parameterTypes; |
| 156 Link<Type> sps = sf.parameterTypes; | 158 Link<Type> sps = sf.parameterTypes; |
| 157 while (!tps.isEmpty() && !sps.isEmpty()) { | 159 while (!tps.isEmpty() && !sps.isEmpty()) { |
| 158 if (!isAssignable(tps.head, sps.head)) return false; | 160 if (!isAssignable(tps.head, sps.head)) return false; |
| 159 tps = tps.tail; | 161 tps = tps.tail; |
| 160 sps = sps.tail; | 162 sps = sps.tail; |
| 161 } | 163 } |
| 162 if (!tps.isEmpty() || !sps.isEmpty()) return false; | 164 if (!tps.isEmpty() || !sps.isEmpty()) return false; |
| 163 if (!isAssignable(sf.returnType, tf.returnType)) return false; | 165 if (!isAssignable(sf.returnType, tf.returnType)) return false; |
| 164 return true; | 166 return true; |
| 167 } else if (t is TypeVariableType) { | |
| 168 if (s is !TypeVariableType) return false; | |
| 169 return (t.element === s.element); | |
| 165 } else { | 170 } else { |
| 166 throw 'internal error: unknown type kind'; | 171 throw 'internal error: unknown type kind'; |
| 167 } | 172 } |
| 168 } | 173 } |
| 169 | 174 |
| 170 bool isAssignable(Type r, Type s) { | 175 bool isAssignable(Type r, Type s) { |
| 171 return isSubtype(r, s) || isSubtype(s, r); | 176 return isSubtype(r, s) || isSubtype(s, r); |
| 172 } | 177 } |
| 173 } | 178 } |
| 174 | 179 |
| 175 class CancelTypeCheckException { | 180 class CancelTypeCheckException { |
| 176 final Node node; | 181 final Node node; |
| 177 final String reason; | 182 final String reason; |
| 178 | 183 |
| 179 CancelTypeCheckException(this.node, this.reason); | 184 CancelTypeCheckException(this.node, this.reason); |
| 180 } | 185 } |
| 181 | 186 |
| 182 Type lookupType(SourceString name, Compiler compiler, types) { | |
| 183 Type t = types.lookup(name); | |
| 184 if (t !== null) return t; | |
| 185 Element element = compiler.coreLibrary.find(name); | |
| 186 if (element !== null && element.kind === ElementKind.CLASS) { | |
| 187 return element.computeType(compiler); | |
| 188 } | |
| 189 return null; | |
| 190 } | |
| 191 | |
| 192 class TypeCheckerVisitor implements Visitor<Type> { | 187 class TypeCheckerVisitor implements Visitor<Type> { |
| 193 final Compiler compiler; | 188 final Compiler compiler; |
| 194 final TreeElements elements; | 189 final TreeElements elements; |
| 195 final Types types; | 190 final Types types; |
| 196 | 191 |
| 197 Node lastSeenNode; | 192 Node lastSeenNode; |
| 198 Type expectedReturnType; | 193 Type expectedReturnType; |
| 199 ClassElement currentClass; | 194 ClassElement currentClass; |
| 200 | 195 |
| 201 Link<Type> cascadeTypes = const EmptyLink<Type>(); | 196 Link<Type> cascadeTypes = const EmptyLink<Type>(); |
| 202 | 197 |
| 203 Type intType; | 198 Type intType; |
| 204 Type doubleType; | 199 Type doubleType; |
| 205 Type boolType; | 200 Type boolType; |
| 206 Type stringType; | 201 Type stringType; |
| 207 Type objectType; | 202 Type objectType; |
| 208 Type listType; | 203 Type listType; |
| 209 | 204 |
| 210 TypeCheckerVisitor(this.compiler, this.elements, this.types) { | 205 TypeCheckerVisitor(this.compiler, this.elements, this.types) { |
| 211 intType = lookupType(Types.INT, compiler, types); | 206 intType = compiler.intClass.computeType(compiler); |
| 212 doubleType = lookupType(Types.DOUBLE, compiler, types); | 207 doubleType = compiler.doubleClass.computeType(compiler); |
| 213 boolType = lookupType(Types.BOOL, compiler, types); | 208 boolType = compiler.boolClass.computeType(compiler); |
| 214 stringType = lookupType(Types.STRING, compiler, types); | 209 stringType = compiler.stringClass.computeType(compiler); |
| 215 objectType = lookupType(Types.OBJECT, compiler, types); | 210 objectType = compiler.objectClass.computeType(compiler); |
| 216 listType = lookupType(Types.LIST, compiler, types); | 211 listType = compiler.listClass.computeType(compiler); |
| 217 } | 212 } |
| 218 | 213 |
| 219 Type fail(node, [reason]) { | 214 Type fail(node, [reason]) { |
| 220 String message = 'cannot type-check'; | 215 String message = 'cannot type-check'; |
| 221 if (reason !== null) { | 216 if (reason !== null) { |
| 222 message = '$message: $reason'; | 217 message = '$message: $reason'; |
| 223 } | 218 } |
| 224 throw new CancelTypeCheckException(node, message); | 219 throw new CancelTypeCheckException(node, message); |
| 225 } | 220 } |
| 226 | 221 |
| (...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 618 return StatementType.RETURNING; | 613 return StatementType.RETURNING; |
| 619 } | 614 } |
| 620 | 615 |
| 621 Type computeType(Element element) { | 616 Type computeType(Element element) { |
| 622 if (element === null) return types.dynamicType; | 617 if (element === null) return types.dynamicType; |
| 623 Type result = element.computeType(compiler); | 618 Type result = element.computeType(compiler); |
| 624 return (result !== null) ? result : types.dynamicType; | 619 return (result !== null) ? result : types.dynamicType; |
| 625 } | 620 } |
| 626 | 621 |
| 627 Type visitTypeAnnotation(TypeAnnotation node) { | 622 Type visitTypeAnnotation(TypeAnnotation node) { |
| 628 if (node.typeName === null) return types.dynamicType; | 623 return elements.getType(node); |
| 629 Identifier identifier = node.typeName.asIdentifier(); | |
| 630 if (identifier === null) { | |
| 631 fail(node.typeName, 'library prefix not implemented'); | |
| 632 } | |
| 633 // TODO(ahe): Why wasn't this resolved by the resolver? | |
| 634 Type type = lookupType(identifier.source, compiler, types); | |
| 635 if (type === null) { | |
| 636 // The type name cannot be resolved, but the resolver | |
| 637 // already gave a warning, so we continue checking. | |
| 638 return types.dynamicType; | |
| 639 } | |
| 640 return type; | |
| 641 } | 624 } |
| 642 | 625 |
| 643 visitTypeVariable(TypeVariable node) { | 626 visitTypeVariable(TypeVariable node) { |
| 644 return types.dynamicType; | 627 return types.dynamicType; |
| 645 } | 628 } |
| 646 | 629 |
| 647 Type visitVariableDefinitions(VariableDefinitions node) { | 630 Type visitVariableDefinitions(VariableDefinitions node) { |
| 648 Type type = analyzeWithDefault(node.type, types.dynamicType); | 631 Type type = analyzeWithDefault(node.type, types.dynamicType); |
| 649 if (type == types.voidType) { | 632 if (type == types.voidType) { |
| 650 reportTypeWarning(node.type, MessageKind.VOID_VARIABLE); | 633 reportTypeWarning(node.type, MessageKind.VOID_VARIABLE); |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 749 } | 732 } |
| 750 | 733 |
| 751 visitCatchBlock(CatchBlock node) { | 734 visitCatchBlock(CatchBlock node) { |
| 752 fail(node); | 735 fail(node); |
| 753 } | 736 } |
| 754 | 737 |
| 755 visitTypedef(Typedef node) { | 738 visitTypedef(Typedef node) { |
| 756 fail(node); | 739 fail(node); |
| 757 } | 740 } |
| 758 } | 741 } |
| OLD | NEW |