Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(154)

Side by Side Diff: lib/compiler/implementation/typechecker.dart

Issue 10834061: Resolve typedefs. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Updated scope handling and type resolution Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698