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 |
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 } catch (CancelTypeCheckException e) { | 17 } catch (CancelTypeCheckException 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 Type { |
28 SourceString get name(); | 28 SourceString get name(); |
29 Element get element(); | 29 Element get element(); |
| 30 |
| 31 /** |
| 32 * Performs the substitution `[arguments[i]/parameters[i]]this`. |
| 33 * The notation is known from this lambda calculus rule: |
| 34 * |
| 35 * (lambda x.e0)e1 -> [e1/x]e0. |
| 36 * |
| 37 * See [TypeVariableType] for a motivation for this method. |
| 38 */ |
| 39 Type subst(Compiler compiler, |
| 40 Link<Type> arguments, Link<TypeVariableType> parameters); |
| 41 |
| 42 /** |
| 43 * Returns the defining type for this type. For non-typedef types, the |
| 44 * defining type is the type itself, whereas for typedef types the defining |
| 45 * type is the defining type of its definition. For example the defining type |
| 46 * for `typedef A Func<A,B>(B b)` is the function type `(B) -> A` and the |
| 47 * defining type for `Func<int,String>` is the function type |
| 48 * `(String) -> int`. |
| 49 */ |
| 50 Type unalias(Compiler compiler); |
30 } | 51 } |
31 | 52 |
| 53 /** |
| 54 * Represents a type variable, that is the type parameters of a class |
| 55 * or interface type. For example, in class Array<E> { ... }`, |
| 56 * E is a type variable. |
| 57 * |
| 58 * Each class/interface should have its own unique type variables, |
| 59 * one for each type parameter. A class/interface with type parameters |
| 60 * is said to be parameterized or generic. |
| 61 * |
| 62 * Non-static members, constructors, and factories of generic |
| 63 * class/interface can refer to type variables of the current class |
| 64 * (not of supertypes). |
| 65 * |
| 66 * When using a generic type, also known as an application or |
| 67 * instantiation of the type, the actual type arguments should be |
| 68 * substituted for the type variables in the class declaration. |
| 69 * |
| 70 * For example, given a box, `class Box<T> { T value; }`, the |
| 71 * type of the expression `new Box<String>().value` is |
| 72 * [String] because we must substitute `String` for the |
| 73 * the type variable `T`. |
| 74 */ |
32 class TypeVariableType implements Type { | 75 class TypeVariableType implements Type { |
33 final SourceString name; | 76 final SourceString name; |
34 TypeVariableElement element; | 77 TypeVariableElement element; |
35 TypeVariableType(this.name, [this.element]); | 78 TypeVariableType(this.name, [this.element]); |
36 | 79 |
37 toString() => name.slowToString(); | 80 Type subst(Compiler compiler, |
| 81 Link<Type> arguments, Link<TypeVariableType> parameters) { |
| 82 if (parameters.isEmpty()) { |
| 83 // Return fast on empty substitutions. |
| 84 return this; |
| 85 } |
| 86 Link<TypeVariableType> parameterLink = parameters; |
| 87 if (arguments.isEmpty()) { |
| 88 // Raw substitution: Dynamic replaces parameters. |
| 89 while (!parameterLink.isEmpty()) { |
| 90 TypeVariableType parameter = parameterLink.head; |
| 91 if (parameter == this) { |
| 92 return compiler.types.dynamicType; |
| 93 } |
| 94 parameterLink = parameterLink.tail; |
| 95 } |
| 96 } else { |
| 97 // Normal substitution. |
| 98 Link<Type> argumentLink = arguments; |
| 99 while (!argumentLink.isEmpty() && !parameterLink.isEmpty()) { |
| 100 TypeVariableType parameter = parameterLink.head; |
| 101 Type argument = argumentLink.head; |
| 102 if (parameter == this) { |
| 103 return argument; |
| 104 } |
| 105 parameterLink = parameterLink.tail; |
| 106 argumentLink = argumentLink.tail; |
| 107 } |
| 108 } |
| 109 // The type variable was not substituted. |
| 110 return this; |
| 111 } |
| 112 |
| 113 Type unalias(Compiler compiler) => this; |
| 114 |
| 115 String toString() => name.slowToString(); |
38 } | 116 } |
39 | 117 |
40 /** | 118 /** |
41 * A statement type tracks whether a statement returns or may return. | 119 * A statement type tracks whether a statement returns or may return. |
42 */ | 120 */ |
43 class StatementType implements Type { | 121 class StatementType implements Type { |
44 final String stringName; | 122 final String stringName; |
45 Element get element() => null; | 123 Element get element() => null; |
46 | 124 |
47 SourceString get name() => new SourceString(stringName); | 125 SourceString get name() => new SourceString(stringName); |
48 | 126 |
49 const StatementType(this.stringName); | 127 const StatementType(this.stringName); |
50 | 128 |
51 static final RETURNING = const StatementType('<returning>'); | 129 static final RETURNING = const StatementType('<returning>'); |
52 static final NOT_RETURNING = const StatementType('<not returning>'); | 130 static final NOT_RETURNING = const StatementType('<not returning>'); |
53 static final MAYBE_RETURNING = const StatementType('<maybe returning>'); | 131 static final MAYBE_RETURNING = const StatementType('<maybe returning>'); |
54 | 132 |
55 /** Combine the information about two control-flow edges that are joined. */ | 133 /** Combine the information about two control-flow edges that are joined. */ |
56 StatementType join(StatementType other) { | 134 StatementType join(StatementType other) { |
57 return (this === other) ? this : MAYBE_RETURNING; | 135 return (this === other) ? this : MAYBE_RETURNING; |
58 } | 136 } |
59 | 137 |
| 138 Type subst(Compiler compiler, |
| 139 Link<Type> arguments, Link<TypeVariableType> parameters) { |
| 140 // Statement types are not substitutable. |
| 141 return this; |
| 142 } |
| 143 |
| 144 Type unalias(Compiler compiler) => this; |
| 145 |
60 String toString() => stringName; | 146 String toString() => stringName; |
61 } | 147 } |
62 | 148 |
63 class VoidType implements Type { | 149 class VoidType implements Type { |
64 const VoidType(this.element); | 150 const VoidType(this.element); |
65 SourceString get name() => element.name; | 151 SourceString get name() => element.name; |
66 final VoidElement element; | 152 final VoidElement element; |
67 | 153 |
68 toString() => name.slowToString(); | 154 Type subst(Compiler compiler, |
| 155 Link<Type> arguments, Link<TypeVariableType> parameters) { |
| 156 // Void cannot be substituted. |
| 157 return this; |
| 158 } |
| 159 |
| 160 Type unalias(Compiler compiler) => this; |
| 161 |
| 162 String toString() => name.slowToString(); |
69 } | 163 } |
70 | 164 |
71 class InterfaceType implements Type { | 165 class InterfaceType implements Type { |
72 final Element element; | 166 final ClassElement element; |
73 final Link<Type> arguments; | 167 final Link<Type> typeArguments; |
74 | 168 |
75 const InterfaceType(this.element, | 169 const InterfaceType(this.element, |
76 [this.arguments = const EmptyLink<Type>()]); | 170 [this.typeArguments = const EmptyLink<Type>()]); |
77 | 171 |
78 SourceString get name() => element.name; | 172 SourceString get name() => element.name; |
79 | 173 |
80 toString() { | 174 Type subst(Compiler compiler, |
| 175 Link<Type> arguments, Link<TypeVariableType> parameters) { |
| 176 if (typeArguments.isEmpty()) { |
| 177 // Return fast on non-generic types. |
| 178 return this; |
| 179 } |
| 180 if (parameters.isEmpty()) { |
| 181 // Return fast on empty substitutions. |
| 182 return this; |
| 183 } |
| 184 if (arguments.isEmpty()) { |
| 185 // Return the 'raw' type on raw substitutions. |
| 186 return new InterfaceType(element); |
| 187 } |
| 188 bool changed = false; |
| 189 var argumentsBuilder = new LinkBuilder<Type>(); |
| 190 Link<Type> typeArgument = typeArguments; |
| 191 while (!typeArgument.isEmpty()) { |
| 192 var argument = |
| 193 typeArgument.head.subst(compiler, arguments, parameters); |
| 194 if (!changed && argument !== typeArgument.head) { |
| 195 changed = true; |
| 196 } |
| 197 argumentsBuilder.addLast(argument); |
| 198 typeArgument = typeArgument.tail; |
| 199 } |
| 200 if (changed) { |
| 201 // Create a new type only if necessary. |
| 202 return new InterfaceType(element, argumentsBuilder.toLink()); |
| 203 } |
| 204 return this; |
| 205 } |
| 206 |
| 207 Type unalias(Compiler compiler) => this; |
| 208 |
| 209 /** |
| 210 * Finds the method, field or property on this interface type named [name]. |
| 211 */ |
| 212 Member lookupMember(Compiler compiler, SourceString name) { |
| 213 ClassElement classElement = element; |
| 214 InterfaceType receiver = this; |
| 215 InterfaceType declarer = receiver; |
| 216 Element member = classElement.lookupLocalMember(name); |
| 217 if (member === null) { |
| 218 classElement.ensureResolved(compiler); |
| 219 for (Link<InterfaceType> supertypes = classElement.allSupertypes; |
| 220 !supertypes.isEmpty() && member === null; |
| 221 supertypes = supertypes.tail) { |
| 222 declarer = supertypes.head; |
| 223 ClassElement lookupTarget = declarer.element; |
| 224 member = lookupTarget.lookupLocalMember(name); |
| 225 } |
| 226 } |
| 227 if (member == null) { |
| 228 return null; |
| 229 } |
| 230 if (member.kind == ElementKind.FUNCTION || |
| 231 member.kind == ElementKind.ABSTRACT_FIELD || |
| 232 member.kind == ElementKind.FIELD) { |
| 233 return new Member(receiver, declarer, member); |
| 234 } |
| 235 return null; |
| 236 } |
| 237 |
| 238 String toString() { |
81 StringBuffer sb = new StringBuffer(); | 239 StringBuffer sb = new StringBuffer(); |
82 sb.add(name.slowToString()); | 240 sb.add(name.slowToString()); |
83 if (!arguments.isEmpty()) { | 241 if (!typeArguments.isEmpty()) { |
84 sb.add('<'); | 242 sb.add('<'); |
85 arguments.printOn(sb, ', '); | 243 typeArguments.printOn(sb, ', '); |
86 sb.add('>'); | 244 sb.add('>'); |
87 } | 245 } |
88 return sb.toString(); | 246 return sb.toString(); |
89 } | 247 } |
90 } | 248 } |
91 | 249 |
92 class FunctionType implements Type { | 250 class FunctionType implements Type { |
93 final Element element; | 251 final Element element; |
94 final Type returnType; | 252 final Type returnType; |
95 final Link<Type> parameterTypes; | 253 Link<Type> parameterTypes; |
96 | 254 |
97 const FunctionType(Type this.returnType, Link<Type> this.parameterTypes, | 255 FunctionType(Type this.returnType, Link<Type> this.parameterTypes, |
98 Element this.element); | 256 Element this.element); |
99 | 257 |
100 toString() { | 258 Type subst(Compiler compiler, |
| 259 Link<Type> arguments, Link<TypeVariableType> parameters) { |
| 260 if (parameters.isEmpty()) { |
| 261 // Return fast on empty substitutions. |
| 262 return this; |
| 263 } |
| 264 var newReturnType = returnType.subst(compiler, arguments, parameters); |
| 265 bool changed = newReturnType !== returnType; |
| 266 var newParameterTypesBuilder = new LinkBuilder<Type>(); |
| 267 Link<Type> parameterType = parameterTypes; |
| 268 while (!parameterType.isEmpty()) { |
| 269 var newParameterType = |
| 270 parameterType.head.subst(compiler, arguments, parameters); |
| 271 if (!changed && newParameterType !== parameterType.head) { |
| 272 changed = true; |
| 273 } |
| 274 newParameterTypesBuilder.addLast(newParameterType); |
| 275 parameterType = parameterType.tail; |
| 276 } |
| 277 if (changed) { |
| 278 // Create a new type only if necessary. |
| 279 return new FunctionType(newReturnType, newParameterTypesBuilder.toLink(), |
| 280 element); |
| 281 } |
| 282 return this; |
| 283 } |
| 284 |
| 285 Type unalias(Compiler compiler) => this; |
| 286 |
| 287 String toString() { |
101 StringBuffer sb = new StringBuffer(); | 288 StringBuffer sb = new StringBuffer(); |
102 bool first = true; | 289 bool first = true; |
103 sb.add('('); | 290 sb.add('('); |
104 parameterTypes.printOn(sb, ', '); | 291 parameterTypes.printOn(sb, ', '); |
105 sb.add(') -> ${returnType}'); | 292 sb.add(') -> ${returnType}'); |
106 return sb.toString(); | 293 return sb.toString(); |
107 } | 294 } |
108 | 295 |
109 SourceString get name() => const SourceString('Function'); | 296 SourceString get name() => const SourceString('Function'); |
110 | 297 |
111 int computeArity() { | 298 int computeArity() { |
112 int arity = 0; | 299 int arity = 0; |
113 parameterTypes.forEach((_) { arity++; }); | 300 parameterTypes.forEach((_) { arity++; }); |
114 return arity; | 301 return arity; |
115 } | 302 } |
116 } | 303 } |
117 | 304 |
| 305 class TypedefType implements Type { |
| 306 final TypedefElement element; |
| 307 final Link<Type> typeArguments; |
| 308 |
| 309 const TypedefType(this.element, |
| 310 [this.typeArguments = const EmptyLink<Type>()]); |
| 311 |
| 312 SourceString get name() => element.name; |
| 313 |
| 314 Type subst(Compiler compiler, |
| 315 Link<Type> arguments, Link<TypeVariableType> parameters) { |
| 316 if (typeArguments.isEmpty()) { |
| 317 // Return fast on non-generic typedefs. |
| 318 return this; |
| 319 } |
| 320 if (parameters.isEmpty()) { |
| 321 // Return fast on empty substitutions. |
| 322 return this; |
| 323 } |
| 324 if (arguments.isEmpty()) { |
| 325 // Return the 'raw' type on raw substitutions. |
| 326 return new TypedefType(element); |
| 327 } |
| 328 bool changed = false; |
| 329 var argumentsBuilder = new LinkBuilder<Type>(); |
| 330 Link<Type> typeArgument = typeArguments; |
| 331 while (!typeArgument.isEmpty()) { |
| 332 var argument = |
| 333 typeArgument.head.subst(compiler, arguments, parameters); |
| 334 if (!changed && argument !== typeArgument.head) { |
| 335 changed = true; |
| 336 } |
| 337 argumentsBuilder.addLast(argument); |
| 338 typeArgument = typeArgument.tail; |
| 339 } |
| 340 if (changed) { |
| 341 // Create a new type only if necessary. |
| 342 return new TypedefType(element, argumentsBuilder.toLink()); |
| 343 } |
| 344 return this; |
| 345 } |
| 346 |
| 347 Type unalias(Compiler compiler) { |
| 348 compiler.resolveTypedef(element); |
| 349 Type definition = element.alias.unalias(compiler); |
| 350 TypedefType declaration = element.computeType(compiler); |
| 351 return definition.subst(compiler, typeArguments, declaration.typeArguments); |
| 352 } |
| 353 |
| 354 String toString() { |
| 355 StringBuffer sb = new StringBuffer(); |
| 356 sb.add(name.slowToString()); |
| 357 if (!typeArguments.isEmpty()) { |
| 358 sb.add('<'); |
| 359 typeArguments.printOn(sb, ', '); |
| 360 sb.add('>'); |
| 361 } |
| 362 return sb.toString(); |
| 363 } |
| 364 } |
| 365 |
| 366 /** |
| 367 * Member encapsulates a member (constructor, method, field, property, getter, |
| 368 * or setter) with the types of the declarer and receiver in order to do |
| 369 * substitution on the member type. |
| 370 * |
| 371 * Consider for instance these classes and the variable `B<String> b`: |
| 372 * |
| 373 * class A<E> { |
| 374 * E field; |
| 375 * } |
| 376 * class B<F> extends A<F> {} |
| 377 * |
| 378 * In a [Member] for `b.field` the [receiver] is `B<String>` and the declarer |
| 379 * is `A<F>`, which is the supertype of `B<F>` from which `field` has been |
| 380 * inherited. To compute the type of `b.field` we must first substitute `E` |
| 381 * by `F` using the relation between `A<E>` and `A<F>`, and then `F` by `String` |
| 382 * using the relation between `B<F>` and `B<String>`. |
| 383 */ |
| 384 class Member { |
| 385 final InterfaceType receiver; |
| 386 final InterfaceType declarer; |
| 387 final Element element; |
| 388 |
| 389 Member(this.receiver, this.declarer, this.element); |
| 390 |
| 391 Type computeType(Compiler compiler) { |
| 392 Type type; |
| 393 if (element.kind == ElementKind.ABSTRACT_FIELD) { |
| 394 AbstractFieldElement abstractFieldElement = element; |
| 395 if (abstractFieldElement.getter != null) { |
| 396 type = abstractFieldElement.getter.computeType(compiler).returnType; |
| 397 } else { |
| 398 type = abstractFieldElement.setter.computeType( |
| 399 compiler).parameterTypes.head; |
| 400 if (type == null) { |
| 401 type = compiler.types.dynamicType; |
| 402 } |
| 403 } |
| 404 } else { |
| 405 type = element.computeType(compiler); |
| 406 } |
| 407 if (!declarer.element.typeVariables.isEmpty()) { |
| 408 type = type.subst(compiler, |
| 409 declarer.typeArguments, |
| 410 declarer.element.computeType(compiler).typeArguments); |
| 411 type = type.subst(compiler, |
| 412 receiver.typeArguments, |
| 413 receiver.element.computeType(compiler).typeArguments); |
| 414 } |
| 415 return type; |
| 416 } |
| 417 |
| 418 String toString() { |
| 419 return '$receiver.$element'; |
| 420 } |
| 421 } |
| 422 |
118 class Types { | 423 class Types { |
| 424 final Compiler compiler; |
119 final VoidType voidType; | 425 final VoidType voidType; |
120 final InterfaceType dynamicType; | 426 final InterfaceType dynamicType; |
121 | 427 |
122 Types(Element dynamicElement) | 428 Types(Compiler compiler, Element dynamicElement) |
123 : this.with(dynamicElement, new LibraryElement(new Script(null, null))); | 429 : this.with(compiler, dynamicElement, |
| 430 new LibraryElement(new Script(null, null))); |
124 | 431 |
125 // TODO(karlklose): should we have a class Void? | 432 // TODO(karlklose): should we have a class Void? |
126 Types.with(Element dynamicElement, LibraryElement library) | 433 Types.with(Compiler this.compiler, |
| 434 Element dynamicElement, |
| 435 LibraryElement library) |
127 : voidType = new VoidType(new VoidElement(library)), | 436 : voidType = new VoidType(new VoidElement(library)), |
128 dynamicType = new InterfaceType(dynamicElement); | 437 dynamicType = new InterfaceType(dynamicElement); |
129 | 438 |
130 /** Returns true if t is a subtype of s */ | 439 /** Returns true if t is a subtype of s */ |
131 bool isSubtype(Type t, Type s) { | 440 bool isSubtype(Type t, Type s) { |
132 if (t === s || t === dynamicType || s === dynamicType || | 441 if (t === s || |
133 // TODO(karlklose): Test for s.element === compiler.objectClass. | 442 t === dynamicType || |
134 s.name == const SourceString('Object')) return true; | 443 s === dynamicType || |
| 444 s.element === compiler.objectClass) { |
| 445 return true; |
| 446 } |
| 447 t = t.unalias(compiler); |
| 448 s = s.unalias(compiler); |
| 449 |
135 if (t is VoidType) { | 450 if (t is VoidType) { |
136 return false; | 451 return false; |
137 } else if (t is InterfaceType) { | 452 } else if (t is InterfaceType) { |
138 if (s is !InterfaceType) return false; | 453 if (s is !InterfaceType) return false; |
139 ClassElement tc = t.element; | 454 ClassElement tc = t.element; |
140 if (tc === s.element) return true; | 455 if (tc === s.element) return true; |
141 for (Link<Type> supertypes = tc.allSupertypes; | 456 for (Link<Type> supertypes = tc.allSupertypes; |
142 supertypes != null && !supertypes.isEmpty(); | 457 supertypes != null && !supertypes.isEmpty(); |
143 supertypes = supertypes.tail) { | 458 supertypes = supertypes.tail) { |
144 Type supertype = supertypes.head; | 459 Type supertype = supertypes.head; |
145 if (supertype.element === s.element) return true; | 460 if (supertype.element === s.element) return true; |
146 } | 461 } |
147 return false; | 462 return false; |
148 } else if (t is FunctionType) { | 463 } else if (t is FunctionType) { |
| 464 if (s.element == compiler.functionClass) return true; |
149 if (s is !FunctionType) return false; | 465 if (s is !FunctionType) return false; |
150 FunctionType tf = t; | 466 FunctionType tf = t; |
151 FunctionType sf = s; | 467 FunctionType sf = s; |
152 Link<Type> tps = tf.parameterTypes; | 468 Link<Type> tps = tf.parameterTypes; |
153 Link<Type> sps = sf.parameterTypes; | 469 Link<Type> sps = sf.parameterTypes; |
154 while (!tps.isEmpty() && !sps.isEmpty()) { | 470 while (!tps.isEmpty() && !sps.isEmpty()) { |
155 if (!isAssignable(tps.head, sps.head)) return false; | 471 if (!isAssignable(tps.head, sps.head)) return false; |
156 tps = tps.tail; | 472 tps = tps.tail; |
157 sps = sps.tail; | 473 sps = sps.tail; |
158 } | 474 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
199 | 515 |
200 TypeCheckerVisitor(this.compiler, this.elements, this.types) { | 516 TypeCheckerVisitor(this.compiler, this.elements, this.types) { |
201 intType = compiler.intClass.computeType(compiler); | 517 intType = compiler.intClass.computeType(compiler); |
202 doubleType = compiler.doubleClass.computeType(compiler); | 518 doubleType = compiler.doubleClass.computeType(compiler); |
203 boolType = compiler.boolClass.computeType(compiler); | 519 boolType = compiler.boolClass.computeType(compiler); |
204 stringType = compiler.stringClass.computeType(compiler); | 520 stringType = compiler.stringClass.computeType(compiler); |
205 objectType = compiler.objectClass.computeType(compiler); | 521 objectType = compiler.objectClass.computeType(compiler); |
206 listType = compiler.listClass.computeType(compiler); | 522 listType = compiler.listClass.computeType(compiler); |
207 } | 523 } |
208 | 524 |
209 Type fail(node, [reason]) { | 525 Type fail(Node node, [reason]) { |
210 String message = 'cannot type-check'; | 526 String message = 'cannot type-check'; |
211 if (reason !== null) { | 527 if (node != null) { |
| 528 message = '$message ${node.getObjectDescription()} `$node`'; |
| 529 } |
| 530 if (reason != null) { |
212 message = '$message: $reason'; | 531 message = '$message: $reason'; |
213 } | 532 } |
214 throw new CancelTypeCheckException(node, message); | 533 throw new CancelTypeCheckException(node, message); |
215 } | 534 } |
216 | 535 |
217 reportTypeWarning(Node node, MessageKind kind, [List arguments = const []]) { | 536 reportTypeWarning(Node node, MessageKind kind, [List arguments = const []]) { |
218 compiler.reportWarning(node, new TypeWarning(kind, arguments)); | 537 compiler.reportWarning(node, new TypeWarning(kind, arguments)); |
219 } | 538 } |
220 | 539 |
221 // TODO(karlklose): remove these functions. | 540 // TODO(karlklose): remove these functions. |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
387 } | 706 } |
388 } | 707 } |
389 if (member !== null && member.kind == ElementKind.FUNCTION) { | 708 if (member !== null && member.kind == ElementKind.FUNCTION) { |
390 return computeType(member); | 709 return computeType(member); |
391 } | 710 } |
392 reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND, | 711 reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND, |
393 [classElement.name, name]); | 712 [classElement.name, name]); |
394 return types.dynamicType; | 713 return types.dynamicType; |
395 } | 714 } |
396 | 715 |
| 716 /** |
| 717 * Returns the interface type on which to lookup members. If [type] is the |
| 718 * function of a getter, the return type is returned. If [type] is a type |
| 719 * variable the bound is returned. |
| 720 */ |
| 721 InterfaceType findReceiverType(Node receiver, Type receiverType) { |
| 722 if (receiverType === null) { |
| 723 fail(receiver, 'receivertype is null'); |
| 724 } |
| 725 if (receiverType.element == compiler.dynamicClass) { |
| 726 return receiverType; |
| 727 } |
| 728 ElementKind receiverKind = receiverType.element.kind; |
| 729 if (receiverKind === ElementKind.GETTER) { |
| 730 FunctionType getterType = receiverType; |
| 731 return findReceiverType(receiver, getterType.returnType); |
| 732 } |
| 733 if (receiverKind === ElementKind.TYPEDEF) { |
| 734 // TODO(karlklose): handle typedefs. |
| 735 return null; |
| 736 } |
| 737 if (receiverKind === ElementKind.TYPE_VARIABLE) { |
| 738 TypeVariableElement typeVariableElement = receiverType.element; |
| 739 return findReceiverType(receiver, typeVariableElement.bound); |
| 740 } |
| 741 if (receiverKind !== ElementKind.CLASS) { |
| 742 fail(receiver, 'unexpected receiver kind: ${receiverKind}'); |
| 743 } |
| 744 return receiverType; |
| 745 } |
| 746 |
397 void analyzeArguments(Send send, FunctionType funType) { | 747 void analyzeArguments(Send send, FunctionType funType) { |
398 Link<Node> arguments = send.arguments; | 748 Link<Node> arguments = send.arguments; |
399 if (funType === null || funType === types.dynamicType) { | 749 if (funType === null || funType === types.dynamicType) { |
400 while(!arguments.isEmpty()) { | 750 while(!arguments.isEmpty()) { |
401 analyze(arguments.head); | 751 analyze(arguments.head); |
402 arguments = arguments.tail; | 752 arguments = arguments.tail; |
403 } | 753 } |
404 } else { | 754 } else { |
405 Link<Type> parameterTypes = funType.parameterTypes; | 755 Link<Type> parameterTypes = funType.parameterTypes; |
406 while (!arguments.isEmpty() && !parameterTypes.isEmpty()) { | 756 while (!arguments.isEmpty() && !parameterTypes.isEmpty()) { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
452 if (!arguments.isEmpty()) { | 802 if (!arguments.isEmpty()) { |
453 // TODO(karlklose): check number of arguments in validator. | 803 // TODO(karlklose): check number of arguments in validator. |
454 checkAssignable(secondArgument, boolType, secondArgumentType); | 804 checkAssignable(secondArgument, boolType, secondArgumentType); |
455 } | 805 } |
456 return boolType; | 806 return boolType; |
457 } | 807 } |
458 fail(selector, 'unexpected operator ${name}'); | 808 fail(selector, 'unexpected operator ${name}'); |
459 | 809 |
460 } else if (node.isPropertyAccess) { | 810 } else if (node.isPropertyAccess) { |
461 if (node.receiver !== null) { | 811 if (node.receiver !== null) { |
462 // TODO(karlklose): we cannot handle fields. | 812 InterfaceType receiverType = |
463 return unhandledExpression(); | 813 findReceiverType(node.receiver, analyze(node.receiver)); |
| 814 if (receiverType === null) return null; |
| 815 if (receiverType.element === compiler.dynamicClass) { |
| 816 return types.dynamicType; |
| 817 } |
| 818 |
| 819 Member member = receiverType.lookupMember(compiler, selector.source); |
| 820 if (member === null || |
| 821 !(member.element.kind === ElementKind.FIELD || |
| 822 member.element.kind === ElementKind.ABSTRACT_FIELD)) { |
| 823 reportTypeWarning(selector, MessageKind.PROPERTY_NOT_FOUND, |
| 824 [receiverType, selector.source]); |
| 825 } else { |
| 826 return member.computeType(compiler); |
| 827 } |
| 828 return types.dynamicType; |
| 829 } else { |
| 830 Element element = elements[node]; |
| 831 if (element === null) { |
| 832 return types.dynamicType; |
| 833 } |
| 834 if ((element.kind == ElementKind.FIELD || |
| 835 element.kind == ElementKind.GETTER) && |
| 836 element.isInstanceMember()) { |
| 837 // Ensure substitution of declared type variables with inherited type |
| 838 // variables. |
| 839 InterfaceType thisType = currentClass.computeType(compiler); |
| 840 Member member = thisType.lookupMember(compiler, selector.source); |
| 841 if (member != null) { |
| 842 // Should always work! |
| 843 return member.computeType(compiler); |
| 844 } |
| 845 compiler.internalError('Could not lookup resolved member ' |
| 846 '${selector.source} on ${thisType}.'); |
| 847 } |
| 848 return computeType(element); |
464 } | 849 } |
465 Element element = elements[node]; | |
466 if (element === null) return types.dynamicType; | |
467 return computeType(element); | |
468 | |
469 } else if (node.isFunctionObjectInvocation) { | 850 } else if (node.isFunctionObjectInvocation) { |
470 fail(node.receiver, 'function object invocation unimplemented'); | 851 fail(node.receiver, 'function object invocation unimplemented'); |
471 | 852 |
472 } else { | 853 } else { |
473 FunctionType computeFunType() { | 854 FunctionType computeFunType() { |
474 if (node.receiver !== null) { | 855 if (node.receiver !== null) { |
475 Type receiverType = analyze(node.receiver); | 856 InterfaceType receiverType = |
476 if (receiverType.element == compiler.dynamicClass) return null; | 857 findReceiverType(node.receiver, analyze(node.receiver)); |
477 if (receiverType === null) { | 858 if (receiverType === null) return null; |
478 fail(node.receiver, 'receivertype is null'); | 859 if (receiverType.element === compiler.dynamicClass) return null; |
479 } | 860 |
480 if (receiverType.element.kind === ElementKind.GETTER) { | 861 Member member = receiverType.lookupMember(compiler, selector.source); |
481 FunctionType getterType = receiverType; | 862 if (member === null || member.element.kind !== ElementKind.FUNCTION) { |
482 receiverType = getterType.returnType; | 863 reportTypeWarning(selector, MessageKind.METHOD_NOT_FOUND, |
483 } | 864 [receiverType, name]); |
484 ElementKind receiverKind = receiverType.element.kind; | |
485 if (receiverKind === ElementKind.TYPEDEF) { | |
486 // TODO(karlklose): handle typedefs. | |
487 return null; | 865 return null; |
488 } | 866 } |
489 if (receiverKind === ElementKind.TYPE_VARIABLE) { | 867 Type memberType = member.computeType(compiler); |
490 // TODO(karlklose): handle type variables. | 868 if (memberType.element == compiler.dynamicClass) return null; |
491 return null; | 869 if (memberType.element == compiler.functionClass) return null; |
492 } | |
493 if (receiverKind !== ElementKind.CLASS) { | |
494 fail(node.receiver, 'unexpected receiver kind: ${receiverKind}'); | |
495 } | |
496 ClassElement classElement = receiverType.element; | |
497 // TODO(karlklose): substitute type arguments. | |
498 Type memberType = | |
499 lookupMethodType(selector, classElement, selector.source); | |
500 if (memberType.element === compiler.dynamicClass) return null; | |
501 return memberType; | 870 return memberType; |
502 } else { | 871 } else { |
503 Element element = elements[node]; | 872 Element element = elements[node]; |
504 if (element === null) { | 873 if (element === null) { |
505 fail(node, 'unresolved ${node.selector}'); | 874 fail(node, 'unresolved ${node.selector}'); |
506 } else if (element.kind === ElementKind.FUNCTION) { | 875 } else if (element.kind === ElementKind.FUNCTION) { |
| 876 if (element.isInstanceMember()) { |
| 877 // Ensure substitution of declared type variables with inherited |
| 878 // type variables. |
| 879 InterfaceType thisType = currentClass.computeType(compiler); |
| 880 Member member = thisType.lookupMember(compiler, selector.source); |
| 881 if (member != null) { |
| 882 // Should always work! |
| 883 return member.computeType(compiler); |
| 884 } |
| 885 compiler.internalError('Could not lookup resolved member ' |
| 886 '${selector.source} on ${thisType}.'); |
| 887 } |
507 return computeType(element); | 888 return computeType(element); |
508 } else if (element.kind === ElementKind.FOREIGN) { | 889 } else if (element.kind === ElementKind.FOREIGN) { |
509 return null; | 890 return null; |
510 } else if (element.kind === ElementKind.VARIABLE | 891 } else if (element.kind === ElementKind.VARIABLE || |
511 || element.kind === ElementKind.FIELD) { | 892 element.kind === ElementKind.FIELD) { |
512 // TODO(karlklose): handle object invocations. | 893 // TODO(karlklose): handle object invocations. |
513 return null; | 894 return null; |
514 } else { | 895 } else { |
515 fail(node, 'unexpected element kind ${element.kind}'); | 896 fail(node, 'unexpected element kind ${element.kind}'); |
516 } | 897 } |
517 } | 898 } |
518 } | 899 } |
519 FunctionType funType = computeFunType(); | 900 FunctionType funType = computeFunType(); |
520 analyzeArguments(node, funType); | 901 analyzeArguments(node, funType); |
521 return (funType !== null) ? funType.returnType : types.dynamicType; | 902 return (funType !== null) ? funType.returnType : types.dynamicType; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
558 analyze(node.first); | 939 analyze(node.first); |
559 analyze(node.second); | 940 analyze(node.second); |
560 return stringType; | 941 return stringType; |
561 } | 942 } |
562 | 943 |
563 Type visitLiteralNull(LiteralNull node) { | 944 Type visitLiteralNull(LiteralNull node) { |
564 return types.dynamicType; | 945 return types.dynamicType; |
565 } | 946 } |
566 | 947 |
567 Type visitNewExpression(NewExpression node) { | 948 Type visitNewExpression(NewExpression node) { |
| 949 InterfaceType type = elements.getType(node.getTypeAnnotation()); |
568 Element element = elements[node.send]; | 950 Element element = elements[node.send]; |
569 analyzeArguments(node.send, computeType(element)); | 951 var member = new Member(type, |
570 return analyze(node.send.selector); | 952 element.enclosingElement.computeType(compiler), |
| 953 element); |
| 954 analyzeArguments(node.send, member.computeType(compiler)); |
| 955 return type; |
571 } | 956 } |
572 | 957 |
573 Type visitLiteralList(LiteralList node) { | 958 Type visitLiteralList(LiteralList node) { |
574 return listType; | 959 Type elementType = node.type != null |
| 960 ? elements[node.type] |
| 961 : compiler.types.dynamicType; |
| 962 var linkBuilder = new LinkBuilder<Type>(); |
| 963 linkBuilder.addLast(elementType); |
| 964 return new InterfaceType(listType.element, linkBuilder.toLink()); |
575 } | 965 } |
576 | 966 |
577 Type visitNodeList(NodeList node) { | 967 Type visitNodeList(NodeList node) { |
578 Type type = StatementType.NOT_RETURNING; | 968 Type type = StatementType.NOT_RETURNING; |
579 bool reportedDeadCode = false; | 969 bool reportedDeadCode = false; |
580 for (Link<Node> link = node.nodes; !link.isEmpty(); link = link.tail) { | 970 for (Link<Node> link = node.nodes; !link.isEmpty(); link = link.tail) { |
581 Type nextType = analyze(link.head); | 971 Type nextType = analyze(link.head); |
582 if (type == StatementType.RETURNING) { | 972 if (type == StatementType.RETURNING) { |
583 if (!reportedDeadCode) { | 973 if (!reportedDeadCode) { |
584 reportTypeWarning(link.head, MessageKind.UNREACHABLE_CODE); | 974 reportTypeWarning(link.head, MessageKind.UNREACHABLE_CODE); |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
772 } | 1162 } |
773 | 1163 |
774 visitCatchBlock(CatchBlock node) { | 1164 visitCatchBlock(CatchBlock node) { |
775 return unhandledStatement(); | 1165 return unhandledStatement(); |
776 } | 1166 } |
777 | 1167 |
778 visitTypedef(Typedef node) { | 1168 visitTypedef(Typedef node) { |
779 return unhandledStatement(); | 1169 return unhandledStatement(); |
780 } | 1170 } |
781 } | 1171 } |
OLD | NEW |