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

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

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

Powered by Google App Engine
This is Rietveld 408576698