| 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 |
| 11 void check(Node tree, TreeElements elements) { | 11 void check(Node tree, TreeElements elements) { |
| 12 measure(() { | 12 measure(() { |
| 13 Visitor visitor = | 13 Visitor visitor = |
| 14 new TypeCheckerVisitor(compiler, elements, compiler.types); | 14 new TypeCheckerVisitor(compiler, elements, compiler.types); |
| 15 try { | 15 try { |
| 16 tree.accept(visitor); | 16 tree.accept(visitor); |
| 17 } on CancelTypeCheckException catch (e) { | 17 } on CancelTypeCheckException catch (e) { |
| 18 if (LOG_FAILURES) { | 18 if (LOG_FAILURES) { |
| 19 // Do not warn about unimplemented features; log message instead. | 19 // Do not warn about unimplemented features; log message instead. |
| 20 compiler.log("'${e.node}': ${e.reason}"); | 20 compiler.log("'${e.node}': ${e.reason}"); |
| 21 } | 21 } |
| 22 } | 22 } |
| 23 }); | 23 }); |
| 24 } | 24 } |
| 25 } | 25 } |
| 26 | 26 |
| 27 interface Type { | 27 interface DartType { |
| 28 SourceString get name(); | 28 SourceString get name(); |
| 29 Element get element(); | 29 Element get element(); |
| 30 | 30 |
| 31 /** | 31 /** |
| 32 * Returns the unaliased type of this type. | 32 * Returns the unaliased type of this type. |
| 33 * | 33 * |
| 34 * The unaliased type of a typedef'd type is the unaliased type to which its | 34 * The unaliased type of a typedef'd type is the unaliased type to which its |
| 35 * name is bound. The unaliased version of any other type is the type itself. | 35 * name is bound. The unaliased version of any other type is the type itself. |
| 36 * | 36 * |
| 37 * For example, the unaliased type of [: typedef A Func<A,B>(B b) :] is the | 37 * For example, the unaliased type of [: typedef A Func<A,B>(B b) :] is the |
| 38 * function type [: (B) -> A :] and the unaliased type of | 38 * function type [: (B) -> A :] and the unaliased type of |
| 39 * [: Func<int,String> :] is the function type [: (String) -> int :]. | 39 * [: Func<int,String> :] is the function type [: (String) -> int :]. |
| 40 */ | 40 */ |
| 41 Type unalias(Compiler compiler); | 41 DartType unalias(Compiler compiler); |
| 42 } | 42 } |
| 43 | 43 |
| 44 class TypeVariableType implements Type { | 44 class TypeVariableType implements DartType { |
| 45 final TypeVariableElement element; | 45 final TypeVariableElement element; |
| 46 | 46 |
| 47 TypeVariableType(this.element); | 47 TypeVariableType(this.element); |
| 48 | 48 |
| 49 SourceString get name => element.name; | 49 SourceString get name => element.name; |
| 50 | 50 |
| 51 Type unalias(Compiler compiler) => this; | 51 DartType unalias(Compiler compiler) => this; |
| 52 | 52 |
| 53 String toString() => name.slowToString(); | 53 String toString() => name.slowToString(); |
| 54 } | 54 } |
| 55 | 55 |
| 56 /** | 56 /** |
| 57 * A statement type tracks whether a statement returns or may return. | 57 * A statement type tracks whether a statement returns or may return. |
| 58 */ | 58 */ |
| 59 class StatementType implements Type { | 59 class StatementType implements DartType { |
| 60 final String stringName; | 60 final String stringName; |
| 61 Element get element => null; | 61 Element get element => null; |
| 62 | 62 |
| 63 SourceString get name => new SourceString(stringName); | 63 SourceString get name => new SourceString(stringName); |
| 64 | 64 |
| 65 const StatementType(this.stringName); | 65 const StatementType(this.stringName); |
| 66 | 66 |
| 67 static const RETURNING = const StatementType('<returning>'); | 67 static const RETURNING = const StatementType('<returning>'); |
| 68 static const NOT_RETURNING = const StatementType('<not returning>'); | 68 static const NOT_RETURNING = const StatementType('<not returning>'); |
| 69 static const MAYBE_RETURNING = const StatementType('<maybe returning>'); | 69 static const MAYBE_RETURNING = const StatementType('<maybe returning>'); |
| 70 | 70 |
| 71 /** Combine the information about two control-flow edges that are joined. */ | 71 /** Combine the information about two control-flow edges that are joined. */ |
| 72 StatementType join(StatementType other) { | 72 StatementType join(StatementType other) { |
| 73 return (this === other) ? this : MAYBE_RETURNING; | 73 return (this === other) ? this : MAYBE_RETURNING; |
| 74 } | 74 } |
| 75 | 75 |
| 76 Type unalias(Compiler compiler) => this; | 76 DartType unalias(Compiler compiler) => this; |
| 77 | 77 |
| 78 String toString() => stringName; | 78 String toString() => stringName; |
| 79 } | 79 } |
| 80 | 80 |
| 81 class VoidType implements Type { | 81 class VoidType implements DartType { |
| 82 const VoidType(this.element); | 82 const VoidType(this.element); |
| 83 SourceString get name => element.name; | 83 SourceString get name => element.name; |
| 84 final VoidElement element; | 84 final VoidElement element; |
| 85 | 85 |
| 86 Type unalias(Compiler compiler) => this; | 86 DartType unalias(Compiler compiler) => this; |
| 87 | 87 |
| 88 String toString() => name.slowToString(); | 88 String toString() => name.slowToString(); |
| 89 } | 89 } |
| 90 | 90 |
| 91 class InterfaceType implements Type { | 91 class InterfaceType implements DartType { |
| 92 final Element element; | 92 final Element element; |
| 93 final Link<Type> arguments; | 93 final Link<DartType> arguments; |
| 94 | 94 |
| 95 const InterfaceType(this.element, | 95 const InterfaceType(this.element, |
| 96 [this.arguments = const EmptyLink<Type>()]); | 96 [this.arguments = const EmptyLink<DartType>()]); |
| 97 | 97 |
| 98 SourceString get name => element.name; | 98 SourceString get name => element.name; |
| 99 | 99 |
| 100 Type unalias(Compiler compiler) => this; | 100 DartType unalias(Compiler compiler) => this; |
| 101 | 101 |
| 102 String toString() { | 102 String toString() { |
| 103 StringBuffer sb = new StringBuffer(); | 103 StringBuffer sb = new StringBuffer(); |
| 104 sb.add(name.slowToString()); | 104 sb.add(name.slowToString()); |
| 105 if (!arguments.isEmpty()) { | 105 if (!arguments.isEmpty()) { |
| 106 sb.add('<'); | 106 sb.add('<'); |
| 107 arguments.printOn(sb, ', '); | 107 arguments.printOn(sb, ', '); |
| 108 sb.add('>'); | 108 sb.add('>'); |
| 109 } | 109 } |
| 110 return sb.toString(); | 110 return sb.toString(); |
| 111 } | 111 } |
| 112 } | 112 } |
| 113 | 113 |
| 114 class FunctionType implements Type { | 114 class FunctionType implements DartType { |
| 115 final Element element; | 115 final Element element; |
| 116 Type returnType; | 116 DartType returnType; |
| 117 Link<Type> parameterTypes; | 117 Link<DartType> parameterTypes; |
| 118 | 118 |
| 119 FunctionType(Type this.returnType, Link<Type> this.parameterTypes, | 119 FunctionType(DartType this.returnType, Link<DartType> this.parameterTypes, |
| 120 Element this.element); | 120 Element this.element); |
| 121 | 121 |
| 122 Type unalias(Compiler compiler) => this; | 122 DartType unalias(Compiler compiler) => this; |
| 123 | 123 |
| 124 String toString() { | 124 String toString() { |
| 125 StringBuffer sb = new StringBuffer(); | 125 StringBuffer sb = new StringBuffer(); |
| 126 bool first = true; | 126 bool first = true; |
| 127 sb.add('('); | 127 sb.add('('); |
| 128 parameterTypes.printOn(sb, ', '); | 128 parameterTypes.printOn(sb, ', '); |
| 129 sb.add(') -> ${returnType}'); | 129 sb.add(') -> ${returnType}'); |
| 130 return sb.toString(); | 130 return sb.toString(); |
| 131 } | 131 } |
| 132 | 132 |
| 133 SourceString get name => const SourceString('Function'); | 133 SourceString get name => const SourceString('Function'); |
| 134 | 134 |
| 135 int computeArity() { | 135 int computeArity() { |
| 136 int arity = 0; | 136 int arity = 0; |
| 137 parameterTypes.forEach((_) { arity++; }); | 137 parameterTypes.forEach((_) { arity++; }); |
| 138 return arity; | 138 return arity; |
| 139 } | 139 } |
| 140 | 140 |
| 141 void initializeFrom(FunctionType other) { | 141 void initializeFrom(FunctionType other) { |
| 142 assert(returnType === null); | 142 assert(returnType === null); |
| 143 assert(parameterTypes === null); | 143 assert(parameterTypes === null); |
| 144 returnType = other.returnType; | 144 returnType = other.returnType; |
| 145 parameterTypes = other.parameterTypes; | 145 parameterTypes = other.parameterTypes; |
| 146 } | 146 } |
| 147 } | 147 } |
| 148 | 148 |
| 149 class TypedefType implements Type { | 149 class TypedefType implements DartType { |
| 150 final TypedefElement element; | 150 final TypedefElement element; |
| 151 final Link<Type> typeArguments; | 151 final Link<DartType> typeArguments; |
| 152 | 152 |
| 153 const TypedefType(this.element, | 153 const TypedefType(this.element, |
| 154 [this.typeArguments = const EmptyLink<Type>()]); | 154 [this.typeArguments = const EmptyLink<DartType>()]); |
| 155 | 155 |
| 156 SourceString get name => element.name; | 156 SourceString get name => element.name; |
| 157 | 157 |
| 158 Type unalias(Compiler compiler) { | 158 DartType unalias(Compiler compiler) { |
| 159 // TODO(ahe): This should be [ensureResolved]. | 159 // TODO(ahe): This should be [ensureResolved]. |
| 160 compiler.resolveTypedef(element); | 160 compiler.resolveTypedef(element); |
| 161 return element.alias.unalias(compiler); | 161 return element.alias.unalias(compiler); |
| 162 } | 162 } |
| 163 | 163 |
| 164 String toString() { | 164 String toString() { |
| 165 StringBuffer sb = new StringBuffer(); | 165 StringBuffer sb = new StringBuffer(); |
| 166 sb.add(name.slowToString()); | 166 sb.add(name.slowToString()); |
| 167 if (!typeArguments.isEmpty()) { | 167 if (!typeArguments.isEmpty()) { |
| 168 sb.add('<'); | 168 sb.add('<'); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 183 : this.with(compiler, dynamicElement, | 183 : this.with(compiler, dynamicElement, |
| 184 new LibraryElement(new Script(null, null))); | 184 new LibraryElement(new Script(null, null))); |
| 185 | 185 |
| 186 Types.with(Compiler this.compiler, | 186 Types.with(Compiler this.compiler, |
| 187 Element dynamicElement, | 187 Element dynamicElement, |
| 188 LibraryElement library) | 188 LibraryElement library) |
| 189 : voidType = new VoidType(new VoidElement(library)), | 189 : voidType = new VoidType(new VoidElement(library)), |
| 190 dynamicType = new InterfaceType(dynamicElement); | 190 dynamicType = new InterfaceType(dynamicElement); |
| 191 | 191 |
| 192 /** Returns true if t is a subtype of s */ | 192 /** Returns true if t is a subtype of s */ |
| 193 bool isSubtype(Type t, Type s) { | 193 bool isSubtype(DartType t, DartType s) { |
| 194 if (t === s || | 194 if (t === s || |
| 195 t === dynamicType || | 195 t === dynamicType || |
| 196 s === dynamicType || | 196 s === dynamicType || |
| 197 s.element === compiler.objectClass) { | 197 s.element === compiler.objectClass) { |
| 198 return true; | 198 return true; |
| 199 } | 199 } |
| 200 t = t.unalias(compiler); | 200 t = t.unalias(compiler); |
| 201 s = s.unalias(compiler); | 201 s = s.unalias(compiler); |
| 202 | 202 |
| 203 if (t is VoidType) { | 203 if (t is VoidType) { |
| 204 return false; | 204 return false; |
| 205 } else if (t is InterfaceType) { | 205 } else if (t is InterfaceType) { |
| 206 if (s is !InterfaceType) return false; | 206 if (s is !InterfaceType) return false; |
| 207 ClassElement tc = t.element; | 207 ClassElement tc = t.element; |
| 208 if (tc === s.element) return true; | 208 if (tc === s.element) return true; |
| 209 for (Link<Type> supertypes = tc.allSupertypes; | 209 for (Link<DartType> supertypes = tc.allSupertypes; |
| 210 supertypes != null && !supertypes.isEmpty(); | 210 supertypes != null && !supertypes.isEmpty(); |
| 211 supertypes = supertypes.tail) { | 211 supertypes = supertypes.tail) { |
| 212 Type supertype = supertypes.head; | 212 DartType supertype = supertypes.head; |
| 213 if (supertype.element === s.element) return true; | 213 if (supertype.element === s.element) return true; |
| 214 } | 214 } |
| 215 return false; | 215 return false; |
| 216 } else if (t is FunctionType) { | 216 } else if (t is FunctionType) { |
| 217 if (s.element === compiler.functionClass) return true; | 217 if (s.element === compiler.functionClass) return true; |
| 218 if (s is !FunctionType) return false; | 218 if (s is !FunctionType) return false; |
| 219 FunctionType tf = t; | 219 FunctionType tf = t; |
| 220 FunctionType sf = s; | 220 FunctionType sf = s; |
| 221 Link<Type> tps = tf.parameterTypes; | 221 Link<DartType> tps = tf.parameterTypes; |
| 222 Link<Type> sps = sf.parameterTypes; | 222 Link<DartType> sps = sf.parameterTypes; |
| 223 while (!tps.isEmpty() && !sps.isEmpty()) { | 223 while (!tps.isEmpty() && !sps.isEmpty()) { |
| 224 if (!isAssignable(tps.head, sps.head)) return false; | 224 if (!isAssignable(tps.head, sps.head)) return false; |
| 225 tps = tps.tail; | 225 tps = tps.tail; |
| 226 sps = sps.tail; | 226 sps = sps.tail; |
| 227 } | 227 } |
| 228 if (!tps.isEmpty() || !sps.isEmpty()) return false; | 228 if (!tps.isEmpty() || !sps.isEmpty()) return false; |
| 229 if (!isAssignable(sf.returnType, tf.returnType)) return false; | 229 if (!isAssignable(sf.returnType, tf.returnType)) return false; |
| 230 return true; | 230 return true; |
| 231 } else if (t is TypeVariableType) { | 231 } else if (t is TypeVariableType) { |
| 232 if (s is !TypeVariableType) return false; | 232 if (s is !TypeVariableType) return false; |
| 233 return (t.element === s.element); | 233 return (t.element === s.element); |
| 234 } else { | 234 } else { |
| 235 throw 'internal error: unknown type kind'; | 235 throw 'internal error: unknown type kind'; |
| 236 } | 236 } |
| 237 } | 237 } |
| 238 | 238 |
| 239 bool isAssignable(Type r, Type s) { | 239 bool isAssignable(DartType r, DartType s) { |
| 240 return isSubtype(r, s) || isSubtype(s, r); | 240 return isSubtype(r, s) || isSubtype(s, r); |
| 241 } | 241 } |
| 242 } | 242 } |
| 243 | 243 |
| 244 class CancelTypeCheckException { | 244 class CancelTypeCheckException { |
| 245 final Node node; | 245 final Node node; |
| 246 final String reason; | 246 final String reason; |
| 247 | 247 |
| 248 CancelTypeCheckException(this.node, this.reason); | 248 CancelTypeCheckException(this.node, this.reason); |
| 249 } | 249 } |
| 250 | 250 |
| 251 class TypeCheckerVisitor implements Visitor<Type> { | 251 class TypeCheckerVisitor implements Visitor<DartType> { |
| 252 final Compiler compiler; | 252 final Compiler compiler; |
| 253 final TreeElements elements; | 253 final TreeElements elements; |
| 254 final Types types; | 254 final Types types; |
| 255 | 255 |
| 256 Node lastSeenNode; | 256 Node lastSeenNode; |
| 257 Type expectedReturnType; | 257 DartType expectedReturnType; |
| 258 ClassElement currentClass; | 258 ClassElement currentClass; |
| 259 | 259 |
| 260 Link<Type> cascadeTypes = const EmptyLink<Type>(); | 260 Link<DartType> cascadeTypes = const EmptyLink<DartType>(); |
| 261 | 261 |
| 262 Type intType; | 262 DartType intType; |
| 263 Type doubleType; | 263 DartType doubleType; |
| 264 Type boolType; | 264 DartType boolType; |
| 265 Type stringType; | 265 DartType stringType; |
| 266 Type objectType; | 266 DartType objectType; |
| 267 Type listType; | 267 DartType listType; |
| 268 | 268 |
| 269 TypeCheckerVisitor(this.compiler, this.elements, this.types) { | 269 TypeCheckerVisitor(this.compiler, this.elements, this.types) { |
| 270 intType = compiler.intClass.computeType(compiler); | 270 intType = compiler.intClass.computeType(compiler); |
| 271 doubleType = compiler.doubleClass.computeType(compiler); | 271 doubleType = compiler.doubleClass.computeType(compiler); |
| 272 boolType = compiler.boolClass.computeType(compiler); | 272 boolType = compiler.boolClass.computeType(compiler); |
| 273 stringType = compiler.stringClass.computeType(compiler); | 273 stringType = compiler.stringClass.computeType(compiler); |
| 274 objectType = compiler.objectClass.computeType(compiler); | 274 objectType = compiler.objectClass.computeType(compiler); |
| 275 listType = compiler.listClass.computeType(compiler); | 275 listType = compiler.listClass.computeType(compiler); |
| 276 } | 276 } |
| 277 | 277 |
| 278 Type fail(node, [reason]) { | 278 DartType fail(node, [reason]) { |
| 279 String message = 'cannot type-check'; | 279 String message = 'cannot type-check'; |
| 280 if (reason !== null) { | 280 if (reason !== null) { |
| 281 message = '$message: $reason'; | 281 message = '$message: $reason'; |
| 282 } | 282 } |
| 283 throw new CancelTypeCheckException(node, message); | 283 throw new CancelTypeCheckException(node, message); |
| 284 } | 284 } |
| 285 | 285 |
| 286 reportTypeWarning(Node node, MessageKind kind, [List arguments = const []]) { | 286 reportTypeWarning(Node node, MessageKind kind, [List arguments = const []]) { |
| 287 compiler.reportWarning(node, new TypeWarning(kind, arguments)); | 287 compiler.reportWarning(node, new TypeWarning(kind, arguments)); |
| 288 } | 288 } |
| 289 | 289 |
| 290 // TODO(karlklose): remove these functions. | 290 // TODO(karlklose): remove these functions. |
| 291 Type unhandledStatement() => StatementType.NOT_RETURNING; | 291 DartType unhandledStatement() => StatementType.NOT_RETURNING; |
| 292 Type unhandledExpression() => types.dynamicType; | 292 DartType unhandledExpression() => types.dynamicType; |
| 293 | 293 |
| 294 Type analyzeNonVoid(Node node) { | 294 DartType analyzeNonVoid(Node node) { |
| 295 Type type = analyze(node); | 295 DartType type = analyze(node); |
| 296 if (type == types.voidType) { | 296 if (type == types.voidType) { |
| 297 reportTypeWarning(node, MessageKind.VOID_EXPRESSION); | 297 reportTypeWarning(node, MessageKind.VOID_EXPRESSION); |
| 298 } | 298 } |
| 299 return type; | 299 return type; |
| 300 } | 300 } |
| 301 | 301 |
| 302 Type analyzeWithDefault(Node node, Type defaultValue) { | 302 DartType analyzeWithDefault(Node node, DartType defaultValue) { |
| 303 return node !== null ? analyze(node) : defaultValue; | 303 return node !== null ? analyze(node) : defaultValue; |
| 304 } | 304 } |
| 305 | 305 |
| 306 Type analyze(Node node) { | 306 DartType analyze(Node node) { |
| 307 if (node == null) { | 307 if (node == null) { |
| 308 final String error = 'internal error: unexpected node: null'; | 308 final String error = 'internal error: unexpected node: null'; |
| 309 if (lastSeenNode != null) { | 309 if (lastSeenNode != null) { |
| 310 fail(null, error); | 310 fail(null, error); |
| 311 } else { | 311 } else { |
| 312 compiler.cancel(error); | 312 compiler.cancel(error); |
| 313 } | 313 } |
| 314 } else { | 314 } else { |
| 315 lastSeenNode = node; | 315 lastSeenNode = node; |
| 316 } | 316 } |
| 317 Type result = node.accept(this); | 317 DartType result = node.accept(this); |
| 318 // TODO(karlklose): record type? | 318 // TODO(karlklose): record type? |
| 319 if (result === null) { | 319 if (result === null) { |
| 320 fail(node, 'internal error: type is null'); | 320 fail(node, 'internal error: type is null'); |
| 321 } | 321 } |
| 322 return result; | 322 return result; |
| 323 } | 323 } |
| 324 | 324 |
| 325 /** | 325 /** |
| 326 * Check if a value of type t can be assigned to a variable, | 326 * Check if a value of type t can be assigned to a variable, |
| 327 * parameter or return value of type s. | 327 * parameter or return value of type s. |
| 328 */ | 328 */ |
| 329 checkAssignable(Node node, Type s, Type t) { | 329 checkAssignable(Node node, DartType s, DartType t) { |
| 330 if (!types.isAssignable(s, t)) { | 330 if (!types.isAssignable(s, t)) { |
| 331 reportTypeWarning(node, MessageKind.NOT_ASSIGNABLE, [s, t]); | 331 reportTypeWarning(node, MessageKind.NOT_ASSIGNABLE, [s, t]); |
| 332 } | 332 } |
| 333 } | 333 } |
| 334 | 334 |
| 335 checkCondition(Expression condition) { | 335 checkCondition(Expression condition) { |
| 336 checkAssignable(condition, boolType, analyze(condition)); | 336 checkAssignable(condition, boolType, analyze(condition)); |
| 337 } | 337 } |
| 338 | 338 |
| 339 void pushCascadeType(Type type) { | 339 void pushCascadeType(DartType type) { |
| 340 cascadeTypes = cascadeTypes.prepend(type); | 340 cascadeTypes = cascadeTypes.prepend(type); |
| 341 } | 341 } |
| 342 | 342 |
| 343 Type popCascadeType() { | 343 DartType popCascadeType() { |
| 344 Type type = cascadeTypes.head; | 344 DartType type = cascadeTypes.head; |
| 345 cascadeTypes = cascadeTypes.tail; | 345 cascadeTypes = cascadeTypes.tail; |
| 346 return type; | 346 return type; |
| 347 } | 347 } |
| 348 | 348 |
| 349 Type visitBlock(Block node) { | 349 DartType visitBlock(Block node) { |
| 350 return analyze(node.statements); | 350 return analyze(node.statements); |
| 351 } | 351 } |
| 352 | 352 |
| 353 Type visitCascade(Cascade node) { | 353 DartType visitCascade(Cascade node) { |
| 354 analyze(node.expression); | 354 analyze(node.expression); |
| 355 return popCascadeType(); | 355 return popCascadeType(); |
| 356 } | 356 } |
| 357 | 357 |
| 358 Type visitCascadeReceiver(CascadeReceiver node) { | 358 DartType visitCascadeReceiver(CascadeReceiver node) { |
| 359 Type type = analyze(node.expression); | 359 DartType type = analyze(node.expression); |
| 360 pushCascadeType(type); | 360 pushCascadeType(type); |
| 361 return type; | 361 return type; |
| 362 } | 362 } |
| 363 | 363 |
| 364 Type visitClassNode(ClassNode node) { | 364 DartType visitClassNode(ClassNode node) { |
| 365 fail(node); | 365 fail(node); |
| 366 } | 366 } |
| 367 | 367 |
| 368 Type visitDoWhile(DoWhile node) { | 368 DartType visitDoWhile(DoWhile node) { |
| 369 StatementType bodyType = analyze(node.body); | 369 StatementType bodyType = analyze(node.body); |
| 370 checkCondition(node.condition); | 370 checkCondition(node.condition); |
| 371 return bodyType.join(StatementType.NOT_RETURNING); | 371 return bodyType.join(StatementType.NOT_RETURNING); |
| 372 } | 372 } |
| 373 | 373 |
| 374 Type visitExpressionStatement(ExpressionStatement node) { | 374 DartType visitExpressionStatement(ExpressionStatement node) { |
| 375 analyze(node.expression); | 375 analyze(node.expression); |
| 376 return StatementType.NOT_RETURNING; | 376 return StatementType.NOT_RETURNING; |
| 377 } | 377 } |
| 378 | 378 |
| 379 /** Dart Programming Language Specification: 11.5.1 For Loop */ | 379 /** Dart Programming Language Specification: 11.5.1 For Loop */ |
| 380 Type visitFor(For node) { | 380 DartType visitFor(For node) { |
| 381 analyzeWithDefault(node.initializer, StatementType.NOT_RETURNING); | 381 analyzeWithDefault(node.initializer, StatementType.NOT_RETURNING); |
| 382 checkCondition(node.condition); | 382 checkCondition(node.condition); |
| 383 analyzeWithDefault(node.update, StatementType.NOT_RETURNING); | 383 analyzeWithDefault(node.update, StatementType.NOT_RETURNING); |
| 384 StatementType bodyType = analyze(node.body); | 384 StatementType bodyType = analyze(node.body); |
| 385 return bodyType.join(StatementType.NOT_RETURNING); | 385 return bodyType.join(StatementType.NOT_RETURNING); |
| 386 } | 386 } |
| 387 | 387 |
| 388 Type visitFunctionDeclaration(FunctionDeclaration node) { | 388 DartType visitFunctionDeclaration(FunctionDeclaration node) { |
| 389 analyze(node.function); | 389 analyze(node.function); |
| 390 return StatementType.NOT_RETURNING; | 390 return StatementType.NOT_RETURNING; |
| 391 } | 391 } |
| 392 | 392 |
| 393 Type visitFunctionExpression(FunctionExpression node) { | 393 DartType visitFunctionExpression(FunctionExpression node) { |
| 394 Type type; | 394 DartType type; |
| 395 Type returnType; | 395 DartType returnType; |
| 396 Type previousType; | 396 DartType previousType; |
| 397 final FunctionElement element = elements[node]; | 397 final FunctionElement element = elements[node]; |
| 398 if (Element.isInvalid(element)) return types.dynamicType; | 398 if (Element.isInvalid(element)) return types.dynamicType; |
| 399 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR || | 399 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR || |
| 400 element.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY) { | 400 element.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY) { |
| 401 type = types.dynamicType; | 401 type = types.dynamicType; |
| 402 returnType = types.voidType; | 402 returnType = types.voidType; |
| 403 } else { | 403 } else { |
| 404 FunctionType functionType = computeType(element); | 404 FunctionType functionType = computeType(element); |
| 405 returnType = functionType.returnType; | 405 returnType = functionType.returnType; |
| 406 type = functionType; | 406 type = functionType; |
| 407 } | 407 } |
| 408 Type previous = expectedReturnType; | 408 DartType previous = expectedReturnType; |
| 409 expectedReturnType = returnType; | 409 expectedReturnType = returnType; |
| 410 if (element.isMember()) currentClass = element.getEnclosingClass(); | 410 if (element.isMember()) currentClass = element.getEnclosingClass(); |
| 411 StatementType bodyType = analyze(node.body); | 411 StatementType bodyType = analyze(node.body); |
| 412 if (returnType != types.voidType && returnType != types.dynamicType | 412 if (returnType != types.voidType && returnType != types.dynamicType |
| 413 && bodyType != StatementType.RETURNING) { | 413 && bodyType != StatementType.RETURNING) { |
| 414 MessageKind kind; | 414 MessageKind kind; |
| 415 if (bodyType == StatementType.MAYBE_RETURNING) { | 415 if (bodyType == StatementType.MAYBE_RETURNING) { |
| 416 kind = MessageKind.MAYBE_MISSING_RETURN; | 416 kind = MessageKind.MAYBE_MISSING_RETURN; |
| 417 } else { | 417 } else { |
| 418 kind = MessageKind.MISSING_RETURN; | 418 kind = MessageKind.MISSING_RETURN; |
| 419 } | 419 } |
| 420 reportTypeWarning(node.name, kind); | 420 reportTypeWarning(node.name, kind); |
| 421 } | 421 } |
| 422 expectedReturnType = previous; | 422 expectedReturnType = previous; |
| 423 return type; | 423 return type; |
| 424 } | 424 } |
| 425 | 425 |
| 426 Type visitIdentifier(Identifier node) { | 426 DartType visitIdentifier(Identifier node) { |
| 427 if (node.isThis()) { | 427 if (node.isThis()) { |
| 428 return currentClass.computeType(compiler); | 428 return currentClass.computeType(compiler); |
| 429 } else { | 429 } else { |
| 430 // This is an identifier of a formal parameter. | 430 // This is an identifier of a formal parameter. |
| 431 return types.dynamicType; | 431 return types.dynamicType; |
| 432 } | 432 } |
| 433 } | 433 } |
| 434 | 434 |
| 435 Type visitIf(If node) { | 435 DartType visitIf(If node) { |
| 436 checkCondition(node.condition); | 436 checkCondition(node.condition); |
| 437 StatementType thenType = analyze(node.thenPart); | 437 StatementType thenType = analyze(node.thenPart); |
| 438 StatementType elseType = node.hasElsePart ? analyze(node.elsePart) | 438 StatementType elseType = node.hasElsePart ? analyze(node.elsePart) |
| 439 : StatementType.NOT_RETURNING; | 439 : StatementType.NOT_RETURNING; |
| 440 return thenType.join(elseType); | 440 return thenType.join(elseType); |
| 441 } | 441 } |
| 442 | 442 |
| 443 Type visitLoop(Loop node) { | 443 DartType visitLoop(Loop node) { |
| 444 return unhandledStatement(); | 444 return unhandledStatement(); |
| 445 } | 445 } |
| 446 | 446 |
| 447 Type lookupMethodType(Node node, ClassElement classElement, | 447 DartType lookupMethodType(Node node, ClassElement classElement, |
| 448 SourceString name) { | 448 SourceString name) { |
| 449 Element member = classElement.lookupLocalMember(name); | 449 Element member = classElement.lookupLocalMember(name); |
| 450 if (member === null) { | 450 if (member === null) { |
| 451 classElement.ensureResolved(compiler); | 451 classElement.ensureResolved(compiler); |
| 452 for (Link<Type> supertypes = classElement.allSupertypes; | 452 for (Link<DartType> supertypes = classElement.allSupertypes; |
| 453 !supertypes.isEmpty() && member === null; | 453 !supertypes.isEmpty() && member === null; |
| 454 supertypes = supertypes.tail) { | 454 supertypes = supertypes.tail) { |
| 455 ClassElement lookupTarget = supertypes.head.element; | 455 ClassElement lookupTarget = supertypes.head.element; |
| 456 member = lookupTarget.lookupLocalMember(name); | 456 member = lookupTarget.lookupLocalMember(name); |
| 457 } | 457 } |
| 458 } | 458 } |
| 459 if (member !== null && member.kind == ElementKind.FUNCTION) { | 459 if (member !== null && member.kind == ElementKind.FUNCTION) { |
| 460 return computeType(member); | 460 return computeType(member); |
| 461 } | 461 } |
| 462 reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND, | 462 reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND, |
| 463 [classElement.name, name]); | 463 [classElement.name, name]); |
| 464 return types.dynamicType; | 464 return types.dynamicType; |
| 465 } | 465 } |
| 466 | 466 |
| 467 void analyzeArguments(Send send, Type type) { | 467 void analyzeArguments(Send send, DartType type) { |
| 468 Link<Node> arguments = send.arguments; | 468 Link<Node> arguments = send.arguments; |
| 469 if (type === null || type === types.dynamicType) { | 469 if (type === null || type === types.dynamicType) { |
| 470 while(!arguments.isEmpty()) { | 470 while(!arguments.isEmpty()) { |
| 471 analyze(arguments.head); | 471 analyze(arguments.head); |
| 472 arguments = arguments.tail; | 472 arguments = arguments.tail; |
| 473 } | 473 } |
| 474 } else { | 474 } else { |
| 475 FunctionType funType = type; | 475 FunctionType funType = type; |
| 476 Link<Type> parameterTypes = funType.parameterTypes; | 476 Link<DartType> parameterTypes = funType.parameterTypes; |
| 477 while (!arguments.isEmpty() && !parameterTypes.isEmpty()) { | 477 while (!arguments.isEmpty() && !parameterTypes.isEmpty()) { |
| 478 checkAssignable(arguments.head, parameterTypes.head, | 478 checkAssignable(arguments.head, parameterTypes.head, |
| 479 analyze(arguments.head)); | 479 analyze(arguments.head)); |
| 480 arguments = arguments.tail; | 480 arguments = arguments.tail; |
| 481 parameterTypes = parameterTypes.tail; | 481 parameterTypes = parameterTypes.tail; |
| 482 } | 482 } |
| 483 if (!arguments.isEmpty()) { | 483 if (!arguments.isEmpty()) { |
| 484 reportTypeWarning(arguments.head, MessageKind.ADDITIONAL_ARGUMENT); | 484 reportTypeWarning(arguments.head, MessageKind.ADDITIONAL_ARGUMENT); |
| 485 } else if (!parameterTypes.isEmpty()) { | 485 } else if (!parameterTypes.isEmpty()) { |
| 486 reportTypeWarning(send, MessageKind.MISSING_ARGUMENT, | 486 reportTypeWarning(send, MessageKind.MISSING_ARGUMENT, |
| 487 [parameterTypes.head]); | 487 [parameterTypes.head]); |
| 488 } | 488 } |
| 489 } | 489 } |
| 490 } | 490 } |
| 491 | 491 |
| 492 Type visitSend(Send node) { | 492 DartType visitSend(Send node) { |
| 493 Element element = elements[node]; | 493 Element element = elements[node]; |
| 494 | 494 |
| 495 if (Elements.isClosureSend(node, element)) { | 495 if (Elements.isClosureSend(node, element)) { |
| 496 // TODO(karlklose): Finish implementation. | 496 // TODO(karlklose): Finish implementation. |
| 497 return types.dynamicType; | 497 return types.dynamicType; |
| 498 } | 498 } |
| 499 | 499 |
| 500 Identifier selector = node.selector.asIdentifier(); | 500 Identifier selector = node.selector.asIdentifier(); |
| 501 String name = selector.source.stringValue; | 501 String name = selector.source.stringValue; |
| 502 | 502 |
| 503 if (node.isOperator && name === 'is') { | 503 if (node.isOperator && name === 'is') { |
| 504 analyze(node.receiver); | 504 analyze(node.receiver); |
| 505 return boolType; | 505 return boolType; |
| 506 } else if (node.isOperator) { | 506 } else if (node.isOperator) { |
| 507 final Node firstArgument = node.receiver; | 507 final Node firstArgument = node.receiver; |
| 508 final Type firstArgumentType = analyze(node.receiver); | 508 final DartType firstArgumentType = analyze(node.receiver); |
| 509 final arguments = node.arguments; | 509 final arguments = node.arguments; |
| 510 final Node secondArgument = arguments.isEmpty() ? null : arguments.head; | 510 final Node secondArgument = arguments.isEmpty() ? null : arguments.head; |
| 511 final Type secondArgumentType = analyzeWithDefault(secondArgument, null); | 511 final DartType secondArgumentType = |
| 512 analyzeWithDefault(secondArgument, null); |
| 512 | 513 |
| 513 if (name === '+' || name === '=' || name === '-' | 514 if (name === '+' || name === '=' || name === '-' |
| 514 || name === '*' || name === '/' || name === '%' | 515 || name === '*' || name === '/' || name === '%' |
| 515 || name === '~/' || name === '|' || name ==='&' | 516 || name === '~/' || name === '|' || name ==='&' |
| 516 || name === '^' || name === '~'|| name === '<<' | 517 || name === '^' || name === '~'|| name === '<<' |
| 517 || name === '>>' || name === '[]') { | 518 || name === '>>' || name === '[]') { |
| 518 return types.dynamicType; | 519 return types.dynamicType; |
| 519 } else if (name === '<' || name === '>' || name === '<=' | 520 } else if (name === '<' || name === '>' || name === '<=' |
| 520 || name === '>=' || name === '==' || name === '!=' | 521 || name === '>=' || name === '==' || name === '!=' |
| 521 || name === '===' || name === '!==') { | 522 || name === '===' || name === '!==') { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 537 } | 538 } |
| 538 if (element === null) return types.dynamicType; | 539 if (element === null) return types.dynamicType; |
| 539 return computeType(element); | 540 return computeType(element); |
| 540 | 541 |
| 541 } else if (node.isFunctionObjectInvocation) { | 542 } else if (node.isFunctionObjectInvocation) { |
| 542 fail(node.receiver, 'function object invocation unimplemented'); | 543 fail(node.receiver, 'function object invocation unimplemented'); |
| 543 | 544 |
| 544 } else { | 545 } else { |
| 545 FunctionType computeFunType() { | 546 FunctionType computeFunType() { |
| 546 if (node.receiver !== null) { | 547 if (node.receiver !== null) { |
| 547 Type receiverType = analyze(node.receiver); | 548 DartType receiverType = analyze(node.receiver); |
| 548 if (receiverType.element == compiler.dynamicClass) return null; | 549 if (receiverType.element == compiler.dynamicClass) return null; |
| 549 if (receiverType === null) { | 550 if (receiverType === null) { |
| 550 fail(node.receiver, 'receivertype is null'); | 551 fail(node.receiver, 'receivertype is null'); |
| 551 } | 552 } |
| 552 if (receiverType.element.kind === ElementKind.GETTER) { | 553 if (receiverType.element.kind === ElementKind.GETTER) { |
| 553 FunctionType getterType = receiverType; | 554 FunctionType getterType = receiverType; |
| 554 receiverType = getterType.returnType; | 555 receiverType = getterType.returnType; |
| 555 } | 556 } |
| 556 ElementKind receiverKind = receiverType.element.kind; | 557 ElementKind receiverKind = receiverType.element.kind; |
| 557 if (receiverKind === ElementKind.TYPEDEF) { | 558 if (receiverKind === ElementKind.TYPEDEF) { |
| 558 // TODO(karlklose): handle typedefs. | 559 // TODO(karlklose): handle typedefs. |
| 559 return null; | 560 return null; |
| 560 } | 561 } |
| 561 if (receiverKind === ElementKind.TYPE_VARIABLE) { | 562 if (receiverKind === ElementKind.TYPE_VARIABLE) { |
| 562 // TODO(karlklose): handle type variables. | 563 // TODO(karlklose): handle type variables. |
| 563 return null; | 564 return null; |
| 564 } | 565 } |
| 565 if (receiverKind !== ElementKind.CLASS) { | 566 if (receiverKind !== ElementKind.CLASS) { |
| 566 fail(node.receiver, 'unexpected receiver kind: ${receiverKind}'); | 567 fail(node.receiver, 'unexpected receiver kind: ${receiverKind}'); |
| 567 } | 568 } |
| 568 ClassElement classElement = receiverType.element; | 569 ClassElement classElement = receiverType.element; |
| 569 // TODO(karlklose): substitute type arguments. | 570 // TODO(karlklose): substitute type arguments. |
| 570 Type memberType = | 571 DartType memberType = |
| 571 lookupMethodType(selector, classElement, selector.source); | 572 lookupMethodType(selector, classElement, selector.source); |
| 572 if (memberType.element === compiler.dynamicClass) return null; | 573 if (memberType.element === compiler.dynamicClass) return null; |
| 573 return memberType; | 574 return memberType; |
| 574 } else { | 575 } else { |
| 575 if (element === null) { | 576 if (element === null) { |
| 576 fail(node, 'unresolved ${node.selector}'); | 577 fail(node, 'unresolved ${node.selector}'); |
| 577 } else if (element.kind === ElementKind.FUNCTION) { | 578 } else if (element.kind === ElementKind.FUNCTION) { |
| 578 return computeType(element); | 579 return computeType(element); |
| 579 } else if (element.kind === ElementKind.FOREIGN) { | 580 } else if (element.kind === ElementKind.FOREIGN) { |
| 580 return null; | 581 return null; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 591 analyzeArguments(node, funType); | 592 analyzeArguments(node, funType); |
| 592 return (funType !== null) ? funType.returnType : types.dynamicType; | 593 return (funType !== null) ? funType.returnType : types.dynamicType; |
| 593 } | 594 } |
| 594 } | 595 } |
| 595 | 596 |
| 596 visitSendSet(SendSet node) { | 597 visitSendSet(SendSet node) { |
| 597 Identifier selector = node.selector; | 598 Identifier selector = node.selector; |
| 598 final name = node.assignmentOperator.source.stringValue; | 599 final name = node.assignmentOperator.source.stringValue; |
| 599 if (name === '++' || name === '--') { | 600 if (name === '++' || name === '--') { |
| 600 final Element element = elements[node.selector]; | 601 final Element element = elements[node.selector]; |
| 601 final Type receiverType = computeType(element); | 602 final DartType receiverType = computeType(element); |
| 602 // TODO(karlklose): this should be the return type instead of int. | 603 // TODO(karlklose): this should be the return type instead of int. |
| 603 return node.isPrefix ? intType : receiverType; | 604 return node.isPrefix ? intType : receiverType; |
| 604 } else { | 605 } else { |
| 605 Type targetType = computeType(elements[node]); | 606 DartType targetType = computeType(elements[node]); |
| 606 Node value = node.arguments.head; | 607 Node value = node.arguments.head; |
| 607 checkAssignable(value, targetType, analyze(value)); | 608 checkAssignable(value, targetType, analyze(value)); |
| 608 return targetType; | 609 return targetType; |
| 609 } | 610 } |
| 610 } | 611 } |
| 611 | 612 |
| 612 Type visitLiteralInt(LiteralInt node) { | 613 DartType visitLiteralInt(LiteralInt node) { |
| 613 return intType; | 614 return intType; |
| 614 } | 615 } |
| 615 | 616 |
| 616 Type visitLiteralDouble(LiteralDouble node) { | 617 DartType visitLiteralDouble(LiteralDouble node) { |
| 617 return doubleType; | 618 return doubleType; |
| 618 } | 619 } |
| 619 | 620 |
| 620 Type visitLiteralBool(LiteralBool node) { | 621 DartType visitLiteralBool(LiteralBool node) { |
| 621 return boolType; | 622 return boolType; |
| 622 } | 623 } |
| 623 | 624 |
| 624 Type visitLiteralString(LiteralString node) { | 625 DartType visitLiteralString(LiteralString node) { |
| 625 return stringType; | 626 return stringType; |
| 626 } | 627 } |
| 627 | 628 |
| 628 Type visitStringJuxtaposition(StringJuxtaposition node) { | 629 DartType visitStringJuxtaposition(StringJuxtaposition node) { |
| 629 analyze(node.first); | 630 analyze(node.first); |
| 630 analyze(node.second); | 631 analyze(node.second); |
| 631 return stringType; | 632 return stringType; |
| 632 } | 633 } |
| 633 | 634 |
| 634 Type visitLiteralNull(LiteralNull node) { | 635 DartType visitLiteralNull(LiteralNull node) { |
| 635 return types.dynamicType; | 636 return types.dynamicType; |
| 636 } | 637 } |
| 637 | 638 |
| 638 Type visitNewExpression(NewExpression node) { | 639 DartType visitNewExpression(NewExpression node) { |
| 639 Element element = elements[node.send]; | 640 Element element = elements[node.send]; |
| 640 analyzeArguments(node.send, computeType(element)); | 641 analyzeArguments(node.send, computeType(element)); |
| 641 return analyze(node.send.selector); | 642 return analyze(node.send.selector); |
| 642 } | 643 } |
| 643 | 644 |
| 644 Type visitLiteralList(LiteralList node) { | 645 DartType visitLiteralList(LiteralList node) { |
| 645 return listType; | 646 return listType; |
| 646 } | 647 } |
| 647 | 648 |
| 648 Type visitNodeList(NodeList node) { | 649 DartType visitNodeList(NodeList node) { |
| 649 Type type = StatementType.NOT_RETURNING; | 650 DartType type = StatementType.NOT_RETURNING; |
| 650 bool reportedDeadCode = false; | 651 bool reportedDeadCode = false; |
| 651 for (Link<Node> link = node.nodes; !link.isEmpty(); link = link.tail) { | 652 for (Link<Node> link = node.nodes; !link.isEmpty(); link = link.tail) { |
| 652 Type nextType = analyze(link.head); | 653 DartType nextType = analyze(link.head); |
| 653 if (type == StatementType.RETURNING) { | 654 if (type == StatementType.RETURNING) { |
| 654 if (!reportedDeadCode) { | 655 if (!reportedDeadCode) { |
| 655 reportTypeWarning(link.head, MessageKind.UNREACHABLE_CODE); | 656 reportTypeWarning(link.head, MessageKind.UNREACHABLE_CODE); |
| 656 reportedDeadCode = true; | 657 reportedDeadCode = true; |
| 657 } | 658 } |
| 658 } else if (type == StatementType.MAYBE_RETURNING){ | 659 } else if (type == StatementType.MAYBE_RETURNING){ |
| 659 if (nextType == StatementType.RETURNING) { | 660 if (nextType == StatementType.RETURNING) { |
| 660 type = nextType; | 661 type = nextType; |
| 661 } | 662 } |
| 662 } else { | 663 } else { |
| 663 type = nextType; | 664 type = nextType; |
| 664 } | 665 } |
| 665 } | 666 } |
| 666 return type; | 667 return type; |
| 667 } | 668 } |
| 668 | 669 |
| 669 Type visitOperator(Operator node) { | 670 DartType visitOperator(Operator node) { |
| 670 fail(node, 'internal error'); | 671 fail(node, 'internal error'); |
| 671 } | 672 } |
| 672 | 673 |
| 673 /** Dart Programming Language Specification: 11.10 Return */ | 674 /** Dart Programming Language Specification: 11.10 Return */ |
| 674 Type visitReturn(Return node) { | 675 DartType visitReturn(Return node) { |
| 675 if (node.getBeginToken().stringValue === 'native') { | 676 if (node.getBeginToken().stringValue === 'native') { |
| 676 return StatementType.RETURNING; | 677 return StatementType.RETURNING; |
| 677 } | 678 } |
| 678 | 679 |
| 679 final expression = node.expression; | 680 final expression = node.expression; |
| 680 final isVoidFunction = (expectedReturnType === types.voidType); | 681 final isVoidFunction = (expectedReturnType === types.voidType); |
| 681 | 682 |
| 682 // Executing a return statement return e; [...] It is a static type warning | 683 // Executing a return statement return e; [...] It is a static type warning |
| 683 // if the type of e may not be assigned to the declared return type of the | 684 // if the type of e may not be assigned to the declared return type of the |
| 684 // immediately enclosing function. | 685 // immediately enclosing function. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 696 // form 'return;' It is a static warning if both of the following conditions | 697 // form 'return;' It is a static warning if both of the following conditions |
| 697 // hold: | 698 // hold: |
| 698 // - f is not a generative constructor. | 699 // - f is not a generative constructor. |
| 699 // - The return type of f may not be assigned to void. | 700 // - The return type of f may not be assigned to void. |
| 700 } else if (!types.isAssignable(expectedReturnType, types.voidType)) { | 701 } else if (!types.isAssignable(expectedReturnType, types.voidType)) { |
| 701 reportTypeWarning(node, MessageKind.RETURN_NOTHING, [expectedReturnType]); | 702 reportTypeWarning(node, MessageKind.RETURN_NOTHING, [expectedReturnType]); |
| 702 } | 703 } |
| 703 return StatementType.RETURNING; | 704 return StatementType.RETURNING; |
| 704 } | 705 } |
| 705 | 706 |
| 706 Type visitThrow(Throw node) { | 707 DartType visitThrow(Throw node) { |
| 707 if (node.expression !== null) analyze(node.expression); | 708 if (node.expression !== null) analyze(node.expression); |
| 708 return StatementType.RETURNING; | 709 return StatementType.RETURNING; |
| 709 } | 710 } |
| 710 | 711 |
| 711 Type computeType(Element element) { | 712 DartType computeType(Element element) { |
| 712 if (Element.isInvalid(element)) return types.dynamicType; | 713 if (Element.isInvalid(element)) return types.dynamicType; |
| 713 Type result = element.computeType(compiler); | 714 DartType result = element.computeType(compiler); |
| 714 return (result !== null) ? result : types.dynamicType; | 715 return (result !== null) ? result : types.dynamicType; |
| 715 } | 716 } |
| 716 | 717 |
| 717 Type visitTypeAnnotation(TypeAnnotation node) { | 718 DartType visitTypeAnnotation(TypeAnnotation node) { |
| 718 return elements.getType(node); | 719 return elements.getType(node); |
| 719 } | 720 } |
| 720 | 721 |
| 721 visitTypeVariable(TypeVariable node) { | 722 visitTypeVariable(TypeVariable node) { |
| 722 return types.dynamicType; | 723 return types.dynamicType; |
| 723 } | 724 } |
| 724 | 725 |
| 725 Type visitVariableDefinitions(VariableDefinitions node) { | 726 DartType visitVariableDefinitions(VariableDefinitions node) { |
| 726 Type type = analyzeWithDefault(node.type, types.dynamicType); | 727 DartType type = analyzeWithDefault(node.type, types.dynamicType); |
| 727 if (type == types.voidType) { | 728 if (type == types.voidType) { |
| 728 reportTypeWarning(node.type, MessageKind.VOID_VARIABLE); | 729 reportTypeWarning(node.type, MessageKind.VOID_VARIABLE); |
| 729 type = types.dynamicType; | 730 type = types.dynamicType; |
| 730 } | 731 } |
| 731 for (Link<Node> link = node.definitions.nodes; !link.isEmpty(); | 732 for (Link<Node> link = node.definitions.nodes; !link.isEmpty(); |
| 732 link = link.tail) { | 733 link = link.tail) { |
| 733 Node initialization = link.head; | 734 Node initialization = link.head; |
| 734 compiler.ensure(initialization is Identifier | 735 compiler.ensure(initialization is Identifier |
| 735 || initialization is Send); | 736 || initialization is Send); |
| 736 if (initialization is Send) { | 737 if (initialization is Send) { |
| 737 Type initializer = analyzeNonVoid(link.head); | 738 DartType initializer = analyzeNonVoid(link.head); |
| 738 checkAssignable(node, type, initializer); | 739 checkAssignable(node, type, initializer); |
| 739 } | 740 } |
| 740 } | 741 } |
| 741 return StatementType.NOT_RETURNING; | 742 return StatementType.NOT_RETURNING; |
| 742 } | 743 } |
| 743 | 744 |
| 744 Type visitWhile(While node) { | 745 DartType visitWhile(While node) { |
| 745 checkCondition(node.condition); | 746 checkCondition(node.condition); |
| 746 StatementType bodyType = analyze(node.body); | 747 StatementType bodyType = analyze(node.body); |
| 747 Expression cond = node.condition.asParenthesizedExpression().expression; | 748 Expression cond = node.condition.asParenthesizedExpression().expression; |
| 748 if (cond.asLiteralBool() !== null && cond.asLiteralBool().value == true) { | 749 if (cond.asLiteralBool() !== null && cond.asLiteralBool().value == true) { |
| 749 // If the condition is a constant boolean expression denoting true, | 750 // If the condition is a constant boolean expression denoting true, |
| 750 // control-flow always enters the loop body. | 751 // control-flow always enters the loop body. |
| 751 // TODO(karlklose): this should be StatementType.RETURNING unless there | 752 // TODO(karlklose): this should be StatementType.RETURNING unless there |
| 752 // is a break in the loop body that has the loop or a label outside the | 753 // is a break in the loop body that has the loop or a label outside the |
| 753 // loop as a target. | 754 // loop as a target. |
| 754 return bodyType; | 755 return bodyType; |
| 755 } else { | 756 } else { |
| 756 return bodyType.join(StatementType.NOT_RETURNING); | 757 return bodyType.join(StatementType.NOT_RETURNING); |
| 757 } | 758 } |
| 758 } | 759 } |
| 759 | 760 |
| 760 Type visitParenthesizedExpression(ParenthesizedExpression node) { | 761 DartType visitParenthesizedExpression(ParenthesizedExpression node) { |
| 761 return analyze(node.expression); | 762 return analyze(node.expression); |
| 762 } | 763 } |
| 763 | 764 |
| 764 Type visitConditional(Conditional node) { | 765 DartType visitConditional(Conditional node) { |
| 765 checkCondition(node.condition); | 766 checkCondition(node.condition); |
| 766 Type thenType = analyzeNonVoid(node.thenExpression); | 767 DartType thenType = analyzeNonVoid(node.thenExpression); |
| 767 Type elseType = analyzeNonVoid(node.elseExpression); | 768 DartType elseType = analyzeNonVoid(node.elseExpression); |
| 768 if (types.isSubtype(thenType, elseType)) { | 769 if (types.isSubtype(thenType, elseType)) { |
| 769 return thenType; | 770 return thenType; |
| 770 } else if (types.isSubtype(elseType, thenType)) { | 771 } else if (types.isSubtype(elseType, thenType)) { |
| 771 return elseType; | 772 return elseType; |
| 772 } else { | 773 } else { |
| 773 return objectType; | 774 return objectType; |
| 774 } | 775 } |
| 775 } | 776 } |
| 776 | 777 |
| 777 Type visitModifiers(Modifiers node) {} | 778 DartType visitModifiers(Modifiers node) {} |
| 778 | 779 |
| 779 visitStringInterpolation(StringInterpolation node) { | 780 visitStringInterpolation(StringInterpolation node) { |
| 780 node.visitChildren(this); | 781 node.visitChildren(this); |
| 781 return stringType; | 782 return stringType; |
| 782 } | 783 } |
| 783 | 784 |
| 784 visitStringInterpolationPart(StringInterpolationPart node) { | 785 visitStringInterpolationPart(StringInterpolationPart node) { |
| 785 node.visitChildren(this); | 786 node.visitChildren(this); |
| 786 return stringType; | 787 return stringType; |
| 787 } | 788 } |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 843 } | 844 } |
| 844 | 845 |
| 845 visitCatchBlock(CatchBlock node) { | 846 visitCatchBlock(CatchBlock node) { |
| 846 return unhandledStatement(); | 847 return unhandledStatement(); |
| 847 } | 848 } |
| 848 | 849 |
| 849 visitTypedef(Typedef node) { | 850 visitTypedef(Typedef node) { |
| 850 return unhandledStatement(); | 851 return unhandledStatement(); |
| 851 } | 852 } |
| 852 } | 853 } |
| OLD | NEW |