Skip to content

Commit 31c24a8

Browse files
author
dlsmith
committed
DynamicJava: Implemented support for static final fields as constant expressions (allowing them to appear in switch statements); fixed implicit supertype of enums from raw Enum to Enum<Foo>.
git-svn-id: file:///tmp/test-svn/trunk@5074 fe72c1cf-3628-48e9-8b72-1c46755d3cff
1 parent 7d708b4 commit 31c24a8

File tree

9 files changed

+62
-10
lines changed

9 files changed

+62
-10
lines changed

dynamicjava/src/edu/rice/cs/dynamicjava/interpreter/ExpressionChecker.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,9 @@ public DJField checkEnumSwitchCase(Expression exp, Type enumT) {
241241
}
242242
addRuntimeCheck(translation, t, ref.field().type());
243243
setType(translation, t);
244-
setType(exp, t);
245244
setTranslation(exp, translation);
245+
setType(exp, t);
246+
if (hasValue(translation)) { setValue(exp, getValue(translation)); }
246247
return ref.field();
247248
}
248249
catch (UnmatchedLookupException e) {
@@ -345,6 +346,7 @@ private class ExpressionVisitor extends AbstractVisitor<Type> implements Lambda<
345346
// VARIABLE_TYPE and TYPE properties are important in the enclosing context; others
346347
// (such as FIELD) are not, and need not be copied to the AmbiguousName
347348
if (hasVariableType(resolvedExp)) { setVariableType(node, getVariableType(resolvedExp)); }
349+
if (hasValue(resolvedExp)) { setValue(node, getValue(resolvedExp)); }
348350
return setType(node, getType(resolvedExp));
349351
}
350352
}
@@ -518,6 +520,8 @@ private DJClass resolveThis(Option<String> outerName, Node node) {
518520
ref = ts.lookupField(obj, node.getFieldName(), context.accessModule());
519521
}
520522
setField(node, ref.field());
523+
Option<Object> val = ref.field().constantValue();
524+
if (val.isSome()) { setValue(node, val.unwrap()); }
521525
setVariableType(node, ref.type());
522526
if (!onlyStatic) { setDJClass(node, enclosingThis); }
523527
Type result = ts.capture(ref.type());
@@ -591,6 +595,8 @@ private DJClass resolveThis(Option<String> outerName, Node node) {
591595
try {
592596
FieldReference ref = ts.lookupStaticField(t, node.getFieldName(), context.accessModule());
593597
setField(node, ref.field());
598+
Option<Object> val = ref.field().constantValue();
599+
if (val.isSome()) { setValue(node, val.unwrap()); }
594600
setVariableType(node, ref.type());
595601
Type result = ts.capture(ref.type());
596602
addRuntimeCheck(node, result, ref.field().type());

dynamicjava/src/edu/rice/cs/dynamicjava/interpreter/TypeNameChecker.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ private class TypeNameVisitor extends AbstractVisitor<Type> implements Lambda<Ty
309309
*/
310310
@Override public Type visit(GenericReferenceTypeName node) {
311311
Iterator<? extends IdentifierToken> ids = node.getIdentifiers().iterator();
312-
Iterator<List<? extends TypeName>> allTargs = node.getTypeArguments().iterator();
312+
Iterator<? extends List<? extends TypeName>> allTargs = node.getTypeArguments().iterator();
313313
String name = "";
314314
Type t = null;
315315

dynamicjava/src/edu/rice/cs/dynamicjava/symbol/ArrayLengthField.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.lang.reflect.Array;
44
import edu.rice.cs.plt.lambda.Box;
5+
import edu.rice.cs.plt.tuple.Option;
56
import edu.rice.cs.dynamicjava.symbol.type.Type;
67

78
/** Provides a DJField interface for accessing an array's implicit "length" field. */
@@ -18,7 +19,8 @@ private ArrayLengthField() {}
1819
public boolean isStatic() { return false; }
1920
public Access accessibility() { return Access.PUBLIC; }
2021
public Access.Module accessModule() { return new TopLevelAccessModule("java.lang"); }
21-
22+
23+
public Option<Object> constantValue() { return Option.none(); }
2224
public Box<Object> boxForReceiver(final Object receiver) {
2325
return new Box<Object>() {
2426
public Object value() { return Array.getLength(receiver); }
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package edu.rice.cs.dynamicjava.symbol;
22

33
import edu.rice.cs.plt.lambda.Box;
4+
import edu.rice.cs.plt.tuple.Option;
45

56
/** Represents a field declaration. */
67
public interface DJField extends Variable, Access.Limited {
78
public boolean isStatic();
89
public Access accessibility();
10+
public Option<Object> constantValue();
911
public Box<Object> boxForReceiver(Object receiver);
1012
}

dynamicjava/src/edu/rice/cs/dynamicjava/symbol/JavaClass.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import edu.rice.cs.dynamicjava.interpreter.EvaluatorException;
1212

1313
import edu.rice.cs.plt.reflect.ReflectUtil;
14+
import edu.rice.cs.plt.tuple.Option;
1415
import edu.rice.cs.plt.iter.IterUtil;
1516
import edu.rice.cs.plt.lambda.Lambda;
1617
import edu.rice.cs.plt.lambda.Thunk;
@@ -166,6 +167,18 @@ protected class JavaField implements DJField {
166167
public Access accessibility() { return extractAccessibility(_f.getModifiers()); }
167168
public Access.Module accessModule() { return JavaClass.this.accessModule(); }
168169

170+
public Option<Object> constantValue() {
171+
// Whether a field is declared as a constant is not available via the reflection API,
172+
// so we approximate by treating all static final fields as constants.
173+
// (Note that some code my execute here during the type checking phase, before "run time".
174+
// This seems to be unavoidable given the reflection-based design.)
175+
if (isStatic() && isFinal()) {
176+
try { return Option.some(boxForReceiver(null).value()); }
177+
catch (WrappedException e) { return Option.none(); }
178+
}
179+
else { return Option.none(); }
180+
}
181+
169182
public Box<Object> boxForReceiver(final Object receiver) {
170183
return new Box<Object>() {
171184

dynamicjava/src/edu/rice/cs/dynamicjava/symbol/StandardTypeSystem.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -876,7 +876,9 @@ private boolean isNumericReference(Type t) {
876876
isSubtype(t, DOUBLE_CLASS));
877877
}
878878

879-
private boolean isBooleanReference(Type t) { return !_opt.prohibitBoxing() && isSubtype(t, BOOLEAN_CLASS); }
879+
private boolean isBooleanReference(Type t) {
880+
return !_opt.prohibitBoxing() && isSubtype(t, BOOLEAN_CLASS) && !isSubtype(t, NULL);
881+
}
880882

881883
private Pair<Expression, Expression> checkForNumericE2() {
882884
return NodeProperties.getType(e2).apply(new TypeAbstractVisitor<Pair<Expression, Expression>>() {

dynamicjava/src/edu/rice/cs/dynamicjava/symbol/TreeClass.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import edu.rice.cs.plt.lambda.Thunk;
66
import edu.rice.cs.plt.lambda.LazyThunk;
77
import edu.rice.cs.plt.lambda.Box;
8+
import edu.rice.cs.plt.tuple.Option;
89
import edu.rice.cs.plt.tuple.Pair;
910
import edu.rice.cs.plt.iter.IterUtil;
1011

@@ -317,6 +318,19 @@ public Access accessibility() {
317318
return isInterface() ? Access.PUBLIC : extractAccessibility(_f.getModifiers());
318319
}
319320
public Access.Module accessModule() { return _accessModule; }
321+
public Option<Object> constantValue() {
322+
if (isFinal() && isStatic()) {
323+
Expression init = _f.getInitializer();
324+
if (init != null) {
325+
if (NodeProperties.hasValue(init)) { return Option.some(NodeProperties.getValue(init)); }
326+
// Since hasValue depends on the order of type checking, and the current order is
327+
// naive, also allow values for literals that haven't yet been checked
328+
// (this still produces incorrect results for non-literal, not-yet-checked constant expressions)
329+
else if (init instanceof Literal) { return Option.some(((Literal) init).getValue()); }
330+
}
331+
}
332+
return Option.none();
333+
}
320334
public Box<Object> boxForReceiver(Object receiver) {
321335
return _loaded.value().boxForReceiver(receiver);
322336
}

dynamicjava/src/koala/dynamicjava/tree/EnumDeclaration.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
package koala.dynamicjava.tree;
3030

3131
import java.util.*;
32+
33+
import koala.dynamicjava.tree.tiger.GenericReferenceTypeName;
3234
import koala.dynamicjava.tree.visitor.Visitor;
3335

3436
import static koala.dynamicjava.tree.ModifierSet.Modifier.*;
@@ -90,13 +92,24 @@ public EnumDeclaration(ModifierSet mods, String name, List<? extends ReferenceTy
9092
// will return false, but since dynamicjava uses
9193
// TigerUtilities.isEnum(), this doesn't pose too big of a problem.
9294
super(mods,
93-
name, new ReferenceTypeName("java.lang.Enum"), impl,
95+
name, makeTypeName(name), impl,
9496
AddValues(name,
9597
HandleConstructors(name,
9698
makeEnumBodyDeclarationsFromEnumConsts(name, body)),
9799
body.getConstants()),
98100
si);
99101
}
102+
103+
private static ReferenceTypeName makeTypeName(String name) {
104+
List<Identifier> c = Arrays.asList(new Identifier("java"), new Identifier("lang"), new Identifier("Enum"));
105+
List<TypeName> emptyTargs = Collections.emptyList();
106+
List<ReferenceTypeName> targs = Arrays.asList(new ReferenceTypeName(name));
107+
List<List<? extends TypeName>> allTArgs = new LinkedList<List<? extends TypeName>>();
108+
allTArgs.add(emptyTargs);
109+
allTArgs.add(emptyTargs);
110+
allTArgs.add(targs);
111+
return new GenericReferenceTypeName(c, allTArgs);
112+
}
100113

101114
static List<Node> AddValues(String enumTypeName, List<Node> body, List<EnumConstant> consts){
102115
List<Node> newbody = body;

dynamicjava/src/koala/dynamicjava/tree/tiger/GenericReferenceTypeName.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,15 @@
4848

4949
public class GenericReferenceTypeName extends ReferenceTypeName {
5050

51-
private List<List<? extends TypeName>> _typeArguments;
51+
private List<? extends List<? extends TypeName>> _typeArguments;
5252

5353
/**
5454
* Initializes the type
5555
* @param ids the list of the tokens that compose the type name
5656
* @param typeArgs the type arguments
5757
* @exception IllegalArgumentException if ids is null
5858
*/
59-
public GenericReferenceTypeName(List<IdentifierToken> ids, List<List<? extends TypeName>> typeArgs) {
59+
public GenericReferenceTypeName(List<? extends IdentifierToken> ids, List<? extends List<? extends TypeName>> typeArgs) {
6060
this(ids, typeArgs, SourceInfo.NONE);
6161
}
6262

@@ -75,15 +75,15 @@ public GenericReferenceTypeName(List<IdentifierToken> ids, List<List<? extends T
7575
* @param ids the list of the tokens that compose the type name
7676
* @exception IllegalArgumentException if ids is null
7777
*/
78-
public GenericReferenceTypeName(List<IdentifierToken> ids, List<List<? extends TypeName>> typeArgs,
78+
public GenericReferenceTypeName(List<? extends IdentifierToken> ids, List<? extends List<? extends TypeName>> typeArgs,
7979
SourceInfo si) {
8080
super(ids, si);
8181
if (ids.size() != typeArgs.size()) { throw new IllegalArgumentException("ids.size() != typeArgs.size()"); }
8282
_typeArguments = typeArgs;
8383
}
8484

8585

86-
public List<List<? extends TypeName>> getTypeArguments(){ return _typeArguments; }
86+
public List<? extends List<? extends TypeName>> getTypeArguments(){ return _typeArguments; }
8787

8888
/**
8989
* Allows a visitor to traverse the tree
@@ -99,7 +99,7 @@ public String toString() {
9999

100100
public String toStringHelper() {
101101
String typeArgS = "";
102-
List<List<? extends TypeName>> alltas = getTypeArguments();
102+
List<? extends List<? extends TypeName>> alltas = getTypeArguments();
103103
for( List<? extends TypeName> ta : alltas ){
104104
if(ta.size()>0)
105105
typeArgS = ""+ta.get(0);

0 commit comments

Comments
 (0)