Skip to content

Commit d00e0fe

Browse files
author
dlsmith
committed
DynamicJava:
- Revised member lookup, fixing correctness problems in method lookup and making everything a lot more readable. - Implemented implicit inner constructor calls ("new Inner()", which is interpreted as "Outer.this.new Inner()"). - Fixed name lookup bug (internal exception) when inside of anonymous classes. - Improved error messages when a lookup result is ambiguous. - Fixed a bug in the TreeCompiler's handling of inner classes appearing in generic signatures. - Changed format of capture variables appearing in error messages ("?T1" instead of "?1"). git-svn-id: file:///tmp/test-svn/trunk@5032 fe72c1cf-3628-48e9-8b72-1c46755d3cff
1 parent c49bfac commit d00e0fe

19 files changed

Lines changed: 1111 additions & 1267 deletions

dynamicjava/lib/plt.jar

348 Bytes
Binary file not shown.

dynamicjava/lib/readme.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ buildlib/*.jar: Binaries used in the build process, but that should not be part
66
VERSIONS:
77

88
asm-3.1.jar: ASM 3.1 (http://asm.objectweb.org)
9-
plt.jar: plt-20090731-r4961
9+
plt.jar: plt-20090824-r5028
1010

1111
buildlib/ant-contrib.jar: ANT Contrib 1.0b3
1212
buildlib/astgen.jar: Built 2009-03-26

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ private boolean hasMethod(String name, TypeSystem ts) {
132132
* if there is no such value (for example, in a static context).
133133
*/
134134
@Override public DJClass getThis(String className) {
135-
if (className.equals(_c.declaredName())) { return _c; }
135+
if (!_c.isAnonymous() && className.equals(_c.declaredName())) { return _c; }
136136
else { return super.getThis(className); }
137137
}
138138

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

Lines changed: 73 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@
114114
* non-static {@code SimpleMethodCall}s and {@code SimpleFieldAccess}es.</li>
115115
* <li>CONSTRUCTOR on {@code ConstructorCall}s and all allocations: {@code SimpleAllocation}s,
116116
* {@code InnerAllocation}s, {@code AnonymousAllocation}s, and {@code AnonymousInnerAllocation}s</li>
117+
* <li>ENCLOSING_THIS on {@code SimpleAllocation}s and {@code AnonymousAllocations}s that represent
118+
* inner allocations with a "this" value of the given class as the enclosing object</li>
117119
* <li>FIELD on all {@code FieldAccess}es</li>
118120
* <li>METHOD on all {@code MethodCall}s</li>
119121
* <li>VARIABLE on all {@code VariableAccess}es, {@code VariableDeclarations}, and {@code FormalParameters}</li>
@@ -204,9 +206,10 @@ public void checkConstructorCall(ConstructorCall node) {
204206
catch (InvalidTypeArgumentException e) {
205207
throw new ExecutionError("type.argument", node);
206208
}
207-
catch (TypeSystemException e) {
209+
catch (UnmatchedLookupException e) {
208210
setErrorStrings(node, ts.userRepresentation(type), nodeTypesString(args));
209-
throw new ExecutionError("no.such.constructor", node);
211+
if (e.matches() > 1) { throw new ExecutionError("ambiguous.constructor", node); }
212+
else { throw new ExecutionError("no.such.constructor", node); }
210213
}
211214
}
212215

@@ -217,7 +220,7 @@ public void checkAccessibility(Access.Limited symbol, Node node) {
217220

218221
/**
219222
* Verify that the given symbol is accessible. If {@code alwaysCheckPrivate}, private access is
220-
* checked even when the options dictate otherwise.
223+
* checked even when the options dictate otherwise. Assumes symbol is not an anonymous class.
221224
*/
222225
private void checkAccessibility(Access.Limited symbol, Node node, boolean alwaysCheckPrivate) {
223226
switch (symbol.accessibility()) {
@@ -352,7 +355,6 @@ else if (context.fieldExists(first.image(), ts)) {
352355
}
353356
}
354357
catch (AmbiguousNameException e) { throw new ExecutionError("ambiguous.name", node); }
355-
catch (InvalidTargetException e) { throw new RuntimeException("context produced bad type"); }
356358
catch (InvalidTypeArgumentException e) { throw new ExecutionError("type.argument.arity", node); }
357359
catch (UnmatchedLookupException e) {
358360
if (e.matches() == 0) { throw new ExecutionError("undefined.name.noinfo", node); }
@@ -375,7 +377,6 @@ else if (ts.containsClass(classType, memberName.image())) {
375377
checkAccessibility(memberType.ofClass(), node);
376378
classType = memberType;
377379
}
378-
catch (InvalidTargetException e) { throw new RuntimeException("ts.containsClass lied"); }
379380
catch (InvalidTypeArgumentException e) { throw new ExecutionError("type.argument.arity", node); }
380381
catch (UnmatchedLookupException e) {
381382
if (e.matches() == 0) { throw new ExecutionError("undefined.name.noinfo", node); }
@@ -482,7 +483,6 @@ private DJClass resolveThis(Option<String> outerName, Node node) {
482483
return setType(node, result);
483484
}
484485
catch (AmbiguousNameException e) { throw new ExecutionError("ambiguous.name", node); }
485-
catch (InvalidTargetException e) { throw new RuntimeException("context produced bad type"); }
486486
catch (UnmatchedLookupException e) {
487487
if (e.matches() == 0) { throw new ExecutionError("undefined.name.noinfo", node); }
488488
else { throw new ExecutionError("ambiguous.name", node); }
@@ -506,9 +506,10 @@ private DJClass resolveThis(Option<String> outerName, Node node) {
506506
addRuntimeCheck(node, result, ref.field().type());
507507
return setType(node, result);
508508
}
509-
catch (TypeSystemException e) {
509+
catch (UnmatchedLookupException e) {
510510
setErrorStrings(node, ts.userRepresentation(receiverT), node.getFieldName());
511-
throw new ExecutionError("no.such.field", node);
511+
if (e.matches() > 1) { throw new ExecutionError("ambiguous.field", node); }
512+
else { throw new ExecutionError("no.such.field", node); }
512513
}
513514
}
514515

@@ -534,9 +535,10 @@ private DJClass resolveThis(Option<String> outerName, Node node) {
534535
addRuntimeCheck(node, result, ref.field().type());
535536
return setType(node, result);
536537
}
537-
catch (TypeSystemException e) {
538+
catch (UnmatchedLookupException e) {
538539
setErrorStrings(node, ts.userRepresentation(t), node.getFieldName());
539-
throw new ExecutionError("no.such.field", node);
540+
if (e.matches() > 1) { throw new ExecutionError("ambiguous.field", node); }
541+
else { throw new ExecutionError("no.such.field", node); }
540542
}
541543
}
542544

@@ -555,9 +557,10 @@ private DJClass resolveThis(Option<String> outerName, Node node) {
555557
addRuntimeCheck(node, result, ref.field().type());
556558
return setType(node, result);
557559
}
558-
catch (TypeSystemException e) {
560+
catch (UnmatchedLookupException e) {
559561
setErrorStrings(node, ts.userRepresentation(t), node.getFieldName());
560-
throw new ExecutionError("no.such.static.field", node);
562+
if (e.matches() > 1) { throw new ExecutionError("ambiguous.field", node); }
563+
else { throw new ExecutionError("no.such.static.field", node); }
561564
}
562565
}
563566

@@ -612,9 +615,10 @@ private DJClass resolveThis(Option<String> outerName, Node node) {
612615
catch (InvalidTypeArgumentException e) {
613616
throw new ExecutionError("type.argument", node);
614617
}
615-
catch (TypeSystemException e) {
618+
catch (UnmatchedLookupException e) {
616619
setErrorStrings(node, ts.userRepresentation(t), node.getMethodName(), nodeTypesString(args));
617-
throw new ExecutionError("no.such.method", node);
620+
if (e.matches() > 1) { throw new ExecutionError("ambiguous.method", node); }
621+
else { throw new ExecutionError("no.such.method", node); }
618622
}
619623
}
620624

@@ -672,9 +676,10 @@ private DJClass resolveThis(Option<String> outerName, Node node) {
672676
catch (InvalidTypeArgumentException e) {
673677
throw new ExecutionError("type.argument", node);
674678
}
675-
catch (TypeSystemException e) {
679+
catch (UnmatchedLookupException e) {
676680
setErrorStrings(node, ts.userRepresentation(receiverT), node.getMethodName(), nodeTypesString(args));
677-
throw new ExecutionError("no.such.method", node);
681+
if (e.matches() > 1) { throw new ExecutionError("ambiguous.method", node); }
682+
else { throw new ExecutionError("no.such.method", node); }
678683
}
679684
}
680685

@@ -714,9 +719,10 @@ private DJClass resolveThis(Option<String> outerName, Node node) {
714719
catch (InvalidTypeArgumentException e) {
715720
throw new ExecutionError("type.argument", node);
716721
}
717-
catch (TypeSystemException e) {
722+
catch (UnmatchedLookupException e) {
718723
setErrorStrings(node, ts.userRepresentation(t), node.getMethodName(), nodeTypesString(args));
719-
throw new ExecutionError("no.such.method", node);
724+
if (e.matches() > 1) { throw new ExecutionError("ambiguous.method", node); }
725+
else { throw new ExecutionError("no.such.method", node); }
720726
}
721727
}
722728

@@ -750,9 +756,10 @@ private DJClass resolveThis(Option<String> outerName, Node node) {
750756
catch (InvalidTypeArgumentException e) {
751757
throw new ExecutionError("type.argument", node);
752758
}
753-
catch (TypeSystemException e) {
759+
catch (UnmatchedLookupException e) {
754760
setErrorStrings(node, ts.userRepresentation(t), node.getMethodName(), nodeTypesString(args));
755-
throw new ExecutionError("no.such.static.method", node);
761+
if (e.matches() > 1) { throw new ExecutionError("ambiguous.method", node); }
762+
else { throw new ExecutionError("no.such.method", node); }
756763
}
757764
}
758765

@@ -835,10 +842,13 @@ private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualTy
835842
*/
836843
@Override public Type visit(SimpleAllocation node) {
837844
Type t = checkTypeName(node.getCreationType());
838-
// TODO: Allow a simple allocation of a dynamic inner class defined in the current context
839-
// (where "new Inner()" is the equivalent of "this.new Inner()" or "SomeOuter.this.new Inner()")
840-
if (!ts.isConcrete(t) || !ts.isStatic(t)) {
841-
throw new ExecutionError("allocation.type", node);
845+
if (!ts.isConcrete(t)) { throw new ExecutionError("allocation.type", node); }
846+
847+
Option<Type> dynamicOuter = ts.dynamicallyEnclosingType(t);
848+
if (dynamicOuter.isSome()) {
849+
DJClass enclosingThis = enclosingThis(dynamicOuter.unwrap());
850+
if (enclosingThis == null) { throw new ExecutionError("allocation.type", node); }
851+
else { setEnclosingThis(node, enclosingThis); }
842852
}
843853

844854
Iterable<? extends Expression> args = node.getArguments();
@@ -860,9 +870,10 @@ private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualTy
860870
catch (InvalidTypeArgumentException e) {
861871
throw new ExecutionError("type.argument", node);
862872
}
863-
catch (TypeSystemException e) {
873+
catch (UnmatchedLookupException e) {
864874
setErrorStrings(node, ts.userRepresentation(t), nodeTypesString(args));
865-
throw new ExecutionError("no.such.constructor", node);
875+
if (e.matches() > 1) { throw new ExecutionError("ambiguous.constructor", node); }
876+
else { throw new ExecutionError("no.such.constructor", node); }
866877
}
867878
}
868879

@@ -872,11 +883,17 @@ private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualTy
872883
*/
873884
@Override public Type visit(AnonymousAllocation node) {
874885
Type t = checkTypeName(node.getCreationType());
875-
// TODO: Allow a simple allocation of a dynamic inner class defined in the current context (as above)
876-
if (!ts.isStatic(t) || (!ts.isExtendable(t) && !ts.isImplementable(t))) {
886+
if (!ts.isExtendable(t) && !ts.isImplementable(t)) {
877887
throw new ExecutionError("allocation.type", node);
878888
}
879889

890+
Option<Type> dynamicOuter = ts.dynamicallyEnclosingType(t);
891+
if (dynamicOuter.isSome()) {
892+
DJClass enclosingThis = enclosingThis(dynamicOuter.unwrap());
893+
if (enclosingThis == null) { throw new ExecutionError("allocation.type", node); }
894+
else { setEnclosingThis(node, enclosingThis); }
895+
}
896+
880897
Iterable<? extends Expression> args = node.getArguments();
881898
checkList(args);
882899

@@ -896,9 +913,10 @@ private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualTy
896913
catch (InvalidTypeArgumentException e) {
897914
throw new ExecutionError("type.argument", node);
898915
}
899-
catch (TypeSystemException e) {
916+
catch (UnmatchedLookupException e) {
900917
setErrorStrings(node, ts.userRepresentation(t), nodeTypesString(args));
901-
throw new ExecutionError("no.such.constructor", node);
918+
if (e.matches() > 1) { throw new ExecutionError("ambiguous.constructor", node); }
919+
else { throw new ExecutionError("no.such.constructor", node); }
902920
}
903921
}
904922

@@ -914,6 +932,19 @@ private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualTy
914932
return setType(node, ts.makeClassType(c));
915933
}
916934

935+
/**
936+
* Determine the innermost "this" class that can be used as an allocation's enclosing object
937+
* where the given type is expected. May return {@code null} if none is found.
938+
*/
939+
private DJClass enclosingThis(Type expected) {
940+
DJClass candidate = context.getThis();
941+
while (candidate != null) {
942+
if (ts.isSubtype(SymbolUtil.thisType(candidate), expected)) { return candidate; }
943+
candidate = SymbolUtil.dynamicOuterClass(candidate);
944+
}
945+
return null;
946+
}
947+
917948
/**
918949
* Visits a InnerAllocation. JLS 15.9.
919950
* @return The type of the expression
@@ -956,17 +987,19 @@ private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualTy
956987
catch (InvalidTypeArgumentException e) {
957988
throw new ExecutionError("type.argument", node);
958989
}
959-
catch (TypeSystemException e) {
990+
catch (UnmatchedLookupException e) {
960991
setErrorStrings(node, ts.userRepresentation(t), nodeTypesString(args));
961-
throw new ExecutionError("no.such.constructor", node);
992+
if (e.matches() > 1) { throw new ExecutionError("ambiguous.constructor", node); }
993+
else { throw new ExecutionError("no.such.constructor", node); }
962994
}
963995
}
964996
catch (InvalidTypeArgumentException e) {
965997
throw new ExecutionError("type.argument", node);
966998
}
967-
catch (TypeSystemException e) {
999+
catch (UnmatchedLookupException e) {
9681000
setErrorStrings(node, ts.userRepresentation(enclosing), node.getClassName());
969-
throw new ExecutionError("no.such.inner.class", node);
1001+
if (e.matches() > 1) { throw new ExecutionError("ambiguous.inner.class", node); }
1002+
else { throw new ExecutionError("no.such.inner.class", node); }
9701003
}
9711004
}
9721005

@@ -1011,17 +1044,19 @@ private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualTy
10111044
catch (InvalidTypeArgumentException e) {
10121045
throw new ExecutionError("type.argument", node);
10131046
}
1014-
catch (TypeSystemException e) {
1047+
catch (UnmatchedLookupException e) {
10151048
setErrorStrings(node, ts.userRepresentation(t), nodeTypesString(args));
1016-
throw new ExecutionError("no.such.constructor", node);
1049+
if (e.matches() > 1) { throw new ExecutionError("ambiguous.constructor", node); }
1050+
else { throw new ExecutionError("no.such.constructor", node); }
10171051
}
10181052
}
10191053
catch (InvalidTypeArgumentException e) {
10201054
throw new ExecutionError("type.argument", node);
10211055
}
1022-
catch (TypeSystemException e) {
1056+
catch (UnmatchedLookupException e) {
10231057
setErrorStrings(node, ts.userRepresentation(enclosing), node.getClassName());
1024-
throw new ExecutionError("no.such.inner.class", node);
1058+
if (e.matches() > 1) { throw new ExecutionError("ambiguous.inner.class", node); }
1059+
else { throw new ExecutionError("no.such.inner.class", node); }
10251060
}
10261061

10271062
TreeClassLoader loader = new TreeClassLoader(context.getClassLoader(), opt);

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,12 @@ private Object handleMethodCall(MethodCall node, Object receiver) {
114114
* @param args May be null, meaning there are no arguments
115115
*/
116116
private Object handleConstructor(Expression node, Expression outer, Iterable<Expression> args) {
117-
Object outerVal = (outer == null) ? null : value(outer);
117+
Object outerVal;
118+
if (outer == null) {
119+
if (hasEnclosingThis(node)) { outerVal = _bindings.getThis(getEnclosingThis(node)); }
120+
else { outerVal = null; }
121+
}
122+
else { outerVal = value(outer); }
118123

119124
Iterable<Object> argVals;
120125
if (args == null) { argVals = IterUtil.empty(); }

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ protected LocalContext duplicate(TypeContext next) {
6363

6464
private DJClass declaredClass(String name) {
6565
for (DJClass c : _classes) {
66-
if (c.declaredName().equals(name)) { return c; }
66+
if (!c.isAnonymous() && c.declaredName().equals(name)) { return c; }
6767
}
6868
return null;
6969
}

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -244,14 +244,11 @@ private ClassType resolveClassName(String name, Node node) {
244244
}
245245
else {
246246
try { result = ts.lookupClass(result, piece, IterUtil.<Type>empty()); }
247-
catch (InvalidTargetException e) { throw new RuntimeException("unexpected bad type"); }
248247
catch (InvalidTypeArgumentException e) { throw new RuntimeException("can't create raw type"); }
249248
catch (UnmatchedLookupException e) {
250-
if (ts.containsClass(result, piece)) { throw new ExecutionError("ambiguous.name", node); }
251-
else {
252-
setErrorStrings(node, piece);
253-
throw new ExecutionError("undefined.class", node);
254-
}
249+
setErrorStrings(node, piece);
250+
if (e.matches() > 1) { throw new ExecutionError("ambiguous.inner.class"); }
251+
else { throw new ExecutionError("no.such.inner.class", node); }
255252
}
256253
}
257254
}

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,10 +1018,10 @@ private void generateUnboxingCode(int size, String className, String methodName,
10181018

10191019
/* AUXILIARY STATIC METHODS */
10201020

1021-
private static String typeSignature(Type t) { return encodeType(t, '.'); }
1021+
private static String typeSignature(Type t) { return encodeType(t); }
10221022

10231023
/** Nonstatic because it depends on field _opt. */
1024-
private String typeDescriptor(Type t) { return encodeType(_opt.typeSystem().erase(t), '$'); }
1024+
private String typeDescriptor(Type t) { return encodeType(_opt.typeSystem().erase(t)); }
10251025

10261026
private static String className(DJClass c) { return c.fullName().replace('.', '/'); }
10271027

@@ -1085,7 +1085,7 @@ private String paramListDescriptor(String prefix, Iterable<LocalVariable> params
10851085
}
10861086

10871087
/** Abstraction of typeDescriptor and typeSignature. */
1088-
private static String encodeType(Type t, final char classDelim) {
1088+
private static String encodeType(Type t) {
10891089
final StringBuilder result = new StringBuilder();
10901090
t.apply(new TypeAbstractVisitor_void() {
10911091
@Override public void forBooleanType(BooleanType t) { result.append('Z'); }
@@ -1104,25 +1104,27 @@ private static String encodeType(Type t, final char classDelim) {
11041104
boolean first = true;
11051105
for (DJClass c : SymbolUtil.outerClassChain(t.ofClass())) {
11061106
if (first) { result.append(className(c)); first = false; }
1107-
else { result.append(classDelim).append(c.declaredName()); }
1107+
else { result.append('$').append(c.declaredName()); }
11081108
}
11091109
result.append(';');
11101110
}
11111111

11121112
@Override public void forParameterizedClassType(ParameterizedClassType t) {
11131113
result.append('L');
1114-
boolean first = true;
1114+
Character classDelim = null;
11151115
Iterator<? extends Type> args = t.typeArguments().iterator();
11161116
DJClass tClass = t.ofClass();
11171117
for (DJClass c : SymbolUtil.outerClassChain(tClass)) {
1118-
if (first) { result.append(className(c)); first = false; }
1118+
if (classDelim == null) { result.append(className(c)); }
11191119
else { result.append(classDelim).append(c.declaredName()); }
1120+
classDelim = '$';
11201121
if (SymbolUtil.dynamicallyEncloses(c, tClass)) {
11211122
Iterable<VariableType> params = c.declaredTypeParameters();
11221123
if (!IterUtil.isEmpty(params)) {
11231124
result.append('<');
11241125
for (VariableType param : params) { args.next().apply(this); }
11251126
result.append('>');
1127+
classDelim = '.';
11261128
}
11271129
}
11281130
}

0 commit comments

Comments
 (0)