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

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: Renamed CompileTimeConstTest to CTConst2Test 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.ast.DartArrayAccess;
9 import com.google.dart.compiler.ast.DartArrayLiteral;
10 import com.google.dart.compiler.ast.DartBinaryExpression;
11 import com.google.dart.compiler.ast.DartContext;
12 import com.google.dart.compiler.ast.DartExpression;
13 import com.google.dart.compiler.ast.DartFunction;
14 import com.google.dart.compiler.ast.DartFunctionObjectInvocation;
15 import com.google.dart.compiler.ast.DartIdentifier;
16 import com.google.dart.compiler.ast.DartIntegerLiteral;
17 import com.google.dart.compiler.ast.DartInvocation;
18 import com.google.dart.compiler.ast.DartMapLiteral;
19 import com.google.dart.compiler.ast.DartMethodInvocation;
20 import com.google.dart.compiler.ast.DartNewExpression;
21 import com.google.dart.compiler.ast.DartNode;
22 import com.google.dart.compiler.ast.DartNullLiteral;
23 import com.google.dart.compiler.ast.DartParenthesizedExpression;
24 import com.google.dart.compiler.ast.DartPropertyAccess;
25 import com.google.dart.compiler.ast.DartRedirectConstructorInvocation;
26 import com.google.dart.compiler.ast.DartStringInterpolation;
27 import com.google.dart.compiler.ast.DartStringLiteral;
28 import com.google.dart.compiler.ast.DartSuperExpression;
29 import com.google.dart.compiler.ast.DartThisExpression;
30 import com.google.dart.compiler.ast.DartUnaryExpression;
31 import com.google.dart.compiler.ast.DartUnqualifiedInvocation;
32 import com.google.dart.compiler.ast.DartVisitor;
33 import com.google.dart.compiler.type.Type;
34
35 /**
36 * Given an expression, Determines if the expression matches all the rules for a
37 * compile-time constant expression and emits a resolution error if not.
38 *
39 * This script doesn't just resolve expressions, it also sets types to the
40 * extent needed to validate compile-time constant expressions (boolean, int,
41 * double, and string types might be set)
42 *
43 */
44 public class CompileTimeConstVisitor extends DartVisitor {
ngeoffray 2011/10/14 09:26:56 Please use the DartNodeTraverser instead. I think
zundel 2011/10/14 20:59:52 Done.
45
46 static CompileTimeConstVisitor create(CoreTypeProvider typeProvider, Resolutio nContext context) {
47 return new CompileTimeConstVisitor(typeProvider, context);
48 }
49
50 private final ResolutionContext context;
51
52 private final Type boolType;
53 private final Type doubleType;
54 private final Type intType;
55 private final Type numType;
56 private final Type stringType;
57 private final Type dynamicType;
58
59
60 private CompileTimeConstVisitor(CoreTypeProvider typeProvider, ResolutionConte xt context) {
61 this.context = context;
62 this.boolType = typeProvider.getBoolType();
63 this.doubleType = typeProvider.getDoubleType();
64 this.intType = typeProvider.getIntType();
65 this.numType = typeProvider.getNumType();
66 this.stringType = typeProvider.getStringType();
67 this.dynamicType = typeProvider.getDynamicType();
68 }
69
70 private boolean checkBoolean(DartNode x, Type type) {
71 if (!type.equals(boolType)) {
72 context.resolutionError(x, DartCompilerErrorCode.EXPECTED_CONSTANT_EXPRESS ION_BOOLEAN,
73 type.toString());
74 return false;
75 }
76 return true;
77 }
78
79 private boolean checkInt(DartNode x, Type type) {
80 if (!type.equals(intType)) {
81 context.resolutionError(x, DartCompilerErrorCode.EXPECTED_CONSTANT_EXPRESS ION_INT,
82 type.toString());
83 return false;
84 }
85 return true;
86 }
87
88 private boolean checkNumber(DartNode x, Type type) {
89 if (!(type.equals(numType) || type.equals(intType) || type.equals(doubleType ))) {
90 context.resolutionError(x, DartCompilerErrorCode.EXPECTED_CONSTANT_EXPRESS ION_NUMBER,
91 type.toString());
92 return false;
93 }
94 return true;
95 }
96
97 private boolean checkNumberBooleanOrStringType(DartNode x, Type type) {
98 if (!type.equals(intType) && !type.equals(boolType)
99 && !type.equals(numType) && !type.equals(doubleType) && !type.equals(str ingType)) {
100 context.resolutionError(x,
101 DartCompilerErrorCode.EXPECTED_CONSTANT_EXPRESSION_STRING_NUMBER_BOOL,
102 type.toString());
103 return false;
104 }
105 return true;
106 }
107
108 @Override
109 public void endVisit(DartBinaryExpression x, DartContext ctx) {
110 DartExpression lhs = x.getArg1();
111 DartExpression rhs = x.getArg2();
112 Type lhsType = getMostSpecificType(lhs);
113 Type rhsType = getMostSpecificType(rhs);
114 lhsType.getClass(); // fast null check
115 rhsType.getClass(); // fast null check
ngeoffray 2011/10/14 09:26:56 you're doing the null checks and then checking for
zundel 2011/10/14 20:59:52 Done.
116 boolean isConst = true;
ngeoffray 2011/10/14 09:26:56 No need for this variable if lhsType and rhsType c
zundel 2011/10/14 20:59:52 Done.
117 if (lhsType == null || rhsType == null) {
118 isConst = false;
119 }
120 if (isConst) {
121 switch (x.getOperator()) {
122 case NE:
123 case EQ:
124 case NE_STRICT:
125 case EQ_STRICT:
126 if (checkNumberBooleanOrStringType(lhs, lhsType) &&
ngeoffray 2011/10/14 09:26:56 Nit: && should be on a newline, right below check.
zundel 2011/10/14 20:59:52 Done.
127 checkNumberBooleanOrStringType(rhs, rhsType)) {
128 setType(x, boolType);
129 }
130 break;
131
132 case AND:
133 case OR:
134 if (checkBoolean(lhs, lhsType)
135 && checkBoolean(rhs, rhsType)) {
ngeoffray 2011/10/14 09:26:56 weird indentation.
zundel 2011/10/14 20:59:52 Done.
136 setType(x, boolType);
137 }
138 break;
139
140 case BIT_NOT:
141 case TRUNC:
142 case BIT_XOR:
143 case BIT_AND:
144 case BIT_OR:
145 case SAR:
146 case SHL:
147 if (checkInt(lhs, lhsType) &&
148 checkInt(rhs, rhsType)) {
149 setType(x, intType);
150 }
ngeoffray 2011/10/14 09:26:56 ditto.
zundel 2011/10/14 20:59:52 Done.
151 break;
152
153 case ADD:
154 case SUB:
155 case MUL:
156 case DIV:
157 case MOD:
158 if (checkNumber(lhs, lhsType) && checkNumber(rhs, rhsType)) {
159 setType(x, numType);
160 }
161 break;
162 case LT:
163 case GT:
164 case LTE:
165 case GTE:
166 if (checkNumber(lhs, lhsType) && checkNumber(rhs, rhsType)) {
167 setType(x, boolType);
168 }
169 break;
170
171 default:
172 // all other operators...
173 expectedConstant(x);
174 }
175 }
176 }
177
178 @Override
179 public void endVisit(DartParenthesizedExpression x, DartContext ctx) {
180 Type type = getMostSpecificType(x.getExpression());
181 setType(x, type);
182 }
183
184 @Override
185 public void endVisit(DartPropertyAccess x, DartContext ctx) {
floitsch 2011/10/14 14:36:58 Does this make sure that PropertyAccess only goes
zundel 2011/10/14 20:59:52 Done.
186 Element element = x.getName().getSymbol();
187 if (element != null && !element.getModifiers().isConstant()) {
188 expectedConstant(x);
189 }
190 Type type = getMostSpecificType(x.getName());
191 setType(x, type);
192 }
193
194 @Override
195 public boolean visit(DartRedirectConstructorInvocation x, DartContext ctx) {
196 if (!x.getSymbol().getModifiers().isConstant()) {
197 expectedConstant(x);
198 }
199 return true;
200 }
201
202 @Override
203 public boolean visit(DartStringInterpolation x, DartContext ctx) {
204 expectedConstant(x);
205 return false;
206 }
207
208 @Override
209 public boolean visit(DartStringLiteral x, DartContext ctx) {
210 return false;
floitsch 2011/10/14 14:36:58 I'm not really familiar with the visitor, but why
zundel 2011/10/14 20:59:52 returns false to stop traversing children. I swit
211 }
212
213 @Override
214 public boolean visit(DartSuperExpression x, DartContext ctx) {
215 expectedConstant(x);
216 return false;
217 }
218
219 @Override
220 public void endVisit(DartUnaryExpression x, DartContext ctx) {
221 Type type = getMostSpecificType(x.getArg());
222 switch (x.getOperator()) {
223 case NOT:
224 if (checkBoolean(x, type)) {
225 x.setType(boolType);
226 }
227 break;
228 case SUB:
229 if (checkNumber(x, type)) {
230 x.setType(numType);
231 }
232 break;
233 case BIT_NOT:
234 if (checkInt(x, type)) {
235 x.setType(intType);
236 }
237 break;
238 default:
239 expectedConstant(x);
240 }
241 }
242
243
244 private void expectedConstant(DartNode x) {
245 context.resolutionError(x, DartCompilerErrorCode.EXPECTED_CONSTANT_EXPRESSIO N);
246 }
247
248 /**
249 * Determine the most specific type assigned to an expression node. Prefer the
250 * setting in the expression's symbol if present. Otherwise, use a type tagged
251 * in the expression node itself.
252 *
253 * @return a non <code>null</code> type value. Dynamic if none other can be
254 * determined.
255 */
256 private Type getMostSpecificType(DartExpression expr) {
257 Element element = (Element)expr.getSymbol();
258 switch (ElementKind.of(element)) {
259 case FIELD:
260 return ((FieldElement)element).getType();
261 case METHOD:
262 return ((MethodElement)element).getType();
263 case VARIABLE:
264 return((VariableElement)element).getType();
265 }
ngeoffray 2011/10/14 09:26:56 Maybe inline the following code into a 'default' c
zundel 2011/10/14 20:59:52 Done.
266
267 if (expr.getType() != null) {
268 return expr.getType();
269 }
270
271 return dynamicType;
272 }
273
274 private void setType(DartExpression x, Type type) {
275 Element element = (Element)x.getSymbol();
276 if (element != null) {
277 Elements.setType(element, type);
278 }
279 // Also set on the expression node itself. Not every expression has a symbo l.
280 x.setType(type);
281 }
282
283 @Override
284 public boolean visit(DartArrayAccess x, DartContext ctx) {
285 // TODO(zundel): remove me if there is nothing to do
286 return true;
287 }
288
289 @Override
290 public boolean visit(DartArrayLiteral x, DartContext ctx) {
291 if (!x.isConst()) {
292 expectedConstant(x);
293 }
294 return true;
295 }
296
297 @Override
298 public boolean visit(DartFunction x, DartContext ctx) {
299 expectedConstant(x);
300 return true;
301 }
302
303 @Override
304 public boolean visit(DartFunctionObjectInvocation x, DartContext ctx) {
305 expectedConstant(x);
306 return false;
307 }
308
309 @Override
310 public boolean visit(DartIdentifier x, DartContext ctx) {
311 Element element = x.getSymbol();
312 switch(ElementKind.of(element)) {
313 case FIELD:
314 case CONSTRUCTOR:
315 case VARIABLE:
316 case PARAMETER:
317 if (!element.getModifiers().isConstant()) {
318 expectedConstant(x);
319 } else {
320 setType(x, getMostSpecificType(x));
321 }
322 break;
323 default:
324 }
325 return true;
326 }
327
328 @Override
329 public boolean visit(DartIntegerLiteral x, DartContext ctx) {
330 return false;
331 }
332
333 @Override
334 public boolean visit(DartInvocation x, DartContext ctx) {
335 expectedConstant(x);
336 return false; // No need to check further
337 }
338
339 @Override
340 public boolean visit(DartMapLiteral x, DartContext ctx) {
341 if (!x.isConst()) {
342 expectedConstant(x);
343 }
344 return true;
345 }
346
347 @Override
348 public boolean visit(DartMethodInvocation x, DartContext ctx) {
349 expectedConstant(x);
350 return false;
351 }
352
353 @Override
354 public boolean visit(DartNewExpression x, DartContext ctx) {
355 boolean isConst = false;
356 Element element = x.getSymbol();
357 switch (ElementKind.of(element)) {
ngeoffray 2011/10/14 09:26:56 Please add a comment that factory methods cannot b
zundel 2011/10/14 20:59:52 I'm keying off of the 'const' reserved word now, s
358 case CONSTRUCTOR:
359 ConstructorElement constructorElement = (ConstructorElement) element;
360 if (constructorElement.getModifiers().isConstant()) {
361 isConst = true;
362 }
363 break;
364 }
365 if (!isConst) {
366 expectedConstant(x);
367 }
368 return true;
369 }
370
371 @Override
372 public boolean visit(DartNullLiteral x, DartContext ctx) {
373 return true;
374 }
375
376 @Override
377 public boolean visit(DartThisExpression x, DartContext ctx) {
378 expectedConstant(x);
379 return true;
380 }
381
382 @Override
383 public boolean visit(DartUnqualifiedInvocation x, DartContext ctx) {
384 expectedConstant(x);
385 return false;
386 }
387 }
388
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698