Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@throws annotation synthesized for class files compiled from Java is broken #7009

Closed
scabug opened this issue Jan 23, 2013 · 6 comments
Closed
Assignees
Labels
Milestone

Comments

@scabug
Copy link

scabug commented Jan 23, 2013

Power REPL shows the problem. See below for comments.

scala
Welcome to Scala version 2.10.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_37).
Type in expressions to have them evaluated.
Type :help for more information.

scala> :power
** Power User mode enabled - BEEP WHIR GYVE **
** :phase has been set to 'typer'.          **
** scala.tools.nsc._ has been imported      **
** global._, definitions._ also imported    **
** Try  :help, :vals, power.<tab>           **

scala> val methodClass = rootMirror.getClassByName(newTermName("java.lang.reflect.Method"))
methodClass: $r.intp.global.ClassSymbol = class Method

scala> val invokeSymbol = methodClass.info.member(newTermName("invoke"))
invokeSymbol: $r.intp.global.Symbol = method invoke

scala> val throwsAnn = invokeSymbol.annotations.head
throwsAnn: $r.intp.global.AnnotationInfo = throws(classOf[java.lang.reflect.InvocationTargetException])

scala> throwsAnn.atp.typeParams
res0: List[$r.intp.global.Symbol] = List(type T)

As you can see, we get higher-kinded (unapplied) type for annotation. This is broken and I believe it caused by PR-1347 which introduced type parameter for scala.throws annotation but forgot to change parseExceptions in ClassfileParser.scala.

This might be related to spurious API changes in sbt's incremental compiler reported here:
sbt/sbt#642 (comment)

@scabug
Copy link
Author

scabug commented Jan 23, 2013

Imported From: https://issues.scala-lang.org/browse/SI-7009?orig=1
Reporter: @gkossakowski
Affected Versions: 2.10.0

@scabug
Copy link
Author

scabug commented Jan 24, 2013

@gkossakowski said:
scala/scala#1961

@scabug
Copy link
Author

scabug commented Jan 25, 2013

@gkossakowski said:
Paul pointed out my pull request that in Scala we allow polymorphic exceptions. This is not being handled properly by ClassfileParser probably with an assumption that since we are parsing exception declarations emitted by Java we'll never get polymorphic exceptions there. That assumption is wrong if you mix Scala and Java. The trick is to define polymorphic exception in Scala. Then declare it in throws declaration in Java class. See the following transcript:

rm -rf classes/*
Grzegorzs-MacBook-Pro:scala-throws grek$ cat Foo.scala
package test

class Foo[T] extends Exception
Grzegorzs-MacBook-Pro:scala-throws grek$ scalac Foo.scala -d classes/
Grzegorzs-MacBook-Pro:scala-throws grek$ cat Xyz.java 
package test;

public class Xyz {
	public void abc() throws Foo {}
}
Grzegorzs-MacBook-Pro:scala-throws grek$ 

Grzegorzs-MacBook-Pro:scala-throws grek$ javac -cp /usr/local/Cellar/scala/2.10.0/libexec/lib/scala-library.jar:classes/ -d classes/ Xyz.java
Grzegorzs-MacBook-Pro:scala-throws grek$ scala -classpath classes/
Welcome to Scala version 2.10.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_37).
Type in expressions to have them evaluated.
Type :help for more information.

scala> :power
** Power User mode enabled - BEEP WHIR GYVE **
** :phase has been set to 'typer'.          **
** scala.tools.nsc._ has been imported      **
** global._, definitions._ also imported    **
** Try  :help, :vals, power.<tab>           **

scala> rootMirror.getClassByName(newTermName("test.Xyz")).info.member(newTermName("abc"))
res0: $r.intp.global.Symbol = method abc

scala> res0.annotations
res1: List[$r.intp.global.AnnotationInfo] = List(throws(classOf[test.Foo]))

scala> val Literal(const) = res1.head.args.head
const: $r.intp.global.Constant = Constant(test.Foo)

scala> const.typeValue
res2: $r.intp.global.Type = test.Foo

scala> res2.typeParams
res3: List[$r.intp.global.Symbol] = List(type T)

scala> exit
warning: there were 1 deprecation warnings; re-run with -deprecation for details

@scabug
Copy link
Author

scabug commented Jan 25, 2013

@gkossakowski said:
Also, here's quote from Java spec:

It is a compile-time error if a generic class is a direct or indirect subclass of Throwable.

That's why code above compiles; javac doesn't even bother to check if an exception declared in throws is polymorphic because it assumes that can never happen.

@scabug
Copy link
Author

scabug commented Jan 28, 2013

@gkossakowski said:
FYI: My first pull request got closed but I'm still working on this problem. I'll have less ambitious pull request ready soon.

@scabug
Copy link
Author

scabug commented Feb 1, 2013

@gkossakowski said:
Fixed by scala/scala#2021

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants