Skip to content

Commit 512658e

Browse files
author
dlsmith
committed
DynamicJava: Fixed special scoping of switch constants for enum types (the constant must be an identifier naming a constant in the corresponding enum type)
git-svn-id: file:///tmp/test-svn/trunk@5072 fe72c1cf-3628-48e9-8b72-1c46755d3cff
1 parent 615ff23 commit 512658e

File tree

3 files changed

+57
-13
lines changed

3 files changed

+57
-13
lines changed

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

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,41 @@ public void checkConstructorCall(ConstructorCall node) {
215215
}
216216
}
217217

218+
/**
219+
* Check an expression appearing as the switch case in an enum switch statement.
220+
* @return The field corresponding to the enum constant's value.
221+
*/
222+
public DJField checkEnumSwitchCase(Expression exp, Type enumT) {
223+
if (!(exp instanceof AmbiguousName)) {
224+
throw new ExecutionError("invalid.enum.constant", exp);
225+
}
226+
List<IdentifierToken> ids = ((AmbiguousName) exp).getIdentifiers();
227+
if (ids.size() != 1) {
228+
throw new ExecutionError("invalid.enum.constant", exp);
229+
}
230+
String name = ids.get(0).image();
231+
Expression translation = new SimpleFieldAccess(name);
232+
try {
233+
// Should actually verify that that the name is a declared enum constant, not just
234+
// a static field. But that requires a lot of unimplemented support where we're
235+
// otherwise treating enums as syntactic sugar for normal class declarations.
236+
StaticFieldReference ref = ts.lookupStaticField(enumT, name, context.accessModule());
237+
setField(translation, ref.field());
238+
Type t = ts.capture(ref.type());
239+
if (!ts.isSubtype(t, enumT)) {
240+
throw new ExecutionError("invalid.enum.constant", exp);
241+
}
242+
addRuntimeCheck(translation, t, ref.field().type());
243+
setType(translation, t);
244+
setType(exp, t);
245+
setTranslation(exp, translation);
246+
return ref.field();
247+
}
248+
catch (UnmatchedLookupException e) {
249+
throw new ExecutionError("invalid.enum.constant", exp);
250+
}
251+
}
252+
218253
/**
219254
* Dynamically determines the appropriate error message type and initializes ERROR_STRINGS with the following:
220255
* {@code 0=type, 1=name, 2=targs, 3=args, 4=expected, 5=candidates}.
@@ -275,6 +310,12 @@ private void checkThrownExceptions(Iterable<? extends Type> thrownTypes, Node no
275310
}
276311
}
277312

313+
private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualType) {
314+
if (!ts.isSubtype(ts.erase(declaredActualType), ts.erase(expectedType))) {
315+
setCheckedType(node, ts.erasedClass(expectedType));
316+
}
317+
}
318+
278319
private String nodeTypesString(Iterable<? extends Node> nodes, TypePrinter printer) {
279320
return printer.print(IterUtil.map(nodes, NODE_TYPE));
280321
}
@@ -752,12 +793,6 @@ private DJClass resolveThis(Option<String> outerName, Node node) {
752793
}
753794
}
754795

755-
private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualType) {
756-
if (!ts.isSubtype(ts.erase(declaredActualType), ts.erase(expectedType))) {
757-
setCheckedType(node, ts.erasedClass(expectedType));
758-
}
759-
}
760-
761796
/** Visits an ArrayAllocation. JLS 15.10.
762797
* @return The type of the array
763798
*/

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

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,8 @@ else if (ts.isIterable(collType)) {
516516
*/
517517
@Override public TypeContext visit(SwitchStatement node) {
518518
Type t = checkType(node.getSelector());
519-
if (!ts.isEnum(t)) {
519+
boolean switchEnum = ts.isEnum(t);
520+
if (!switchEnum) {
520521
try {
521522
Expression exp = ts.makePrimitive(node.getSelector());
522523
if (!(getType(exp) instanceof IntegralType) || (getType(exp) instanceof LongType)) {
@@ -538,16 +539,20 @@ else if (ts.isIterable(collType)) {
538539
- A local variable is in scope for the rest of the switch statement's body -- it "falls through"
539540
- A local class is *only* in scope in its SwitchBlock -- it does not "fall through"
540541
This is a mess. For now we just follow a no-fall-through approach. */
541-
542-
bk.acceptVisitor(this);
543-
544542
if (bk.getExpression() == null) {
545543
if (hasDefault) { throw new ExecutionError("duplicate.switch.case", node); }
546544
hasDefault = true;
547545
}
548-
546+
else if (switchEnum) {
547+
DJField val = new ExpressionChecker(context, opt).checkEnumSwitchCase(bk.getExpression(), t);
548+
if (values.contains(val)) {
549+
throw new ExecutionError("duplicate.switch.case", bk);
550+
}
551+
values.add(val);
552+
}
549553
else {
550554
Expression exp = bk.getExpression();
555+
checkType(exp);
551556
if (!hasValue(exp) || getValue(exp) == null) {
552557
throw new ExecutionError("invalid.constant", exp);
553558
}
@@ -556,12 +561,14 @@ else if (ts.isIterable(collType)) {
556561
throw new ExecutionError("switch.label.type", exp);
557562
}
558563
if (values.contains(getValue(exp))) {
559-
throw new ExecutionError("duplicate.switch.case", node);
564+
throw new ExecutionError("duplicate.switch.case", bk);
560565
}
561566
values.add(getValue(exp));
562567
}
568+
569+
if (bk.getStatements() != null) { checkList(bk.getStatements()); }
563570
}
564-
571+
565572
return context;
566573
}
567574

dynamicjava/src/koala/dynamicjava/interpreter/resources/messages.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@ interface.member = Illegal interface member
235235

236236
# Used by ClassInfoCompiler, TypeChecker
237237
invalid.constant = Invalid constant
238+
239+
invalid.enum.constant = Invalid enum constant name
238240

239241
# Used by TypeChecker
240242
iterable.type = Iterated type must be an array or an Iterable

0 commit comments

Comments
 (0)