Handle primitive and void class literals
MOE_MIGRATED_REVID=136373334
diff --git a/java/com/google/turbine/binder/ConstEvaluator.java b/java/com/google/turbine/binder/ConstEvaluator.java
index 11b4b98..76c1c6a 100644
--- a/java/com/google/turbine/binder/ConstEvaluator.java
+++ b/java/com/google/turbine/binder/ConstEvaluator.java
@@ -40,10 +40,12 @@
import com.google.turbine.tree.Tree;
import com.google.turbine.tree.Tree.ArrayInit;
import com.google.turbine.tree.Tree.Binary;
+import com.google.turbine.tree.Tree.ClassLiteral;
import com.google.turbine.tree.Tree.ClassTy;
import com.google.turbine.tree.Tree.Conditional;
import com.google.turbine.tree.Tree.ConstVarName;
import com.google.turbine.tree.Tree.Expression;
+import com.google.turbine.tree.Tree.PrimTy;
import com.google.turbine.tree.Tree.TypeCast;
import com.google.turbine.tree.Tree.Unary;
import com.google.turbine.type.Type;
@@ -115,6 +117,8 @@
throw new AssertionError(t.kind());
case CONST_VAR_NAME:
return evalConstVar((ConstVarName) t);
+ case CLASS_LITERAL:
+ return evalClassLiteral((ClassLiteral) t);
case BINARY:
return evalBinary((Binary) t);
case TYPE_CAST:
@@ -132,7 +136,27 @@
}
}
- /** Evaluate a reference to another constant variable. */
+ /** Evaluates a class literal. */
+ // TODO(cushon): consider distinguishing between constant field and annotation values,
+ // and only allowing class literals / enum constants in the latter
+ Const evalClassLiteral(ClassLiteral t) {
+ switch (t.type().kind()) {
+ case PRIM_TY:
+ return new Const.ClassValue(new Type.PrimTy(((PrimTy) t.type()).tykind()));
+ case VOID_TY:
+ return new Const.ClassValue(Type.VOID);
+ case CLASS_TY:
+ {
+ ClassTy classTy = (ClassTy) t.type();
+ ClassSymbol classSym = HierarchyBinder.resolveClass(env, owner.scope(), sym, classTy);
+ return new Const.ClassValue(Type.ClassTy.asNonParametricClassTy(classSym));
+ }
+ default:
+ throw new AssertionError(t.type().kind());
+ }
+ }
+
+ /** Evaluates a reference to another constant variable. */
Const evalConstVar(ConstVarName t) {
LookupResult result = owner.scope().lookup(new LookupKey(t.name()));
if (result != null) {
@@ -160,11 +184,6 @@
sym = Resolve.resolve(env, sym, result.remaining().get(i));
}
String name = result.remaining().get(result.remaining().size() - 1);
- if (name.equals("class")) {
- // TODO(cushon): consider distinguishing between constant field and annotation values,
- // and only allowing class literals / enum constants in the latter
- return new Const.ClassValue(sym.toString());
- }
FieldInfo field = inheritedField(env, sym, name);
if ((field.access() & TurbineFlag.ACC_ENUM) == TurbineFlag.ACC_ENUM) {
return new Const.EnumConstantValue(field.sym());
diff --git a/java/com/google/turbine/lower/Lower.java b/java/com/google/turbine/lower/Lower.java
index 00adbb9..ef6cdf7 100644
--- a/java/com/google/turbine/lower/Lower.java
+++ b/java/com/google/turbine/lower/Lower.java
@@ -352,7 +352,7 @@
}
}
- private static ImmutableMap<String, ElementValue> annotationValues(
+ private ImmutableMap<String, ElementValue> annotationValues(
ImmutableMap<String, Const> values, Env<ClassSymbol, TypeBoundClass> env) {
ImmutableMap.Builder<String, ElementValue> result = ImmutableMap.builder();
for (Map.Entry<String, Const> entry : values.entrySet()) {
@@ -361,12 +361,12 @@
return result.build();
}
- private static ElementValue annotationValue(Const value, Env<ClassSymbol, TypeBoundClass> env) {
+ private ElementValue annotationValue(Const value, Env<ClassSymbol, TypeBoundClass> env) {
switch (value.kind()) {
case CLASS_LITERAL:
{
Const.ClassValue classValue = (Const.ClassValue) value;
- return new ElementValue.ConstClassValue("L" + classValue.className() + ";");
+ return new ElementValue.ConstClassValue(SigWriter.type(sig.signature(classValue.type())));
}
case ENUM_CONSTANT:
{
diff --git a/java/com/google/turbine/model/Const.java b/java/com/google/turbine/model/Const.java
index e207c79..946b724 100644
--- a/java/com/google/turbine/model/Const.java
+++ b/java/com/google/turbine/model/Const.java
@@ -20,6 +20,7 @@
import com.google.common.collect.ImmutableMap;
import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.binder.sym.FieldSymbol;
+import com.google.turbine.type.Type;
/**
* Compile-time constant expressions, including literals of primitive or String type, class
@@ -626,15 +627,15 @@
/** A class literal constant. */
public static class ClassValue extends Const {
- private final String className;
+ private final Type type;
- public ClassValue(String className) {
- this.className = className;
+ public ClassValue(Type type) {
+ this.type = type;
}
@Override
public String toString() {
- return String.format("%s.class", className);
+ return String.format("%s.class", type);
}
@Override
@@ -643,8 +644,8 @@
}
/** The class name. */
- public String className() {
- return className;
+ public Type type() {
+ return type;
}
}
diff --git a/java/com/google/turbine/parse/ConstExpressionParser.java b/java/com/google/turbine/parse/ConstExpressionParser.java
index 7407e8d..aa08bfc 100644
--- a/java/com/google/turbine/parse/ConstExpressionParser.java
+++ b/java/com/google/turbine/parse/ConstExpressionParser.java
@@ -24,6 +24,10 @@
import com.google.turbine.model.Const;
import com.google.turbine.model.TurbineConstantTypeKind;
import com.google.turbine.tree.Tree;
+import com.google.turbine.tree.Tree.ClassLiteral;
+import com.google.turbine.tree.Tree.ClassTy;
+import com.google.turbine.tree.Tree.Expression;
+import com.google.turbine.tree.Tree.VoidTy;
import com.google.turbine.tree.TurbineOperatorKind;
import javax.annotation.Nullable;
@@ -127,6 +131,24 @@
return arrayInitializer();
case IDENT:
return qualIdent();
+ case BYTE:
+ return primitiveClassLiteral(TurbineConstantTypeKind.BYTE);
+ case CHAR:
+ return primitiveClassLiteral(TurbineConstantTypeKind.CHAR);
+ case DOUBLE:
+ return primitiveClassLiteral(TurbineConstantTypeKind.DOUBLE);
+ case FLOAT:
+ return primitiveClassLiteral(TurbineConstantTypeKind.FLOAT);
+ case INT:
+ return primitiveClassLiteral(TurbineConstantTypeKind.INT);
+ case LONG:
+ return primitiveClassLiteral(TurbineConstantTypeKind.LONG);
+ case SHORT:
+ return primitiveClassLiteral(TurbineConstantTypeKind.SHORT);
+ case BOOLEAN:
+ return primitiveClassLiteral(TurbineConstantTypeKind.BOOLEAN);
+ case VOID:
+ return primitiveClassLiteral(VoidTy.INSTANCE);
case AT:
return annotation();
default:
@@ -134,6 +156,23 @@
}
}
+ private Expression primitiveClassLiteral(TurbineConstantTypeKind type) {
+ return primitiveClassLiteral(new Tree.PrimTy(type));
+ }
+
+ private Expression primitiveClassLiteral(Tree.Type type) {
+ eat();
+ if (token != Token.DOT) {
+ return null;
+ }
+ eat();
+ if (token != Token.CLASS) {
+ return null;
+ }
+ eat();
+ return new ClassLiteral(type);
+ }
+
private Tree.Expression maybeCast() {
eat();
switch (token) {
@@ -188,12 +227,7 @@
case TILDE:
case IDENT:
{
- Tree.ClassTy cty = null;
- for (String bit : cvar.name()) {
- cty =
- new Tree.ClassTy(Optional.fromNullable(cty), bit, ImmutableList.<Tree.Type>of());
- }
- return new Tree.TypeCast(cty, primary(false));
+ return new Tree.TypeCast(asClassTy(cvar.name()), primary(false));
}
default:
return expr;
@@ -203,6 +237,14 @@
}
}
+ private ClassTy asClassTy(ImmutableList<String> names) {
+ ClassTy cty = null;
+ for (String bit : names) {
+ cty = new ClassTy(Optional.fromNullable(cty), bit, ImmutableList.<Tree.Type>of());
+ }
+ return cty;
+ }
+
private void eat() {
token = lexer.next();
}
@@ -373,8 +415,8 @@
break;
case CLASS:
// TODO(cushon): only allow in annotations?
- bits.add("class");
- break;
+ eat();
+ return new Tree.ClassLiteral(asClassTy(bits.build()));
default:
return null;
}
diff --git a/java/com/google/turbine/tree/Pretty.java b/java/com/google/turbine/tree/Pretty.java
index 8e62718..8fa3f63 100644
--- a/java/com/google/turbine/tree/Pretty.java
+++ b/java/com/google/turbine/tree/Pretty.java
@@ -19,6 +19,7 @@
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
+import com.google.turbine.tree.Tree.ClassLiteral;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -179,6 +180,13 @@
}
@Override
+ public Void visitClassLiteral(ClassLiteral classLiteral, Void input) {
+ classLiteral.accept(this, input);
+ append(".class");
+ return null;
+ }
+
+ @Override
public Void visitAssign(Tree.Assign assign, Void input) {
append(assign.name()).append(" = ");
assign.expr().accept(this, null);
diff --git a/java/com/google/turbine/tree/Tree.java b/java/com/google/turbine/tree/Tree.java
index b4bd669..9ee02b6 100644
--- a/java/com/google/turbine/tree/Tree.java
+++ b/java/com/google/turbine/tree/Tree.java
@@ -47,6 +47,7 @@
UNARY,
BINARY,
CONST_VAR_NAME,
+ CLASS_LITERAL,
ASSIGN,
CONDITIONAL,
ARRAY_INIT,
@@ -371,6 +372,30 @@
}
}
+ /** A JLS 15.8.2 class literal. */
+ public static class ClassLiteral extends Expression {
+
+ private final Type type;
+
+ public ClassLiteral(Type type) {
+ this.type = type;
+ }
+
+ @Override
+ public Kind kind() {
+ return Kind.CLASS_LITERAL;
+ }
+
+ @Override
+ public <I, O> O accept(Visitor<I, O> visitor, I input) {
+ return visitor.visitClassLiteral(this, input);
+ }
+
+ public Type type() {
+ return type;
+ }
+ }
+
/** A JLS 15.26 assignment expression. */
public static class Assign extends Expression {
private final String name;
@@ -861,6 +886,8 @@
O visitConstVarName(ConstVarName constVarName, I input);
+ O visitClassLiteral(ClassLiteral classLiteral, I input);
+
O visitAssign(Assign assign, I input);
O visitConditional(Conditional conditional, I input);
diff --git a/javatests/com/google/turbine/lower/LowerIntegrationTest.java b/javatests/com/google/turbine/lower/LowerIntegrationTest.java
index c6378b6..4080c1d 100644
--- a/javatests/com/google/turbine/lower/LowerIntegrationTest.java
+++ b/javatests/com/google/turbine/lower/LowerIntegrationTest.java
@@ -212,6 +212,7 @@
"hex_int.test",
"const_conv.test",
"bmethod.test",
+ "prim_class.test",
};
List<Object[]> tests =
ImmutableList.copyOf(testCases).stream().map(x -> new Object[] {x}).collect(toList());
diff --git a/javatests/com/google/turbine/lower/testdata/prim_class.test b/javatests/com/google/turbine/lower/testdata/prim_class.test
new file mode 100644
index 0000000..c4f51f6
--- /dev/null
+++ b/javatests/com/google/turbine/lower/testdata/prim_class.test
@@ -0,0 +1,25 @@
+=== Anno.java ===
+@interface Anno {
+ Class<?> value() default Anno.class;
+}
+
+=== Annos.java ===
+@interface Annos {
+ Anno[] value() default {};
+}
+
+=== Test.java ===
+class Test {
+ @Annos({
+ @Anno(byte.class),
+ @Anno(char.class),
+ @Anno(double.class),
+ @Anno(float.class),
+ @Anno(int.class),
+ @Anno(long.class),
+ @Anno(short.class),
+ @Anno(boolean.class),
+ @Anno(void.class),
+ })
+ int x;
+}