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

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

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

Powered by Google App Engine
This is Rietveld 408576698