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

Side by Side Diff: compiler/java/com/google/dart/compiler/resolver/CompileTimeConstVisitor.java

Issue 8523034: Compile Time Constants cycle check (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Added new test to exercise code that was throwing ICE Created 9 years, 1 month 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
(Empty)
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
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.
4
5 package com.google.dart.compiler.resolver;
6
7 import com.google.dart.compiler.InternalCompilerException;
8 import com.google.dart.compiler.ast.DartArrayLiteral;
9 import com.google.dart.compiler.ast.DartBinaryExpression;
10 import com.google.dart.compiler.ast.DartExpression;
11 import com.google.dart.compiler.ast.DartFunction;
12 import com.google.dart.compiler.ast.DartFunctionObjectInvocation;
13 import com.google.dart.compiler.ast.DartIdentifier;
14 import com.google.dart.compiler.ast.DartInvocation;
15 import com.google.dart.compiler.ast.DartMapLiteral;
16 import com.google.dart.compiler.ast.DartMethodInvocation;
17 import com.google.dart.compiler.ast.DartNewExpression;
18 import com.google.dart.compiler.ast.DartNode;
19 import com.google.dart.compiler.ast.DartNodeTraverser;
20 import com.google.dart.compiler.ast.DartParenthesizedExpression;
21 import com.google.dart.compiler.ast.DartPropertyAccess;
22 import com.google.dart.compiler.ast.DartRedirectConstructorInvocation;
23 import com.google.dart.compiler.ast.DartStringInterpolation;
24 import com.google.dart.compiler.ast.DartSuperExpression;
25 import com.google.dart.compiler.ast.DartThisExpression;
26 import com.google.dart.compiler.ast.DartUnaryExpression;
27 import com.google.dart.compiler.ast.DartUnqualifiedInvocation;
28 import com.google.dart.compiler.type.Type;
29
30 /**
31 * Given an expression, Determines if the expression matches all the rules for a
32 * compile-time constant expression and emits a resolution error if not.
33 *
34 * This script doesn't just resolve expressions, it also sets types to the
35 * extent needed to validate compile-time constant expressions (boolean, int,
36 * double, and string types might be set)
37 *
38 */
39 public class CompileTimeConstVisitor extends DartNodeTraverser<Void> {
40
41 static CompileTimeConstVisitor create(CoreTypeProvider typeProvider, Resolutio nContext context) {
42 return new CompileTimeConstVisitor(typeProvider, context);
43 }
44
45 private final ResolutionContext context;
46
47 private final Type boolType;
48 private final Type doubleType;
49 private final Type intType;
50 private final Type numType;
51 private final Type stringType;
52 private final Type dynamicType;
53
54
55 private CompileTimeConstVisitor(CoreTypeProvider typeProvider, ResolutionConte xt context) {
56 this.context = context;
57 this.boolType = typeProvider.getBoolType();
58 this.doubleType = typeProvider.getDoubleType();
59 this.intType = typeProvider.getIntType();
60 this.numType = typeProvider.getNumType();
61 this.stringType = typeProvider.getStringType();
62 this.dynamicType = typeProvider.getDynamicType();
63 }
64
65 private boolean checkBoolean(DartNode x, Type type) {
66 if (!type.equals(boolType)) {
67 context.onError(x, ResolverErrorCode.EXPECTED_CONSTANT_EXPRESSION_BOOLEAN,
68 type.toString());
69 return false;
70 }
71 return true;
72 }
73
74 private boolean checkInt(DartNode x, Type type) {
75 if (!type.equals(intType)) {
76 context.onError(x, ResolverErrorCode.EXPECTED_CONSTANT_EXPRESSION_ INT,
77 type.toString());
78 return false;
79 }
80 return true;
81 }
82
83 private boolean checkNumber(DartNode x, Type type) {
84 if (!(type.equals(numType) || type.equals(intType) || type.equals(doubleType ))) {
85 context.onError(x, ResolverErrorCode.EXPECTED_CONSTANT_EXPRESSION_NUMBER,
86 type.toString());
87 return false;
88 }
89 return true;
90 }
91
92 private boolean checkNumberBooleanOrStringType(DartNode x, Type type) {
93 if (!type.equals(intType) && !type.equals(boolType)
94 && !type.equals(numType) && !type.equals(doubleType) && !type.equals(str ingType)) {
95 context.onError(x,
96 ResolverErrorCode.EXPECTED_CONSTANT_EXPRESSION_STRING_NUMBER_BOOL,
97 type.toString());
98 return false;
99 }
100 return true;
101 }
102
103 @Override
104 public Void visitBinaryExpression(DartBinaryExpression x) {
105 x.visitChildren(this);
106
107 DartExpression lhs = x.getArg1();
108 DartExpression rhs = x.getArg2();
109 Type lhsType = getMostSpecificType(lhs);
110 Type rhsType = getMostSpecificType(rhs);
111 lhsType.getClass(); // fast null check
112 rhsType.getClass(); // fast null check
113 switch (x.getOperator()) {
114 case NE:
115 case EQ:
116 case NE_STRICT:
117 case EQ_STRICT:
118 if (checkNumberBooleanOrStringType(lhs, lhsType)
119 && checkNumberBooleanOrStringType(rhs, rhsType)) {
120 setType(x, boolType);
121 }
122 break;
123
124 case AND:
125 case OR:
126 if (checkBoolean(lhs, lhsType) && checkBoolean(rhs, rhsType)) {
127 setType(x, boolType);
128 }
129 break;
130
131 case BIT_NOT:
132 case TRUNC:
133 case BIT_XOR:
134 case BIT_AND:
135 case BIT_OR:
136 case SAR:
137 case SHL:
138 if (checkInt(lhs, lhsType) && checkInt(rhs, rhsType)) {
139 setType(x, intType);
140 }
141 break;
142
143 case ADD:
144 case SUB:
145 case MUL:
146 case DIV:
147 case MOD:
148 if (checkNumber(lhs, lhsType) && checkNumber(rhs, rhsType)) {
149 setType(x, numType);
150 }
151 break;
152 case LT:
153 case GT:
154 case LTE:
155 case GTE:
156 if (checkNumber(lhs, lhsType) && checkNumber(rhs, rhsType)) {
157 setType(x, boolType);
158 }
159 break;
160
161 default:
162 // all other operators...
163 expectedConstant(x);
164 }
165 return null;
166 }
167
168 @Override
169 public Void visitParenthesizedExpression(DartParenthesizedExpression x) {
170 x.visitChildren(this);
171 Type type = getMostSpecificType(x.getExpression());
172 setType(x, type);
173 return null;
174 }
175
176 @Override
177 public Void visitPropertyAccess(DartPropertyAccess x) {
178 x.visitChildren(this);
179 switch (ElementKind.of(x.getQualifier().getSymbol())) {
180 case CLASS:
181 case LIBRARY:
182 case NONE:
183 // OK.
184 break;
185 default:
186 expectedConstant(x);
187 return null;
188 }
189 Element element = x.getName().getSymbol();
190 if (element != null && !element.getModifiers().isConstant()) {
191 expectedConstant(x);
192 }
193 Type type = getMostSpecificType(x.getName());
194 setType(x, type);
195 return null;
196 }
197
198 @Override
199 public Void visitRedirectConstructorInvocation(DartRedirectConstructorInvocati on x) {
200 Element element = x.getSymbol();
201 if (element != null) {
202 if (!element.getModifiers().isConstant()) {
203 expectedConstant(x);
204 }
205 }
206 x.visitChildren(this);
207 return null;
208 }
209
210 @Override
211 public Void visitStringInterpolation(DartStringInterpolation x) {
212 expectedConstant(x);
213 return null;
214 }
215
216 @Override
217 public Void visitSuperExpression(DartSuperExpression x) {
218 // No need to traverse further - super() expressions are never constant
219 expectedConstant(x);
220 return null;
221 }
222
223 @Override
224 public Void visitUnaryExpression(DartUnaryExpression x) {
225 x.visitChildren(this);
226
227 Type type = getMostSpecificType(x.getArg());
228 switch (x.getOperator()) {
229 case NOT:
230 if (checkBoolean(x, type)) {
231 x.setType(boolType);
232 }
233 break;
234 case SUB:
235 if (checkNumber(x, type)) {
236 x.setType(numType);
237 }
238 break;
239 case BIT_NOT:
240 if (checkInt(x, type)) {
241 x.setType(intType);
242 }
243 break;
244 default:
245 expectedConstant(x);
246 }
247 return null;
248 }
249
250 @Override
251 public Void visitArrayLiteral(DartArrayLiteral x) {
252 if (!x.isConst()) {
253 expectedConstant(x);
254 } else {
255 x.visitChildren(this);
256 }
257 return null;
258 }
259
260 @Override
261 public Void visitFunction(DartFunction x) {
262 // No need to traverse, functions are always disallowed.
263 expectedConstant(x);
264 return null;
265 }
266
267 @Override
268 public Void visitFunctionObjectInvocation(DartFunctionObjectInvocation x) {
269 // No need to traverse, function object invocations are always disallowed.
270 expectedConstant(x);
271 return null;
272 }
273
274 @Override
275 public Void visitIdentifier(DartIdentifier x) {
276 x.visitChildren(this);
277
278 Element element = x.getSymbol();
279 switch(ElementKind.of(element)) {
280 case CLASS:
281 case PARAMETER:
282 // OK
283 break;
284 case FIELD:
285 case CONSTRUCTOR:
286 case VARIABLE:
287 if (!element.getModifiers().isConstant()) {
288 expectedConstant(x);
289 } else {
290 setType(x, getMostSpecificType(x));
291 }
292 break;
293
294 case NONE:
295 Type type = getMostSpecificType(x);
296 if (dynamicType.equals(type)) {
297 // TODO(zundel) This is the case for unresolved identifiers that need to be recursively
298 // checked.
299 // expectedConstant(x);
300 }
301 setType(x, type);
302 break;
303 default:
304 throw new InternalCompilerException("Unexpected element " + x.toString()
305 + " kind: " + ElementKind.of(element)
306 + " evaluating type for compile-time constant expression.");
307 }
308 return null;
309 }
310
311
312 @Override
313 public Void visitInvocation(DartInvocation x) {
314 // No need to traverse, invocations are always disallowed.
315 expectedConstant(x);
316 return null;
317 }
318
319 @Override
320 public Void visitMapLiteral(DartMapLiteral x) {
321 if (!x.isConst()) {
322 expectedConstant(x);
323 } else {
324 x.visitChildren(this);
325 }
326 return null;
327 }
328
329 @Override
330 public Void visitMethodInvocation(DartMethodInvocation x) {
331 // No need to traverse, method invocations are always disallowed.
332 expectedConstant(x);
333 return null;
334 }
335
336 @Override
337 public Void visitNewExpression(DartNewExpression x) {
338 if (!x.isConst()) {
339 expectedConstant(x);
340 } else {
341 x.visitChildren(this);
342 }
343 return null;
344 }
345
346
347 @Override
348 public Void visitThisExpression(DartThisExpression x) {
349 // No need to traverse, this expressions are always disallowed.
350 expectedConstant(x);
351 return null;
352 }
353
354 @Override
355 public Void visitUnqualifiedInvocation(DartUnqualifiedInvocation x) {
356 // No need to traverse, always disallowed.
357 expectedConstant(x);
358 return null;
359 }
360
361 /**
362 * Logs a general message "expected a constant expression" error. Use a more
363 * specific error message when possible.
364 */
365 private void expectedConstant(DartNode x) {
366 context.onError(x, ResolverErrorCode.EXPECTED_CONSTANT_EXPRESSION);
367 }
368
369 /**
370 * Determine the most specific type assigned to an expression node. Prefer the
371 * setting in the expression's symbol if present. Otherwise, use a type tagged
372 * in the expression node itself.
373 *
374 * @return a non <code>null</code> type value. Dynamic if none other can be
375 * determined.
376 */
377 private Type getMostSpecificType(DartExpression expr) {
378 // TODO(zundel): this routine needs to recursively resolve as compile time c onstants any
379 // symbols that have not yet been resolved.
380 Element element = (Element)expr.getSymbol();
381 switch (ElementKind.of(element)) {
382 case FIELD:
383 return ((FieldElement)element).getType();
384 case METHOD:
385 return ((MethodElement)element).getType();
386 case VARIABLE:
387 return((VariableElement)element).getType();
388 case CONSTRUCTOR:
389 return ((ConstructorElement)element).getType();
390 case NONE:
391 if (expr.getType() != null) {
392 return expr.getType();
393 }
394 return dynamicType;
395 default:
396 throw new InternalCompilerException("Unexpected element " + expr.toStrin g()
397 + " kind: " + ElementKind.of(element )
398 + "evaluating type for compile-time constant expression.");
399 }
400 }
401
402 private void setType(DartExpression x, Type type) {
403 Element element = (Element)x.getSymbol();
404 if (element != null) {
405 Elements.setType(element, type);
406 }
407 // Also set on the expression node itself. Not every expression has a symbo l.
408 x.setType(type);
409 }
410 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698