ConstEvaluator.java revision 2f66fb86c5de3e13b58b1a521ffc307c8cef1f50
1/*
2 * Copyright 2016 Google Inc. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.turbine.binder;
18
19import static com.google.common.base.Preconditions.checkNotNull;
20
21import com.google.common.collect.ImmutableList;
22import com.google.common.collect.ImmutableMap;
23import com.google.common.collect.Iterables;
24import com.google.turbine.binder.bound.AnnotationValue;
25import com.google.turbine.binder.bound.ClassValue;
26import com.google.turbine.binder.bound.EnumConstantValue;
27import com.google.turbine.binder.bound.SourceTypeBoundClass;
28import com.google.turbine.binder.bound.TypeBoundClass;
29import com.google.turbine.binder.bound.TypeBoundClass.FieldInfo;
30import com.google.turbine.binder.bound.TypeBoundClass.MethodInfo;
31import com.google.turbine.binder.env.CompoundEnv;
32import com.google.turbine.binder.env.Env;
33import com.google.turbine.binder.lookup.CompoundScope;
34import com.google.turbine.binder.lookup.LookupKey;
35import com.google.turbine.binder.lookup.LookupResult;
36import com.google.turbine.binder.sym.ClassSymbol;
37import com.google.turbine.binder.sym.FieldSymbol;
38import com.google.turbine.diag.TurbineError;
39import com.google.turbine.diag.TurbineError.ErrorKind;
40import com.google.turbine.model.Const;
41import com.google.turbine.model.Const.Value;
42import com.google.turbine.model.TurbineConstantTypeKind;
43import com.google.turbine.model.TurbineFlag;
44import com.google.turbine.tree.Tree;
45import com.google.turbine.tree.Tree.ArrayInit;
46import com.google.turbine.tree.Tree.Binary;
47import com.google.turbine.tree.Tree.ClassLiteral;
48import com.google.turbine.tree.Tree.ClassTy;
49import com.google.turbine.tree.Tree.Conditional;
50import com.google.turbine.tree.Tree.ConstVarName;
51import com.google.turbine.tree.Tree.Expression;
52import com.google.turbine.tree.Tree.PrimTy;
53import com.google.turbine.tree.Tree.TypeCast;
54import com.google.turbine.tree.Tree.Unary;
55import com.google.turbine.type.AnnoInfo;
56import com.google.turbine.type.Type;
57import java.util.ArrayDeque;
58import java.util.Iterator;
59import java.util.LinkedHashMap;
60import java.util.Map;
61
62/**
63 * Constant expression evaluation.
64 *
65 * <p>JLS §15.4 requires this class to be strictfp.
66 */
67public strictfp class ConstEvaluator {
68
69  /** The symbol of the enclosing class. */
70  private final ClassSymbol owner;
71
72  /** The bound node of the enclosing class. */
73  private final SourceTypeBoundClass base;
74
75  /** The constant variable environment. */
76  private final Env<FieldSymbol, Const.Value> values;
77
78  /** The class environment. */
79  private final CompoundEnv<ClassSymbol, TypeBoundClass> env;
80
81  private final CompoundScope scope;
82
83  public ConstEvaluator(
84      ClassSymbol owner,
85      SourceTypeBoundClass base,
86      CompoundScope scope,
87      Env<FieldSymbol, Const.Value> values,
88      CompoundEnv<ClassSymbol, TypeBoundClass> env) {
89
90    this.owner = owner;
91    this.base = base;
92    this.values = values;
93    this.env = env;
94    this.scope = scope;
95  }
96
97  /** Evaluates the given expression's value. */
98  public Const eval(Tree t) {
99    switch (t.kind()) {
100      case LITERAL:
101        {
102          Const.Value a = (Const.Value) ((Tree.Literal) t).value();
103          if (a == null) {
104            return null;
105          }
106          switch (a.constantTypeKind()) {
107            case CHAR:
108              return new Const.CharValue(((com.google.turbine.model.Const.CharValue) a).value());
109            case INT:
110              return new Const.IntValue(((com.google.turbine.model.Const.IntValue) a).value());
111            case LONG:
112              return new Const.LongValue(((com.google.turbine.model.Const.LongValue) a).value());
113            case FLOAT:
114              return new Const.FloatValue(((com.google.turbine.model.Const.FloatValue) a).value());
115            case DOUBLE:
116              return new Const.DoubleValue(
117                  ((com.google.turbine.model.Const.DoubleValue) a).value());
118            case BOOLEAN:
119              return new Const.BooleanValue(
120                  ((com.google.turbine.model.Const.BooleanValue) a).value());
121            case STRING:
122              return new Const.StringValue(
123                  ((com.google.turbine.model.Const.StringValue) a).value());
124            case SHORT:
125            case BYTE:
126            case NULL:
127            default:
128              throw new AssertionError(a.constantTypeKind());
129          }
130        }
131      case VOID_TY:
132        throw new AssertionError(t.kind());
133      case CONST_VAR_NAME:
134        return evalConstVar((ConstVarName) t);
135      case CLASS_LITERAL:
136        return evalClassLiteral((ClassLiteral) t);
137      case BINARY:
138        return evalBinary((Binary) t);
139      case TYPE_CAST:
140        return evalCast((TypeCast) t);
141      case UNARY:
142        return evalUnary((Unary) t);
143      case CONDITIONAL:
144        return evalConditional((Conditional) t);
145      case ARRAY_INIT:
146        return evalArrayInit((ArrayInit) t);
147      case ANNO_EXPR:
148        return evalAnno(((Tree.AnnoExpr) t).value());
149      default:
150        throw new AssertionError(t.kind());
151    }
152  }
153
154  /** Evaluates a class literal. */
155  Const evalClassLiteral(ClassLiteral t) {
156    return new ClassValue(evalClassLiteralType(t.type()));
157  }
158
159  private Type evalClassLiteralType(Tree.Type type) {
160    switch (type.kind()) {
161      case PRIM_TY:
162        return new Type.PrimTy(((PrimTy) type).tykind(), ImmutableList.of());
163      case VOID_TY:
164        return Type.VOID;
165      case CLASS_TY:
166        return Type.ClassTy.asNonParametricClassTy(resolveClass((ClassTy) type));
167      case ARR_TY:
168        return new Type.ArrayTy(
169            evalClassLiteralType(((Tree.ArrTy) type).elem()), ImmutableList.of());
170      default:
171        throw new AssertionError(type.kind());
172    }
173  }
174
175  /**
176   * Resolves the {@link ClassSymbol} for the given {@link Tree.ClassTy}, with handling for
177   * non-canonical qualified type names.
178   *
179   * <p>Similar to {@link HierarchyBinder#resolveClass}, except we can't unconditionally consider
180   * members of the current class (e.g. when binding constants inside annotations on that class),
181   * and when we do want to consider members we can rely on them being in the current scope (it
182   * isn't completed during the hierarchy phase).
183   */
184  private ClassSymbol resolveClass(ClassTy classTy) {
185    ArrayDeque<String> flat = new ArrayDeque<>();
186    for (ClassTy curr = classTy; curr != null; curr = curr.base().orNull()) {
187      flat.addFirst(curr.name());
188    }
189    LookupResult result = scope.lookup(new LookupKey(flat));
190    if (result == null) {
191      throw error(classTy.position(), ErrorKind.SYMBOL_NOT_FOUND, flat.peekFirst());
192    }
193    ClassSymbol classSym = (ClassSymbol) result.sym();
194    for (String bit : result.remaining()) {
195      classSym = Resolve.resolve(env, owner, classSym, bit);
196      if (classSym == null) {
197        throw error(classTy.position(), ErrorKind.SYMBOL_NOT_FOUND, bit);
198      }
199    }
200    return classSym;
201  }
202
203  /** Evaluates a reference to another constant variable. */
204  Const evalConstVar(ConstVarName t) {
205    FieldInfo field = resolveField(t);
206    if (field == null) {
207      return null;
208    }
209    if ((field.access() & TurbineFlag.ACC_ENUM) == TurbineFlag.ACC_ENUM) {
210      return new EnumConstantValue(field.sym());
211    }
212    if (field.value() != null) {
213      return field.value();
214    }
215    return values.get(field.sym());
216  }
217
218  FieldInfo resolveField(ConstVarName t) {
219    String simpleName = t.name().get(0);
220    FieldInfo field = lexicalField(env, owner, simpleName);
221    if (field != null) {
222      return field;
223    }
224    field = resolveQualifiedField(t);
225    if (field != null) {
226      return field;
227    }
228    ClassSymbol classSymbol = base.memberImports().singleMemberImport(simpleName);
229    if (classSymbol != null) {
230      field = Resolve.resolveField(env, owner, classSymbol, simpleName);
231      if (field != null) {
232        return field;
233      }
234    }
235    Iterator<ClassSymbol> it = base.memberImports().onDemandImports();
236    while (it.hasNext()) {
237      field = Resolve.resolveField(env, owner, it.next(), simpleName);
238      if (field == null) {
239        continue;
240      }
241      // resolve handles visibility of inherited members; on-demand imports of private members are
242      // a special case
243      if ((field.access() & TurbineFlag.ACC_PRIVATE) == TurbineFlag.ACC_PRIVATE) {
244        continue;
245      }
246      return field;
247    }
248    return null;
249  }
250
251  private FieldInfo resolveQualifiedField(ConstVarName t) {
252    if (t.name().size() <= 1) {
253      return null;
254    }
255    LookupResult result = scope.lookup(new LookupKey(t.name()));
256    if (result == null) {
257      return null;
258    }
259    ClassSymbol sym = (ClassSymbol) result.sym();
260    for (int i = 0; i < result.remaining().size() - 1; i++) {
261      sym = Resolve.resolve(env, sym, sym, result.remaining().get(i));
262      if (sym == null) {
263        return null;
264      }
265    }
266    return Resolve.resolveField(env, owner, sym, Iterables.getLast(result.remaining()));
267  }
268
269  /** Search for constant variables in lexically enclosing scopes. */
270  private FieldInfo lexicalField(
271      Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, String name) {
272    while (sym != null) {
273      TypeBoundClass info = env.get(sym);
274      FieldInfo field = Resolve.resolveField(env, owner, sym, name);
275      if (field != null) {
276        return field;
277      }
278      sym = info.owner();
279    }
280    return null;
281  }
282
283  /** Casts the value to the given type. */
284  static Const cast(Type ty, Const value) {
285    checkNotNull(value);
286    switch (ty.tyKind()) {
287      case CLASS_TY:
288      case TY_VAR:
289        return value;
290      case PRIM_TY:
291        return coerce((Const.Value) value, ((Type.PrimTy) ty).primkind());
292      default:
293        throw new AssertionError(ty.tyKind());
294    }
295  }
296
297  private static Const.Value coerce(Const.Value value, TurbineConstantTypeKind kind) {
298    switch (kind) {
299      case BOOLEAN:
300        return value.asBoolean();
301      case STRING:
302        return value.asString();
303      case LONG:
304        return value.asLong();
305      case INT:
306        return value.asInteger();
307      case BYTE:
308        return value.asByte();
309      case CHAR:
310        return value.asChar();
311      case SHORT:
312        return value.asShort();
313      case DOUBLE:
314        return value.asDouble();
315      case FLOAT:
316        return value.asFloat();
317      default:
318        throw new AssertionError(kind);
319    }
320  }
321
322  private Const.Value evalValue(Expression tree) {
323    Const result = eval(tree);
324    // TODO(cushon): consider distinguishing between constant field and annotation values,
325    // and only allowing class literals / enum constants in the latter
326    return (result instanceof Const.Value) ? (Const.Value) result : null;
327  }
328
329  private Const.Value evalConditional(Conditional t) {
330    Const.Value condition = evalValue(t.cond());
331    if (condition == null) {
332      return null;
333    }
334    return condition.asBoolean().value() ? evalValue(t.iftrue()) : evalValue(t.iffalse());
335  }
336
337  private Const.Value evalUnary(Unary t) {
338    Const.Value expr = evalValue(t.expr());
339    if (expr == null) {
340      return null;
341    }
342    switch (t.op()) {
343      case NOT:
344        return unaryNegate(expr);
345      case BITWISE_COMP:
346        return bitwiseComp(expr);
347      case UNARY_PLUS:
348        return unaryPlus(expr);
349      case NEG:
350        return unaryMinus(expr);
351      default:
352        throw new AssertionError(t.op());
353    }
354  }
355
356  private Value unaryNegate(Value expr) {
357    switch (expr.constantTypeKind()) {
358      case BOOLEAN:
359        return new Const.BooleanValue(!expr.asBoolean().value());
360      default:
361        throw new AssertionError(expr.constantTypeKind());
362    }
363  }
364
365  private Value bitwiseComp(Value expr) {
366    expr = promoteUnary(expr);
367    switch (expr.constantTypeKind()) {
368      case INT:
369        return new Const.IntValue(~expr.asInteger().value());
370      case LONG:
371        return new Const.LongValue(~expr.asLong().value());
372      default:
373        throw new AssertionError(expr.constantTypeKind());
374    }
375  }
376
377  private Value unaryPlus(Value expr) {
378    expr = promoteUnary(expr);
379    switch (expr.constantTypeKind()) {
380      case INT:
381        return new Const.IntValue(+expr.asInteger().value());
382      case LONG:
383        return new Const.LongValue(+expr.asLong().value());
384      case FLOAT:
385        return new Const.FloatValue(+expr.asFloat().value());
386      case DOUBLE:
387        return new Const.DoubleValue(+expr.asDouble().value());
388      default:
389        throw new AssertionError(expr.constantTypeKind());
390    }
391  }
392
393  private Value unaryMinus(Value expr) {
394    expr = promoteUnary(expr);
395    switch (expr.constantTypeKind()) {
396      case INT:
397        return new Const.IntValue(-expr.asInteger().value());
398      case LONG:
399        return new Const.LongValue(-expr.asLong().value());
400      case FLOAT:
401        return new Const.FloatValue(-expr.asFloat().value());
402      case DOUBLE:
403        return new Const.DoubleValue(-expr.asDouble().value());
404      default:
405        throw new AssertionError(expr.constantTypeKind());
406    }
407  }
408  private Const.Value evalCast(TypeCast t) {
409    Const.Value expr = evalValue(t.expr());
410    if (expr == null) {
411      return null;
412    }
413    switch (t.ty().kind()) {
414      case PRIM_TY:
415        return coerce(expr, ((Tree.PrimTy) t.ty()).tykind());
416      case CLASS_TY:
417        {
418          ClassTy classTy = (ClassTy) t.ty();
419          // TODO(cushon): check package?
420          if (!classTy.name().equals("String")) {
421            throw new AssertionError(classTy);
422          }
423          return expr.asString();
424        }
425      default:
426        throw new AssertionError(t.ty().kind());
427    }
428  }
429
430  static Const.Value add(Const.Value a, Const.Value b) {
431    if (a.constantTypeKind() == TurbineConstantTypeKind.STRING
432        || b.constantTypeKind() == TurbineConstantTypeKind.STRING) {
433      return new Const.StringValue(a.asString().value() + b.asString().value());
434    }
435    TurbineConstantTypeKind type = promoteBinary(a, b);
436    a = coerce(a, type);
437    b = coerce(b, type);
438    switch (type) {
439      case INT:
440        return new Const.IntValue(a.asInteger().value() + b.asInteger().value());
441      case LONG:
442        return new Const.LongValue(a.asLong().value() + b.asLong().value());
443      case FLOAT:
444        return new Const.FloatValue(a.asFloat().value() + b.asFloat().value());
445      case DOUBLE:
446        return new Const.DoubleValue(a.asDouble().value() + b.asDouble().value());
447      default:
448        throw new AssertionError(type);
449    }
450  }
451
452  static Const.Value subtract(Const.Value a, Const.Value b) {
453    TurbineConstantTypeKind type = promoteBinary(a, b);
454    a = coerce(a, type);
455    b = coerce(b, type);
456    switch (type) {
457      case INT:
458        return new Const.IntValue(a.asInteger().value() - b.asInteger().value());
459      case LONG:
460        return new Const.LongValue(a.asLong().value() - b.asLong().value());
461      case FLOAT:
462        return new Const.FloatValue(a.asFloat().value() - b.asFloat().value());
463      case DOUBLE:
464        return new Const.DoubleValue(a.asDouble().value() - b.asDouble().value());
465      default:
466        throw new AssertionError(type);
467    }
468  }
469
470  static Const.Value mult(Const.Value a, Const.Value b) {
471    TurbineConstantTypeKind type = promoteBinary(a, b);
472    a = coerce(a, type);
473    b = coerce(b, type);
474    switch (type) {
475      case INT:
476        return new Const.IntValue(a.asInteger().value() * b.asInteger().value());
477      case LONG:
478        return new Const.LongValue(a.asLong().value() * b.asLong().value());
479      case FLOAT:
480        return new Const.FloatValue(a.asFloat().value() * b.asFloat().value());
481      case DOUBLE:
482        return new Const.DoubleValue(a.asDouble().value() * b.asDouble().value());
483      default:
484        throw new AssertionError(type);
485    }
486  }
487
488  static Const.Value divide(Const.Value a, Const.Value b) {
489    TurbineConstantTypeKind type = promoteBinary(a, b);
490    a = coerce(a, type);
491    b = coerce(b, type);
492    switch (type) {
493      case INT:
494        return new Const.IntValue(a.asInteger().value() / b.asInteger().value());
495      case LONG:
496        return new Const.LongValue(a.asLong().value() / b.asLong().value());
497      case FLOAT:
498        return new Const.FloatValue(a.asFloat().value() / b.asFloat().value());
499      case DOUBLE:
500        return new Const.DoubleValue(a.asDouble().value() / b.asDouble().value());
501      default:
502        throw new AssertionError(type);
503    }
504  }
505
506  static Const.Value mod(Const.Value a, Const.Value b) {
507    TurbineConstantTypeKind type = promoteBinary(a, b);
508    a = coerce(a, type);
509    b = coerce(b, type);
510    switch (type) {
511      case INT:
512        return new Const.IntValue(a.asInteger().value() % b.asInteger().value());
513      case LONG:
514        return new Const.LongValue(a.asLong().value() % b.asLong().value());
515      case FLOAT:
516        return new Const.FloatValue(a.asFloat().value() % b.asFloat().value());
517      case DOUBLE:
518        return new Const.DoubleValue(a.asDouble().value() % b.asDouble().value());
519      default:
520        throw new AssertionError(type);
521    }
522  }
523
524  static final int INT_SHIFT_MASK = 0b11111;
525
526  static final int LONG_SHIFT_MASK = 0b111111;
527
528  static Const.Value shiftLeft(Const.Value a, Const.Value b) {
529    a = promoteUnary(a);
530    b = promoteUnary(b);
531    switch (a.constantTypeKind()) {
532      case INT:
533        return new Const.IntValue(
534            a.asInteger().value() << (b.asInteger().value() & INT_SHIFT_MASK));
535      case LONG:
536        return new Const.LongValue(a.asLong().value() << (b.asInteger().value() & LONG_SHIFT_MASK));
537      default:
538        throw new AssertionError(a.constantTypeKind());
539    }
540  }
541
542  static Const.Value shiftRight(Const.Value a, Const.Value b) {
543    a = promoteUnary(a);
544    b = promoteUnary(b);
545    switch (a.constantTypeKind()) {
546      case INT:
547        return new Const.IntValue(
548            a.asInteger().value() >> (b.asInteger().value() & INT_SHIFT_MASK));
549      case LONG:
550        return new Const.LongValue(a.asLong().value() >> (b.asInteger().value() & LONG_SHIFT_MASK));
551      default:
552        throw new AssertionError(a.constantTypeKind());
553    }
554  }
555
556  static Const.Value unsignedShiftRight(Const.Value a, Const.Value b) {
557    a = promoteUnary(a);
558    b = promoteUnary(b);
559    switch (a.constantTypeKind()) {
560      case INT:
561        return new Const.IntValue(
562            a.asInteger().value() >>> (b.asInteger().value() & INT_SHIFT_MASK));
563      case LONG:
564        return new Const.LongValue(
565            a.asLong().value() >>> (b.asInteger().value() & LONG_SHIFT_MASK));
566      default:
567        throw new AssertionError(a.constantTypeKind());
568    }
569  }
570
571  static Const.Value lessThan(Const.Value a, Const.Value b) {
572    TurbineConstantTypeKind type = promoteBinary(a, b);
573    a = coerce(a, type);
574    b = coerce(b, type);
575    switch (type) {
576      case INT:
577        return new Const.BooleanValue(a.asInteger().value() < b.asInteger().value());
578      case LONG:
579        return new Const.BooleanValue(a.asLong().value() < b.asLong().value());
580      case FLOAT:
581        return new Const.BooleanValue(a.asFloat().value() < b.asFloat().value());
582      case DOUBLE:
583        return new Const.BooleanValue(a.asDouble().value() < b.asDouble().value());
584      default:
585        throw new AssertionError(type);
586    }
587  }
588
589  static Const.Value lessThanEqual(Const.Value a, Const.Value b) {
590    TurbineConstantTypeKind type = promoteBinary(a, b);
591    a = coerce(a, type);
592    b = coerce(b, type);
593    switch (type) {
594      case INT:
595        return new Const.BooleanValue(a.asInteger().value() <= b.asInteger().value());
596      case LONG:
597        return new Const.BooleanValue(a.asLong().value() <= b.asLong().value());
598      case FLOAT:
599        return new Const.BooleanValue(a.asFloat().value() <= b.asFloat().value());
600      case DOUBLE:
601        return new Const.BooleanValue(a.asDouble().value() <= b.asDouble().value());
602      default:
603        throw new AssertionError(type);
604    }
605  }
606
607  static Const.Value greaterThan(Const.Value a, Const.Value b) {
608    TurbineConstantTypeKind type = promoteBinary(a, b);
609    a = coerce(a, type);
610    b = coerce(b, type);
611    switch (type) {
612      case INT:
613        return new Const.BooleanValue(a.asInteger().value() > b.asInteger().value());
614      case LONG:
615        return new Const.BooleanValue(a.asLong().value() > b.asLong().value());
616      case FLOAT:
617        return new Const.BooleanValue(a.asFloat().value() > b.asFloat().value());
618      case DOUBLE:
619        return new Const.BooleanValue(a.asDouble().value() > b.asDouble().value());
620      default:
621        throw new AssertionError(type);
622    }
623  }
624
625  static Const.Value greaterThanEqual(Const.Value a, Const.Value b) {
626    TurbineConstantTypeKind type = promoteBinary(a, b);
627    a = coerce(a, type);
628    b = coerce(b, type);
629    switch (type) {
630      case INT:
631        return new Const.BooleanValue(a.asInteger().value() >= b.asInteger().value());
632      case LONG:
633        return new Const.BooleanValue(a.asLong().value() >= b.asLong().value());
634      case FLOAT:
635        return new Const.BooleanValue(a.asFloat().value() >= b.asFloat().value());
636      case DOUBLE:
637        return new Const.BooleanValue(a.asDouble().value() >= b.asDouble().value());
638      default:
639        throw new AssertionError(type);
640    }
641  }
642
643  static Const.Value equal(Const.Value a, Const.Value b) {
644    switch (a.constantTypeKind()) {
645      case STRING:
646        return new Const.BooleanValue(a.asString().value().equals(b.asString().value()));
647      case BOOLEAN:
648        return new Const.BooleanValue(a.asBoolean().value() == b.asBoolean().value());
649      default:
650        break;
651    }
652    TurbineConstantTypeKind type = promoteBinary(a, b);
653    a = coerce(a, type);
654    b = coerce(b, type);
655    switch (type) {
656      case INT:
657        return new Const.BooleanValue(a.asInteger().value() == b.asInteger().value());
658      case LONG:
659        return new Const.BooleanValue(a.asLong().value() == b.asLong().value());
660      case FLOAT:
661        return new Const.BooleanValue(a.asFloat().value() == b.asFloat().value());
662      case DOUBLE:
663        return new Const.BooleanValue(a.asDouble().value() == b.asDouble().value());
664      default:
665        throw new AssertionError(type);
666    }
667  }
668
669  static Const.Value notEqual(Const.Value a, Const.Value b) {
670    switch (a.constantTypeKind()) {
671      case STRING:
672        return new Const.BooleanValue(!a.asString().value().equals(b.asString().value()));
673      case BOOLEAN:
674        return new Const.BooleanValue(a.asBoolean().value() != b.asBoolean().value());
675      default:
676        break;
677    }
678    TurbineConstantTypeKind type = promoteBinary(a, b);
679    a = coerce(a, type);
680    b = coerce(b, type);
681    switch (type) {
682      case INT:
683        return new Const.BooleanValue(a.asInteger().value() != b.asInteger().value());
684      case LONG:
685        return new Const.BooleanValue(a.asLong().value() != b.asLong().value());
686      case FLOAT:
687        return new Const.BooleanValue(a.asFloat().value() != b.asFloat().value());
688      case DOUBLE:
689        return new Const.BooleanValue(a.asDouble().value() != b.asDouble().value());
690      default:
691        throw new AssertionError(type);
692    }
693  }
694
695  static Const.Value bitwiseAnd(Const.Value a, Const.Value b) {
696    switch (a.constantTypeKind()) {
697      case BOOLEAN:
698        return new Const.BooleanValue(a.asBoolean().value() & b.asBoolean().value());
699      default:
700        break;
701    }
702    TurbineConstantTypeKind type = promoteBinary(a, b);
703    a = coerce(a, type);
704    b = coerce(b, type);
705    switch (type) {
706      case INT:
707        return new Const.IntValue(a.asInteger().value() & b.asInteger().value());
708      case LONG:
709        return new Const.LongValue(a.asLong().value() & b.asLong().value());
710      default:
711        throw new AssertionError(type);
712    }
713  }
714
715  static Const.Value bitwiseOr(Const.Value a, Const.Value b) {
716    switch (a.constantTypeKind()) {
717      case BOOLEAN:
718        return new Const.BooleanValue(a.asBoolean().value() | b.asBoolean().value());
719      default:
720        break;
721    }
722    TurbineConstantTypeKind type = promoteBinary(a, b);
723    a = coerce(a, type);
724    b = coerce(b, type);
725    switch (type) {
726      case INT:
727        return new Const.IntValue(a.asInteger().value() | b.asInteger().value());
728      case LONG:
729        return new Const.LongValue(a.asLong().value() | b.asLong().value());
730      default:
731        throw new AssertionError(type);
732    }
733  }
734
735  static Const.Value bitwiseXor(Const.Value a, Const.Value b) {
736    switch (a.constantTypeKind()) {
737      case BOOLEAN:
738        return new Const.BooleanValue(a.asBoolean().value() ^ b.asBoolean().value());
739      default:
740        break;
741    }
742    TurbineConstantTypeKind type = promoteBinary(a, b);
743    a = coerce(a, type);
744    b = coerce(b, type);
745    switch (type) {
746      case INT:
747        return new Const.IntValue(a.asInteger().value() ^ b.asInteger().value());
748      case LONG:
749        return new Const.LongValue(a.asLong().value() ^ b.asLong().value());
750      default:
751        throw new AssertionError(type);
752    }
753  }
754
755  private Const.Value evalBinary(Binary t) {
756    Const.Value lhs = evalValue(t.lhs());
757    Const.Value rhs = evalValue(t.rhs());
758    if (lhs == null || rhs == null) {
759      return null;
760    }
761    switch (t.op()) {
762      case PLUS:
763        return add(lhs, rhs);
764      case MINUS:
765        return subtract(lhs, rhs);
766      case MULT:
767        return mult(lhs, rhs);
768      case DIVIDE:
769        return divide(lhs, rhs);
770      case MODULO:
771        return mod(lhs, rhs);
772      case SHIFT_LEFT:
773        return shiftLeft(lhs, rhs);
774      case SHIFT_RIGHT:
775        return shiftRight(lhs, rhs);
776      case UNSIGNED_SHIFT_RIGHT:
777        return unsignedShiftRight(lhs, rhs);
778      case LESS_THAN:
779        return lessThan(lhs, rhs);
780      case GREATER_THAN:
781        return greaterThan(lhs, rhs);
782      case LESS_THAN_EQ:
783        return lessThanEqual(lhs, rhs);
784      case GREATER_THAN_EQ:
785        return greaterThanEqual(lhs, rhs);
786      case EQUAL:
787        return equal(lhs, rhs);
788      case NOT_EQUAL:
789        return notEqual(lhs, rhs);
790      case AND:
791        return new Const.BooleanValue(lhs.asBoolean().value() && rhs.asBoolean().value());
792      case OR:
793        return new Const.BooleanValue(lhs.asBoolean().value() || rhs.asBoolean().value());
794      case BITWISE_AND:
795        return bitwiseAnd(lhs, rhs);
796      case BITWISE_XOR:
797        return bitwiseXor(lhs, rhs);
798      case BITWISE_OR:
799        return bitwiseOr(lhs, rhs);
800      default:
801        throw new AssertionError(t.op());
802    }
803  }
804
805  private static Const.Value promoteUnary(Const.Value v) {
806    switch (v.constantTypeKind()) {
807      case CHAR:
808      case SHORT:
809      case BYTE:
810        return v.asInteger();
811      case INT:
812      case LONG:
813      case FLOAT:
814      case DOUBLE:
815        return v;
816      default:
817        throw new AssertionError(v.constantTypeKind());
818    }
819  }
820
821  private static TurbineConstantTypeKind promoteBinary(Const.Value a, Const.Value b) {
822    a = promoteUnary(a);
823    b = promoteUnary(b);
824    switch (a.constantTypeKind()) {
825      case INT:
826        switch (b.constantTypeKind()) {
827          case INT:
828          case LONG:
829          case DOUBLE:
830          case FLOAT:
831            return b.constantTypeKind();
832          default:
833            throw new AssertionError(b.constantTypeKind());
834        }
835      case LONG:
836        switch (b.constantTypeKind()) {
837          case INT:
838            return TurbineConstantTypeKind.LONG;
839          case LONG:
840          case DOUBLE:
841          case FLOAT:
842            return b.constantTypeKind();
843          default:
844            throw new AssertionError(b.constantTypeKind());
845        }
846      case FLOAT:
847        switch (b.constantTypeKind()) {
848          case INT:
849          case LONG:
850          case FLOAT:
851            return TurbineConstantTypeKind.FLOAT;
852          case DOUBLE:
853            return TurbineConstantTypeKind.DOUBLE;
854          default:
855            throw new AssertionError(b.constantTypeKind());
856        }
857      case DOUBLE:
858        switch (b.constantTypeKind()) {
859          case INT:
860          case LONG:
861          case FLOAT:
862          case DOUBLE:
863            return TurbineConstantTypeKind.DOUBLE;
864          default:
865            throw new AssertionError(b.constantTypeKind());
866        }
867      default:
868        throw new AssertionError(a.constantTypeKind());
869    }
870  }
871
872  ImmutableList<AnnoInfo> evaluateAnnotations(ImmutableList<AnnoInfo> annotations) {
873    ImmutableList.Builder<AnnoInfo> result = ImmutableList.builder();
874    for (AnnoInfo annotation : annotations) {
875      result.add(evaluateAnnotation(annotation.sym(), annotation.args()));
876    }
877    return result.build();
878  }
879
880  /**
881   * Evaluates annotation arguments given the symbol of the annotation declaration and a list of
882   * expression trees.
883   */
884  AnnoInfo evaluateAnnotation(ClassSymbol sym, ImmutableList<Expression> args) {
885    Map<String, Type> template = new LinkedHashMap<>();
886    for (MethodInfo method : env.get(sym).methods()) {
887      template.put(method.name(), method.returnType());
888    }
889
890    ImmutableMap.Builder<String, Const> values = ImmutableMap.builder();
891    for (Expression arg : args) {
892      Expression expr;
893      String key;
894      if (arg.kind() == Tree.Kind.ASSIGN) {
895        Tree.Assign assign = (Tree.Assign) arg;
896        key = assign.name();
897        expr = assign.expr();
898      } else {
899        // expand the implicit 'value' name; `@Foo(42)` is sugar for `@Foo(value=42)`
900        key = "value";
901        expr = arg;
902      }
903      Type ty = template.get(key);
904      if (ty == null) {
905        throw error(arg.position(), ErrorKind.CANNOT_RESOLVE, key);
906      }
907      Const value = evalAnnotationValue(expr, ty);
908      values.put(key, value);
909    }
910    return new AnnoInfo(sym, args, values.build());
911  }
912
913  private AnnotationValue evalAnno(Tree.Anno t) {
914    LookupResult result = scope.lookup(new LookupKey(t.name()));
915    ClassSymbol sym = (ClassSymbol) result.sym();
916    for (String name : result.remaining()) {
917      sym = Resolve.resolve(env, sym, sym, name);
918    }
919    AnnoInfo annoInfo = evaluateAnnotation(sym, t.args());
920    return new AnnotationValue(annoInfo.sym(), annoInfo.values());
921  }
922
923  private Const.ArrayInitValue evalArrayInit(ArrayInit t) {
924    ImmutableList.Builder<Const> elements = ImmutableList.builder();
925    for (Expression e : t.exprs()) {
926      Const arg = eval(e);
927      if (arg == null) {
928        return null;
929      }
930      elements.add(arg);
931    }
932    return new Const.ArrayInitValue(elements.build());
933  }
934
935  Const evalAnnotationValue(Tree tree, Type ty) {
936    if (ty == null) {
937      throw error(tree.position(), ErrorKind.EXPRESSION_ERROR);
938    }
939    Const value = eval(tree);
940    switch (ty.tyKind()) {
941      case PRIM_TY:
942        return coerce((Const.Value) value, ((Type.PrimTy) ty).primkind());
943      case CLASS_TY:
944      case TY_VAR:
945        return value;
946      case ARRAY_TY:
947        {
948          Type elementType = ((Type.ArrayTy) ty).elementType();
949          ImmutableList<Const> elements =
950              value.kind() == Const.Kind.ARRAY
951                  ? ((Const.ArrayInitValue) value).elements()
952                  : ImmutableList.of(value);
953          ImmutableList.Builder<Const> coerced = ImmutableList.builder();
954          for (Const element : elements) {
955            coerced.add(cast(elementType, element));
956          }
957          return new Const.ArrayInitValue(coerced.build());
958        }
959      default:
960        throw new AssertionError(ty.tyKind());
961    }
962  }
963
964  private TurbineError error(int position, ErrorKind kind, Object... args) {
965    return TurbineError.format(base.source(), position, kind, args);
966  }
967
968  public Const.Value evalFieldInitializer(Expression expression, Type type) {
969    Const value = eval(expression);
970    if (value == null || value.kind() != Const.Kind.PRIMITIVE) {
971      return null;
972    }
973    return (Const.Value) cast(type, value);
974  }
975}
976