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

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: Feedback from floitsch 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> {
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);
ngeoffray 2011/10/17 10:59:38 Do you really need to visit children here?
zundel 2011/10/17 14:14:26 a qualifier is a part of a PropertyAccess and is t
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 Element element = x.getSymbol();
202 if (element != null) {
203 if (!element.getModifiers().isConstant()) {
204 expectedConstant(x);
205 }
206 }
207 x.visitChildren(this);
208 return null;
209 }
210
211 @Override
212 public Void visitStringInterpolation(DartStringInterpolation x) {
213 expectedConstant(x);
214 return null;
215 }
216
217 @Override
218 public Void visitSuperExpression(DartSuperExpression x) {
219 // No need to traverse further - super() expressions are never constant
220 expectedConstant(x);
221 return null;
222 }
223
224 @Override
225 public Void visitUnaryExpression(DartUnaryExpression x) {
226 x.visitChildren(this);
227
228 Type type = getMostSpecificType(x.getArg());
229 switch (x.getOperator()) {
230 case NOT:
231 if (checkBoolean(x, type)) {
232 x.setType(boolType);
233 }
234 break;
235 case SUB:
236 if (checkNumber(x, type)) {
237 x.setType(numType);
238 }
239 break;
240 case BIT_NOT:
241 if (checkInt(x, type)) {
242 x.setType(intType);
243 }
244 break;
245 default:
246 expectedConstant(x);
247 }
248 return null;
249 }
250
251 @Override
252 public Void visitArrayLiteral(DartArrayLiteral x) {
253 if (!x.isConst()) {
254 expectedConstant(x);
255 } else {
256 x.visitChildren(this);
257 }
258 return null;
259 }
260
261 @Override
262 public Void visitFunction(DartFunction x) {
263 // No need to traverse, functions are always disallowed.
264 expectedConstant(x);
265 return null;
266 }
267
268 @Override
269 public Void visitFunctionObjectInvocation(DartFunctionObjectInvocation x) {
270 // No need to traverse, function object invocations are always disallowed.
271 expectedConstant(x);
272 return null;
273 }
274
275 @Override
276 public Void visitIdentifier(DartIdentifier x) {
277 x.visitChildren(this);
278
279 Element element = x.getSymbol();
280 switch(ElementKind.of(element)) {
281 case FIELD:
282 case CONSTRUCTOR:
283 case VARIABLE:
284 case PARAMETER:
ngeoffray 2011/10/17 10:59:38 It looks like this will say a library prefix or a
zundel 2011/10/17 14:14:26 Added kind CLASS and an ICE for the cases not expl
285 if (!element.getModifiers().isConstant()) {
286 expectedConstant(x);
287 } else {
288 setType(x, getMostSpecificType(x));
289 }
290 break;
291 }
292 return null;
293 }
294
295
296 @Override
297 public Void visitInvocation(DartInvocation x) {
298 // No need to traverse, invocations are always disallowed.
299 expectedConstant(x);
300 return null;
301 }
302
303 @Override
304 public Void visitMapLiteral(DartMapLiteral x) {
305 if (!x.isConst()) {
306 expectedConstant(x);
307 } else {
308 x.visitChildren(this);
309 }
310 return null;
311 }
312
313 @Override
314 public Void visitMethodInvocation(DartMethodInvocation x) {
315 // No need to traverse, method invocations are always disallowed.
316 expectedConstant(x);
317 return null;
318 }
319
320 @Override
321 public Void visitNewExpression(DartNewExpression x) {
322 if (!x.isConst()) {
323 expectedConstant(x);
324 } else {
325 x.visitChildren(this);
326 }
327 return null;
328 }
329
330
331 @Override
332 public Void visitThisExpression(DartThisExpression x) {
333 // No need to traverse, this expressions are always disallowed.
334 expectedConstant(x);
335 return null;
336 }
337
338 @Override
339 public Void visitUnqualifiedInvocation(DartUnqualifiedInvocation x) {
340 // No need to traverse, always disallowed.
341 expectedConstant(x);
342 return null;
343 }
344
345 /**
346 * Logs a general message "expected a constant expression" error. Use a more
347 * specific error message when possible.
348 */
349 private void expectedConstant(DartNode x) {
350 context.resolutionError(x, DartCompilerErrorCode.EXPECTED_CONSTANT_EXPRESSIO N);
351 }
352
353 /**
354 * Determine the most specific type assigned to an expression node. Prefer the
355 * setting in the expression's symbol if present. Otherwise, use a type tagged
356 * in the expression node itself.
357 *
358 * @return a non <code>null</code> type value. Dynamic if none other can be
359 * determined.
360 */
361 private Type getMostSpecificType(DartExpression expr) {
362 // TODO(zundel): this routine needs to recursively resolve as compile time c onstants any
363 // symbols that have not yet been resolved.
364 Element element = (Element)expr.getSymbol();
365 switch (ElementKind.of(element)) {
366 case FIELD:
367 return ((FieldElement)element).getType();
368 case METHOD:
369 return ((MethodElement)element).getType();
370 case VARIABLE:
371 return((VariableElement)element).getType();
372 case CONSTRUCTOR:
373 return ((ConstructorElement)element).getType();
374 case NONE:
375 if (expr.getType() != null) {
376 return expr.getType();
377 }
378 return dynamicType;
379 default:
380 throw new InternalCompilerException("Unhandled element " + expr.toString ()
381 + " kind: " + ElementKind.of(element ));
382 }
383 }
384
385 private void setType(DartExpression x, Type type) {
386 Element element = (Element)x.getSymbol();
387 if (element != null) {
388 Elements.setType(element, type);
389 }
390 // Also set on the expression node itself. Not every expression has a symbo l.
391 x.setType(type);
392 }
393 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698