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

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

Issue 10826045: Substitution handled for most Send nodes. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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
« no previous file with comments | « lib/compiler/implementation/tree/nodes.dart ('k') | lib/compiler/implementation/warnings.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
(...skipping 11 matching lines...) Expand all
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 30
31 /** 31 /**
32 * Performs the substitution [arguments[i]/parameters[i]]this. 32 * Performs the substitution `[arguments[i]/parameters[i]]this`, where
33 * `parameters[i]` denotes the i'th type variable in [typeParameters].
33 * The notation is known from this lambda calculus rule: 34 * The notation is known from this lambda calculus rule:
34 * (lambda x.e0)e1 -> [e1/x]e0. 35 *
36 * (lambda x.e0)e1 -> [e1/x]e0.
35 * 37 *
36 * See [TypeVariableType] for a motivation for this method. 38 * See [TypeVariableType] for a motivation for this method.
37 */ 39 */
38 Type subst(Link<Type> arguments, List<Type> parameters); 40 Type subst(Compiler compiler, Link<Type> arguments,
41 LinkedHashMap<SourceString, TypeVariableElement> typeParameters);
39 } 42 }
40 43
41 /** 44 /**
42 * Represents a type variable, that is the type parameters of a class 45 * Represents a type variable, that is the type parameters of a class
43 * or interface type. For example, in class Array<E> { ... }`, 46 * or interface type. For example, in class Array<E> { ... }`,
44 * E is a type variable. 47 * E is a type variable.
45 * 48 *
46 * Each class/interface should have its own unique type variables, 49 * Each class/interface should have its own unique type variables,
47 * one for each type parameter. A class/interface with type parameters 50 * one for each type parameter. A class/interface with type parameters
48 * is said to be parameterized or generic. 51 * is said to be parameterized or generic.
49 * 52 *
50 * Non-static members, constructors, and factories of generic 53 * Non-static members, constructors, and factories of generic
51 * class/interface can refer to type variables of the current class 54 * class/interface can refer to type variables of the current class
52 * (not of supertypes). 55 * (not of supertypes).
53 * 56 *
54 * When using a generic type, also known as an application or 57 * When using a generic type, also known as an application or
55 * instantiation of the type, the actual type arguments should be 58 * instantiation of the type, the actual type arguments should be
56 * substituted for the type variables in the class declaration. 59 * substituted for the type variables in the class declaration.
57 * 60 *
58 * For example, given a box, `class Box<T> { T value; }`, the 61 * For example, given a box, `class Box<T> { T value; }`, the
59 * type of the expression `new Box<String>().value` is 62 * type of the expression `new Box<String>().value` is
60 * [String] because we must substitute `String` for the 63 * [String] because we must substitute `String` for the
61 * the type variable `T`. 64 * the type variable `T`.
62 */ 65 */
63 class TypeVariableType implements Type { 66 class TypeVariableType implements Type {
64 final SourceString name; 67 final SourceString name;
65 TypeVariableElement element; 68 TypeVariableElement element;
66 TypeVariableType(this.name, [this.element]); 69 TypeVariableType(this.name, [this.element]);
67 70
68 Type subst(Link<Type> arguments, List<Type> parameters) { 71 Type subst(Compiler compiler, Link<Type> arguments,
69 if (arguments.isEmpty()) { 72 LinkedHashMap<SourceString, TypeVariableElement> typeParameters) {
73 if (typeParameters.isEmpty()) {
70 // Return fast on empty substitutions. 74 // Return fast on empty substitutions.
71 return this; 75 return this;
72 } 76 }
73 Link<Type> argumentLink = arguments; 77 Iterator<TypeVariableElement> parameterIterator =
74 Iterator<Type> parameterIterator = parameters.iterator(); 78 typeParameters.getValues().iterator();
75 while (!argumentLink.isEmpty() && parameterIterator.hasNext()) { 79 if (arguments.isEmpty()) {
76 Type parameter = parameterIterator.next(); 80 // Raw substitution: Dynamic replaces parameters.
77 Type argument = argumentLink.head; 81 while (parameterIterator.hasNext()) {
78 if (parameter === this) { 82 TypeVariableType parameter = parameterIterator.next().type;
79 return argument; 83 if (parameter == this) {
84 return compiler.types.dynamicType;
85 }
80 } 86 }
81 argumentLink = argumentLink.tail; 87 } else {
88 // Normal substitution.
89 Link<Type> argumentLink = arguments;
90 while (!argumentLink.isEmpty() && parameterIterator.hasNext()) {
91 TypeVariableType parameter = parameterIterator.next().type;
92 Type argument = argumentLink.head;
93 if (parameter == this) {
94 return argument;
95 }
96 argumentLink = argumentLink.tail;
97 }
82 } 98 }
83 // The type variable was not substituted. 99 // The type variable was not substituted.
84 return this; 100 return this;
85 } 101 }
86 102
87 String toString() => name.slowToString(); 103 String toString() => name.slowToString();
88 } 104 }
89 105
90 /** 106 /**
91 * A statement type tracks whether a statement returns or may return. 107 * A statement type tracks whether a statement returns or may return.
92 */ 108 */
93 class StatementType implements Type { 109 class StatementType implements Type {
94 final String stringName; 110 final String stringName;
95 Element get element() => null; 111 Element get element() => null;
96 112
97 SourceString get name() => new SourceString(stringName); 113 SourceString get name() => new SourceString(stringName);
98 114
99 const StatementType(this.stringName); 115 const StatementType(this.stringName);
100 116
101 static final RETURNING = const StatementType('<returning>'); 117 static final RETURNING = const StatementType('<returning>');
102 static final NOT_RETURNING = const StatementType('<not returning>'); 118 static final NOT_RETURNING = const StatementType('<not returning>');
103 static final MAYBE_RETURNING = const StatementType('<maybe returning>'); 119 static final MAYBE_RETURNING = const StatementType('<maybe returning>');
104 120
105 /** Combine the information about two control-flow edges that are joined. */ 121 /** Combine the information about two control-flow edges that are joined. */
106 StatementType join(StatementType other) { 122 StatementType join(StatementType other) {
107 return (this === other) ? this : MAYBE_RETURNING; 123 return (this === other) ? this : MAYBE_RETURNING;
108 } 124 }
109 125
110 Type subst(Link<Type> arguments, List<Type> parameters) { 126 Type subst(Compiler compiler, Link<Type> arguments,
127 LinkedHashMap<SourceString, TypeVariableElement> typeParameters) {
111 // Statement types are not substitutable. 128 // Statement types are not substitutable.
112 return this; 129 return this;
113 } 130 }
114 131
115 String toString() => stringName; 132 String toString() => stringName;
116 } 133 }
117 134
118 class VoidType implements Type { 135 class VoidType implements Type {
119 const VoidType(this.element); 136 const VoidType(this.element);
120 SourceString get name() => element.name; 137 SourceString get name() => element.name;
121 final VoidElement element; 138 final VoidElement element;
122 139
123 Type subst(Link<Type> arguments, List<Type> parameters) { 140 Type subst(Compiler compiler, Link<Type> arguments,
141 LinkedHashMap<SourceString, TypeVariableElement> typeParameters) {
124 // Void cannot be substituted. 142 // Void cannot be substituted.
125 return this; 143 return this;
126 } 144 }
127 145
128 String toString() => name.slowToString(); 146 String toString() => name.slowToString();
129 } 147 }
130 148
131 class InterfaceType implements Type { 149 class InterfaceType implements Type {
132 final Element element; 150 final ClassElement element;
133 final Link<Type> arguments; 151 final Link<Type> typeArguments;
134 152
135 const InterfaceType(this.element, 153 const InterfaceType(this.element,
136 [this.arguments = const EmptyLink<Type>()]); 154 [this.typeArguments = const EmptyLink<Type>()]);
137 155
138 SourceString get name() => element.name; 156 SourceString get name() => element.name;
139 157
140 Type subst(Link<Type> replacements, List<Type> parameters) { 158 Type subst(Compiler compiler, Link<Type> arguments,
141 if (arguments.isEmpty()) { 159 LinkedHashMap<SourceString, TypeVariableElement> typeParameters) {
160 if (typeArguments.isEmpty()) {
142 // Return fast on non-generic types. 161 // Return fast on non-generic types.
143 return this; 162 return this;
144 } 163 }
145 if (replacements.isEmpty()) { 164 if (typeParameters.isEmpty()) {
146 // Return fast on empty substitutions. 165 // Return fast on empty substitutions.
147 return this; 166 return this;
148 } 167 }
168 if (arguments.isEmpty()) {
169 // Return the 'raw' type on raw substitutions.
170 return new InterfaceType(element);
171 }
149 bool changed = false; 172 bool changed = false;
150 var argumentsBuilder = new LinkBuilder<Type>(); 173 var argumentsBuilder = new LinkBuilder<Type>();
151 Link<Type> argument = arguments; 174 Link<Type> typeArgument = typeArguments;
152 while (!argument.isEmpty()) { 175 while (!typeArgument.isEmpty()) {
153 var replacement = argument.head.subst(replacements, parameters); 176 var argument =
154 if (!changed && replacement !== argument.head) { 177 typeArgument.head.subst(compiler, arguments, typeParameters);
178 if (!changed && argument !== typeArgument.head) {
155 changed = true; 179 changed = true;
156 } 180 }
157 argumentsBuilder.addLast(replacement); 181 argumentsBuilder.addLast(argument);
158 argument = argument.tail; 182 typeArgument = typeArgument.tail;
159 } 183 }
160 if (changed) { 184 if (changed) {
161 // Create a new type only if necessary. 185 // Create a new type only if necessary.
162 return new InterfaceType(element, argumentsBuilder.toLink()); 186 return new InterfaceType(element, argumentsBuilder.toLink());
163 } 187 }
164 return this; 188 return this;
165 } 189 }
166 190
191 /**
192 * Finds the method, field or property on this interface type named [name].
193 */
194 Member lookupMember(Compiler compiler, SourceString name) {
195 ClassElement classElement = element;
196 InterfaceType receiver = this;
197 InterfaceType declarer = receiver;
198 Element member = classElement.lookupLocalMember(name);
199 if (member === null) {
200 classElement.ensureResolved(compiler);
201 for (Link<InterfaceType> supertypes = classElement.allSupertypes;
202 !supertypes.isEmpty() && member === null;
203 supertypes = supertypes.tail) {
204 declarer = supertypes.head;
205 ClassElement lookupTarget = declarer.element;
206 member = lookupTarget.lookupLocalMember(name);
207 }
208 }
209 if (member == null) {
210 return null;
211 }
212 if (member.kind == ElementKind.FUNCTION ||
213 member.kind == ElementKind.ABSTRACT_FIELD ||
214 member.kind == ElementKind.FIELD) {
215 return new Member(receiver, declarer, member);
216 }
217 return null;
218 }
219
167 String toString() { 220 String toString() {
168 StringBuffer sb = new StringBuffer(); 221 StringBuffer sb = new StringBuffer();
169 sb.add(name.slowToString()); 222 sb.add(name.slowToString());
170 if (!arguments.isEmpty()) { 223 if (!typeArguments.isEmpty()) {
171 sb.add('<'); 224 sb.add('<');
172 arguments.printOn(sb, ', '); 225 typeArguments.printOn(sb, ', ');
173 sb.add('>'); 226 sb.add('>');
174 } 227 }
175 return sb.toString(); 228 return sb.toString();
176 } 229 }
177 } 230 }
178 231
179 class FunctionType implements Type { 232 class FunctionType implements Type {
180 final Element element; 233 final Element element;
181 final Type returnType; 234 final Type returnType;
182 final Link<Type> parameterTypes; 235 final Link<Type> parameterTypes;
183 236
184 const FunctionType(Type this.returnType, Link<Type> this.parameterTypes, 237 const FunctionType(Type this.returnType, Link<Type> this.parameterTypes,
185 Element this.element); 238 Element this.element);
186 239
187 Type subst(Link<Type> arguments, List<Type> parameters) { 240 Type subst(Compiler compiler, Link<Type> arguments,
188 if (arguments.isEmpty()) { 241 LinkedHashMap<SourceString, TypeVariableElement> typeParameters) {
242 if (typeParameters.isEmpty()) {
189 // Return fast on empty substitutions. 243 // Return fast on empty substitutions.
190 return this; 244 return this;
191 } 245 }
192 var newReturnType = returnType.subst(arguments, parameters); 246 var newReturnType = returnType.subst(compiler, arguments, typeParameters);
193 bool changed = newReturnType !== returnType; 247 bool changed = newReturnType !== returnType;
194 var parameterBuilder = new LinkBuilder<Type>(); 248 var newParameterTypesBuilder = new LinkBuilder<Type>();
195 Link<Type> parameterType = parameterTypes; 249 Link<Type> parameterType = parameterTypes;
196 while (!parameterType.isEmpty()) { 250 while (!parameterType.isEmpty()) {
197 var replacement = parameterType.head.subst(arguments, parameters); 251 var newParameterType =
198 if (!changed && replacement !== parameterType.head) { 252 parameterType.head.subst(compiler, arguments, typeParameters);
253 if (!changed && newParameterType !== parameterType.head) {
199 changed = true; 254 changed = true;
200 } 255 }
201 parameterBuilder.addLast(replacement); 256 newParameterTypesBuilder.addLast(newParameterType);
202 parameterType = parameterType.tail; 257 parameterType = parameterType.tail;
203 } 258 }
204 if (changed) { 259 if (changed) {
205 // Create a new type only if necessary. 260 // Create a new type only if necessary.
206 return new FunctionType(newReturnType, parameterBuilder.toLink(), 261 return new FunctionType(newReturnType, newParameterTypesBuilder.toLink(),
207 element); 262 element);
208 } 263 }
209 return this; 264 return this;
210 } 265 }
211 266
212 String toString() { 267 String toString() {
213 StringBuffer sb = new StringBuffer(); 268 StringBuffer sb = new StringBuffer();
214 bool first = true; 269 bool first = true;
215 sb.add('('); 270 sb.add('(');
216 parameterTypes.printOn(sb, ', '); 271 parameterTypes.printOn(sb, ', ');
217 sb.add(') -> ${returnType}'); 272 sb.add(') -> ${returnType}');
218 return sb.toString(); 273 return sb.toString();
219 } 274 }
220 275
221 SourceString get name() => const SourceString('Function'); 276 SourceString get name() => const SourceString('Function');
222 277
223 int computeArity() { 278 int computeArity() {
224 int arity = 0; 279 int arity = 0;
225 parameterTypes.forEach((_) { arity++; }); 280 parameterTypes.forEach((_) { arity++; });
226 return arity; 281 return arity;
227 } 282 }
228 } 283 }
229 284
285 /**
286 * Member encapsulates a member (constructor, method, field, property, getter,
287 * or setter) with the types of the declarer and receiver in order to do
288 * substitution on the member type.
289 *
290 * Consider for instance these classes and the variable `B<String> b`:
291 *
292 * class A<E> {
293 * E field;
294 * }
295 * class B<F> extends A<F> {}
296 *
297 * In a [Member] for `b.field` the [receiver] is `B<String>` and the declarer
298 * is `A<F>`, which is the supertype of `B<F>` from which `field` has been
299 * inherited. To compute the type of `b.field` we must first substitute `E`
300 * by `F` using the relation between `A<E>` and `A<F>`, and then `F` by `String`
301 * using the relation between `B<F>` and `B<String>`.
302 */
303 class Member {
304 final InterfaceType receiver;
305 final InterfaceType declarer;
306 final Element element;
307
308 Member(this.receiver, this.declarer, this.element);
309
310 Type computeType(Compiler compiler) {
311 Type type;
312 if (element.kind == ElementKind.ABSTRACT_FIELD) {
313 AbstractFieldElement abstractFieldElement = element;
314 if (abstractFieldElement.getter != null) {
315 type = abstractFieldElement.getter.computeType(compiler).returnType;
316 } else {
317 type = abstractFieldElement.setter.computeType(
318 compiler).parameterTypes.head;
319 if (type == null) {
320 type = compiler.types.dynamicType;
321 }
322 }
323 } else {
324 type = element.computeType(compiler);
325 }
326 if (!declarer.element.typeParameters.isEmpty()) {
327 type = type.subst(compiler,
328 declarer.typeArguments, declarer.element.typeParameters);
329 type = type.subst(compiler,
330 receiver.typeArguments, receiver.element.typeParameters);
331 }
332 return type;
333 }
334
335 String toString() {
336 return '$receiver.$element';
337 }
338 }
339
230 class Types { 340 class Types {
231 final VoidType voidType; 341 final VoidType voidType;
232 final InterfaceType dynamicType; 342 final InterfaceType dynamicType;
343 final Element functionElement;
233 344
234 Types(Element dynamicElement) 345 Types(Element dynamicElement, Element functionElement)
235 : this.with(dynamicElement, new LibraryElement(new Script(null, null))); 346 : this.with(dynamicElement, functionElement,
347 new LibraryElement(new Script(null, null)));
236 348
237 // TODO(karlklose): should we have a class Void? 349 // TODO(karlklose): should we have a class Void?
238 Types.with(Element dynamicElement, LibraryElement library) 350 Types.with(Element dynamicElement,
351 Element this.functionElement,
352 LibraryElement library)
239 : voidType = new VoidType(new VoidElement(library)), 353 : voidType = new VoidType(new VoidElement(library)),
240 dynamicType = new InterfaceType(dynamicElement); 354 dynamicType = new InterfaceType(dynamicElement);
241 355
242 /** Returns true if t is a subtype of s */ 356 /** Returns true if t is a subtype of s */
243 bool isSubtype(Type t, Type s) { 357 bool isSubtype(Type t, Type s) {
244 if (t === s || t === dynamicType || s === dynamicType || 358 if (t === s || t === dynamicType || s === dynamicType ||
245 // TODO(karlklose): Test for s.element === compiler.objectClass. 359 // TODO(karlklose): Test for s.element === compiler.objectClass.
246 s.name == const SourceString('Object')) return true; 360 s.name == const SourceString('Object')) return true;
247 if (t is VoidType) { 361 if (t is VoidType) {
248 return false; 362 return false;
249 } else if (t is InterfaceType) { 363 } else if (t is InterfaceType) {
250 if (s is !InterfaceType) return false; 364 if (s is !InterfaceType) return false;
251 ClassElement tc = t.element; 365 ClassElement tc = t.element;
252 if (tc === s.element) return true; 366 if (tc === s.element) return true;
253 for (Link<Type> supertypes = tc.allSupertypes; 367 for (Link<Type> supertypes = tc.allSupertypes;
254 supertypes != null && !supertypes.isEmpty(); 368 supertypes != null && !supertypes.isEmpty();
255 supertypes = supertypes.tail) { 369 supertypes = supertypes.tail) {
256 Type supertype = supertypes.head; 370 Type supertype = supertypes.head;
257 if (supertype.element === s.element) return true; 371 if (supertype.element === s.element) return true;
258 } 372 }
259 return false; 373 return false;
260 } else if (t is FunctionType) { 374 } else if (t is FunctionType) {
375 if (s.element == functionElement) return true;
261 if (s is !FunctionType) return false; 376 if (s is !FunctionType) return false;
262 FunctionType tf = t; 377 FunctionType tf = t;
263 FunctionType sf = s; 378 FunctionType sf = s;
264 Link<Type> tps = tf.parameterTypes; 379 Link<Type> tps = tf.parameterTypes;
265 Link<Type> sps = sf.parameterTypes; 380 Link<Type> sps = sf.parameterTypes;
266 while (!tps.isEmpty() && !sps.isEmpty()) { 381 while (!tps.isEmpty() && !sps.isEmpty()) {
267 if (!isAssignable(tps.head, sps.head)) return false; 382 if (!isAssignable(tps.head, sps.head)) return false;
268 tps = tps.tail; 383 tps = tps.tail;
269 sps = sps.tail; 384 sps = sps.tail;
270 } 385 }
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 426
312 TypeCheckerVisitor(this.compiler, this.elements, this.types) { 427 TypeCheckerVisitor(this.compiler, this.elements, this.types) {
313 intType = compiler.intClass.computeType(compiler); 428 intType = compiler.intClass.computeType(compiler);
314 doubleType = compiler.doubleClass.computeType(compiler); 429 doubleType = compiler.doubleClass.computeType(compiler);
315 boolType = compiler.boolClass.computeType(compiler); 430 boolType = compiler.boolClass.computeType(compiler);
316 stringType = compiler.stringClass.computeType(compiler); 431 stringType = compiler.stringClass.computeType(compiler);
317 objectType = compiler.objectClass.computeType(compiler); 432 objectType = compiler.objectClass.computeType(compiler);
318 listType = compiler.listClass.computeType(compiler); 433 listType = compiler.listClass.computeType(compiler);
319 } 434 }
320 435
321 Type fail(node, [reason]) { 436 Type fail(Node node, [reason]) {
322 String message = 'cannot type-check'; 437 String message = 'cannot type-check';
323 if (reason !== null) { 438 if (node != null) {
439 message = '$message ${node.getObjectDescription()} `$node`';
440 }
441 if (reason != null) {
324 message = '$message: $reason'; 442 message = '$message: $reason';
325 } 443 }
326 throw new CancelTypeCheckException(node, message); 444 throw new CancelTypeCheckException(node, message);
327 } 445 }
328 446
329 reportTypeWarning(Node node, MessageKind kind, [List arguments = const []]) { 447 reportTypeWarning(Node node, MessageKind kind, [List arguments = const []]) {
330 compiler.reportWarning(node, new TypeWarning(kind, arguments)); 448 compiler.reportWarning(node, new TypeWarning(kind, arguments));
331 } 449 }
332 450
333 // TODO(karlklose): remove these functions. 451 // TODO(karlklose): remove these functions.
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
499 } 617 }
500 } 618 }
501 if (member !== null && member.kind == ElementKind.FUNCTION) { 619 if (member !== null && member.kind == ElementKind.FUNCTION) {
502 return computeType(member); 620 return computeType(member);
503 } 621 }
504 reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND, 622 reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND,
505 [classElement.name, name]); 623 [classElement.name, name]);
506 return types.dynamicType; 624 return types.dynamicType;
507 } 625 }
508 626
627 /**
628 * Returns the interface type on which to lookup members. If [type] is the
629 * function of a getter, the return type is returned. If [type] is a type
630 * variable the bound is returned.
631 */
632 InterfaceType findReceiverType(Node receiver, Type receiverType) {
633 if (receiverType === null) {
634 fail(receiver, 'receivertype is null');
635 }
636 if (receiverType.element == compiler.dynamicClass) {
637 return receiverType;
638 }
639 ElementKind receiverKind = receiverType.element.kind;
640 if (receiverKind === ElementKind.GETTER) {
641 FunctionType getterType = receiverType;
642 return findReceiverType(receiver, getterType.returnType);
643 }
644 if (receiverKind === ElementKind.TYPEDEF) {
645 // TODO(karlklose): handle typedefs.
646 return null;
647 }
648 if (receiverKind === ElementKind.TYPE_VARIABLE) {
649 TypeVariableElement typeVariableElement = receiverType.element;
650 return findReceiverType(receiver, typeVariableElement.bound);
651 }
652 if (receiverKind !== ElementKind.CLASS) {
653 fail(receiver, 'unexpected receiver kind: ${receiverKind}');
654 }
655 return receiverType;
656 }
657
509 void analyzeArguments(Send send, FunctionType funType) { 658 void analyzeArguments(Send send, FunctionType funType) {
510 Link<Node> arguments = send.arguments; 659 Link<Node> arguments = send.arguments;
511 if (funType === null || funType === types.dynamicType) { 660 if (funType === null || funType === types.dynamicType) {
512 while(!arguments.isEmpty()) { 661 while(!arguments.isEmpty()) {
513 analyze(arguments.head); 662 analyze(arguments.head);
514 arguments = arguments.tail; 663 arguments = arguments.tail;
515 } 664 }
516 } else { 665 } else {
517 Link<Type> parameterTypes = funType.parameterTypes; 666 Link<Type> parameterTypes = funType.parameterTypes;
518 while (!arguments.isEmpty() && !parameterTypes.isEmpty()) { 667 while (!arguments.isEmpty() && !parameterTypes.isEmpty()) {
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
564 if (!arguments.isEmpty()) { 713 if (!arguments.isEmpty()) {
565 // TODO(karlklose): check number of arguments in validator. 714 // TODO(karlklose): check number of arguments in validator.
566 checkAssignable(secondArgument, boolType, secondArgumentType); 715 checkAssignable(secondArgument, boolType, secondArgumentType);
567 } 716 }
568 return boolType; 717 return boolType;
569 } 718 }
570 fail(selector, 'unexpected operator ${name}'); 719 fail(selector, 'unexpected operator ${name}');
571 720
572 } else if (node.isPropertyAccess) { 721 } else if (node.isPropertyAccess) {
573 if (node.receiver !== null) { 722 if (node.receiver !== null) {
574 // TODO(karlklose): we cannot handle fields. 723 InterfaceType receiverType =
575 return unhandledExpression(); 724 findReceiverType(node.receiver, analyze(node.receiver));
725 if (receiverType === null) return null;
726 if (receiverType.element === compiler.dynamicClass) {
727 return types.dynamicType;
728 }
729
730 Member member = receiverType.lookupMember(compiler, selector.source);
731 if (member === null ||
732 !(member.element.kind === ElementKind.FIELD ||
733 member.element.kind === ElementKind.ABSTRACT_FIELD)) {
734 reportTypeWarning(selector, MessageKind.PROPERTY_NOT_FOUND,
735 [receiverType, selector.source]);
736 } else {
737 return member.computeType(compiler);
738 }
739 return types.dynamicType;
740 } else {
741 Element element = elements[node];
742 if (element === null) {
743 return types.dynamicType;
744 }
745 if ((element.kind == ElementKind.FIELD ||
746 element.kind == ElementKind.GETTER) &&
747 element.isInstanceMember()) {
748 // Ensure substitution of declared type variables with inherited type
749 // variables.
750 InterfaceType thisType = currentClass.computeType(compiler);
751 Member member = thisType.lookupMember(compiler, selector.source);
752 if (member != null) {
753 // Should always work!
754 return member.computeType(compiler);
755 }
756 compiler.internalError('Could not lookup resolved member '
757 '${selector.source} on ${thisType}.');
758 }
759 return computeType(element);
576 } 760 }
577 Element element = elements[node];
578 if (element === null) return types.dynamicType;
579 return computeType(element);
580
581 } else if (node.isFunctionObjectInvocation) { 761 } else if (node.isFunctionObjectInvocation) {
582 fail(node.receiver, 'function object invocation unimplemented'); 762 fail(node.receiver, 'function object invocation unimplemented');
583 763
584 } else { 764 } else {
585 FunctionType computeFunType() { 765 FunctionType computeFunType() {
586 if (node.receiver !== null) { 766 if (node.receiver !== null) {
587 Type receiverType = analyze(node.receiver); 767 InterfaceType receiverType =
588 if (receiverType.element == compiler.dynamicClass) return null; 768 findReceiverType(node.receiver, analyze(node.receiver));
589 if (receiverType === null) { 769 if (receiverType === null) return null;
590 fail(node.receiver, 'receivertype is null'); 770 if (receiverType.element === compiler.dynamicClass) return null;
591 } 771
592 if (receiverType.element.kind === ElementKind.GETTER) { 772 Member member = receiverType.lookupMember(compiler, selector.source);
593 FunctionType getterType = receiverType; 773 if (member === null || member.element.kind !== ElementKind.FUNCTION) {
594 receiverType = getterType.returnType; 774 reportTypeWarning(selector, MessageKind.METHOD_NOT_FOUND,
595 } 775 [receiverType, name]);
596 ElementKind receiverKind = receiverType.element.kind;
597 if (receiverKind === ElementKind.TYPEDEF) {
598 // TODO(karlklose): handle typedefs.
599 return null; 776 return null;
600 } 777 }
601 if (receiverKind === ElementKind.TYPE_VARIABLE) { 778 Type memberType = member.computeType(compiler);
602 // TODO(karlklose): handle type variables. 779 if (memberType.element == compiler.dynamicClass) return null;
603 return null; 780 if (memberType.element == compiler.functionClass) return null;
604 }
605 if (receiverKind !== ElementKind.CLASS) {
606 fail(node.receiver, 'unexpected receiver kind: ${receiverKind}');
607 }
608 ClassElement classElement = receiverType.element;
609 // TODO(karlklose): substitute type arguments.
610 Type memberType =
611 lookupMethodType(selector, classElement, selector.source);
612 if (memberType.element === compiler.dynamicClass) return null;
613 return memberType; 781 return memberType;
614 } else { 782 } else {
615 Element element = elements[node]; 783 Element element = elements[node];
616 if (element === null) { 784 if (element === null) {
617 fail(node, 'unresolved ${node.selector}'); 785 fail(node, 'unresolved ${node.selector}');
618 } else if (element.kind === ElementKind.FUNCTION) { 786 } else if (element.kind === ElementKind.FUNCTION) {
787 if (element.isInstanceMember()) {
788 // Ensure substitution of declared type variables with inherited
789 // type variables.
790 InterfaceType thisType = currentClass.computeType(compiler);
791 Member member = thisType.lookupMember(compiler, selector.source);
792 if (member != null) {
793 // Should always work!
794 return member.computeType(compiler);
795 }
796 compiler.internalError('Could not lookup resolved member '
797 '${selector.source} on ${thisType}.');
798 }
619 return computeType(element); 799 return computeType(element);
620 } else if (element.kind === ElementKind.FOREIGN) { 800 } else if (element.kind === ElementKind.FOREIGN) {
621 return null; 801 return null;
622 } else if (element.kind === ElementKind.VARIABLE 802 } else if (element.kind === ElementKind.VARIABLE ||
623 || element.kind === ElementKind.FIELD) { 803 element.kind === ElementKind.FIELD) {
624 // TODO(karlklose): handle object invocations. 804 // TODO(karlklose): handle object invocations.
625 return null; 805 return null;
626 } else { 806 } else {
627 fail(node, 'unexpected element kind ${element.kind}'); 807 fail(node, 'unexpected element kind ${element.kind}');
628 } 808 }
629 } 809 }
630 } 810 }
631 FunctionType funType = computeFunType(); 811 FunctionType funType = computeFunType();
632 analyzeArguments(node, funType); 812 analyzeArguments(node, funType);
633 return (funType !== null) ? funType.returnType : types.dynamicType; 813 return (funType !== null) ? funType.returnType : types.dynamicType;
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
670 analyze(node.first); 850 analyze(node.first);
671 analyze(node.second); 851 analyze(node.second);
672 return stringType; 852 return stringType;
673 } 853 }
674 854
675 Type visitLiteralNull(LiteralNull node) { 855 Type visitLiteralNull(LiteralNull node) {
676 return types.dynamicType; 856 return types.dynamicType;
677 } 857 }
678 858
679 Type visitNewExpression(NewExpression node) { 859 Type visitNewExpression(NewExpression node) {
860 InterfaceType type = elements.getType(node.getTypeAnnotation());
680 Element element = elements[node.send]; 861 Element element = elements[node.send];
681 analyzeArguments(node.send, computeType(element)); 862 var member = new Member(type,
682 return analyze(node.send.selector); 863 element.enclosingElement.computeType(compiler),
864 element);
865 analyzeArguments(node.send, member.computeType(compiler));
866 return type;
683 } 867 }
684 868
685 Type visitLiteralList(LiteralList node) { 869 Type visitLiteralList(LiteralList node) {
686 return listType; 870 Type elementType = node.type != null
871 ? elements[node.type]
872 : compiler.types.dynamicType;
873 var linkBuilder = new LinkBuilder<Type>();
874 linkBuilder.addLast(elementType);
875 return new InterfaceType(listType.element, linkBuilder.toLink());
687 } 876 }
688 877
689 Type visitNodeList(NodeList node) { 878 Type visitNodeList(NodeList node) {
690 Type type = StatementType.NOT_RETURNING; 879 Type type = StatementType.NOT_RETURNING;
691 bool reportedDeadCode = false; 880 bool reportedDeadCode = false;
692 for (Link<Node> link = node.nodes; !link.isEmpty(); link = link.tail) { 881 for (Link<Node> link = node.nodes; !link.isEmpty(); link = link.tail) {
693 Type nextType = analyze(link.head); 882 Type nextType = analyze(link.head);
694 if (type == StatementType.RETURNING) { 883 if (type == StatementType.RETURNING) {
695 if (!reportedDeadCode) { 884 if (!reportedDeadCode) {
696 reportTypeWarning(link.head, MessageKind.UNREACHABLE_CODE); 885 reportTypeWarning(link.head, MessageKind.UNREACHABLE_CODE);
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
884 } 1073 }
885 1074
886 visitCatchBlock(CatchBlock node) { 1075 visitCatchBlock(CatchBlock node) {
887 return unhandledStatement(); 1076 return unhandledStatement();
888 } 1077 }
889 1078
890 visitTypedef(Typedef node) { 1079 visitTypedef(Typedef node) {
891 return unhandledStatement(); 1080 return unhandledStatement();
892 } 1081 }
893 } 1082 }
OLDNEW
« no previous file with comments | « lib/compiler/implementation/tree/nodes.dart ('k') | lib/compiler/implementation/warnings.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698