Skip to content

Commit

Permalink
SI-6168 Retain prefix when parsing types in JVM signatures
Browse files Browse the repository at this point in the history
When reading Java classfiles, the generic signatures are
used to construct the corresponding Scala type signatures.

In the enclosed test case, the field `SomeClass.f` had
the JVM signature:

    LContext<LSomeClass;>.Field<Ljava.lang.Integer;>;

The parser first (correctly) parsed the prefix as `Context[SomeClass]`.
It then looked up the type symbol for `Field` in that that type. It then
discarded the parsed prefix, and instead used the prefix from the
info of the type symbol: `Context[ParentType]`.

This commit changes the signature parser after the first `.` to
use the result of prior parsing as the prefix.

I've also included a test case with Java static inner classes,
which don't require any special treatment.
  • Loading branch information
retronym committed Mar 25, 2013
1 parent 1187c98 commit edee27f
Show file tree
Hide file tree
Showing 10 changed files with 149 additions and 1 deletion.
Expand Up @@ -607,6 +607,8 @@ abstract class ClassfileParser {
val sym = getOwner(jflags).newValue(name.toTermName, NoPosition, sflags)
val isEnum = (jflags & JAVA_ACC_ENUM) != 0

// Note: the info may be overrwritten later with a generic signature
// parsed from SignatureATTR
sym setInfo {
if (isEnum) ConstantType(Constant(sym))
else info
Expand Down Expand Up @@ -661,6 +663,8 @@ abstract class ClassfileParser {
}
info = MethodType(newParams, clazz.tpe)
}
// Note: the info may be overrwritten later with a generic signature
// parsed from SignatureATTR
sym.setInfo(info)
importPrivateWithinFromJavaFlags(sym, jflags)
parseAttributes(sym, info)
Expand Down Expand Up @@ -754,7 +758,9 @@ abstract class ClassfileParser {
accept('.')
val name = subName(c => c == ';' || c == '<' || c == '.').toTypeName
val clazz = tpe.member(name)
tpe = processClassType(processInner(clazz.tpe))
val dummyArgs = Nil // the actual arguments are added in processClassType
val inner = typeRef(pre = tpe, sym = clazz, args = dummyArgs)
tpe = processClassType(inner)
}
accept(';')
tpe
Expand Down
34 changes: 34 additions & 0 deletions test/files/run/t6168/Context.java
@@ -0,0 +1,34 @@
public class Context<ParentType> {
private ParentType parent;

public Context() {}

public ParentType getParent() {
return parent;
}

public void setParent(ParentType parent) {
this.parent = parent;
}

public Field<Integer> intField() {
return new Field<Integer>() {
@Override
public Integer get() {
return 0;
}

@Override
public ParentType set(Integer t) {
return parent;
}
};
}

public abstract class Field<T> { //Note this is a path dependent type

public abstract T get();

public abstract ParentType set(T t);
}
}
8 changes: 8 additions & 0 deletions test/files/run/t6168/JavaTest.java
@@ -0,0 +1,8 @@
public class JavaTest {
public static void main(String[] args) {
SomeClass a = new SomeClass();
SomeClass2 a2 = new SomeClass2();
SomeClass b = a.f.set(23).f.set(23);
SomeClass2 b2 = a2.f.set(23).f.set(23);
}
}
14 changes: 14 additions & 0 deletions test/files/run/t6168/SomeClass.java
@@ -0,0 +1,14 @@
public class SomeClass {
private final Context<SomeClass> context = new Context<SomeClass>();
{
context.setParent(this);
}

public final Context<SomeClass>.Field<Integer> f = context.intField();

public SomeClass() {
f.set(23).f.set(23);
}
}


12 changes: 12 additions & 0 deletions test/files/run/t6168/SomeClass2.java
@@ -0,0 +1,12 @@
public class SomeClass2 {
private final Context<SomeClass2> context = new Context<SomeClass2>();
{
context.setParent(this);
}

public final Context<SomeClass2>.Field<Integer> f = context.intField();

public SomeClass2() {
f.set(23).f.set(23);
}
}
15 changes: 15 additions & 0 deletions test/files/run/t6168/main.scala
@@ -0,0 +1,15 @@


object Test extends App {
JavaTest.main(null)

var a1 : SomeClass = new SomeClass
var a2 : SomeClass2 = new SomeClass2
//import language.implicitConversions
//implicit def setParentType2SomeClass(x:Any) = x.asInstanceOf[SomeClass]
//implicit def setParentType2SomeClass2(x:Any) = x.asInstanceOf[SomeClass2]
//var b : SomeClass = a.f.set(23).asInstanceOf[SomeClass].f.set(23).asInstanceOf[SomeClass]
//var b2 : SomeClass2 = a2.f.set(23).asInstanceOf[SomeClass2].f.set(23).asInstanceOf[SomeClass2]
var b1 : SomeClass = a1.f.set(23).f.set(23)
var b2 : SomeClass2 = a2.f.set(23).f.set(23)
}
34 changes: 34 additions & 0 deletions test/files/run/t6168b/Context.java
@@ -0,0 +1,34 @@
public class Context<ParentType> {
private ParentType parent;

public Context() {}

public ParentType getParent() {
return parent;
}

public void setParent(ParentType parent) {
this.parent = parent;
}

public Field<Integer> intField() {
return new Field<Integer>() {
@Override
public Integer get() {
return 0;
}

@Override
public ParentType set(Integer t) {
return parent;
}
};
}

public static abstract class Field<T> {

public abstract T get();

public abstract Object set(T t);
}
}
6 changes: 6 additions & 0 deletions test/files/run/t6168b/JavaTest.java
@@ -0,0 +1,6 @@
public class JavaTest {
public static void main(String[] args) {
SomeClass a = new SomeClass();
Object b = a.f.set(23);
}
}
11 changes: 11 additions & 0 deletions test/files/run/t6168b/SomeClass.java
@@ -0,0 +1,11 @@
public class SomeClass {
private final Context<SomeClass> context = new Context<SomeClass>();
{
context.setParent(this);
}

public final Context.Field<Integer> f = context.intField();

}


8 changes: 8 additions & 0 deletions test/files/run/t6168b/main.scala
@@ -0,0 +1,8 @@


object Test extends App {
JavaTest.main(null)

var a1 : SomeClass = new SomeClass
var b1 : Object = a1.f.set(23)
}

0 comments on commit edee27f

Please sign in to comment.