From f1701f704a2485fcc2eb6d5d8b5d0228beddd9b3 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Thu, 31 Jan 2013 20:40:16 +0100 Subject: SI-7008 @throws annotations are now populated in reflect Runtime reflection in JavaMirrors previously forgot to fill in @throws when importing Java reflection artifacts. Now this is fixed. Note that generic exception types used in `throws` specifications will be garbled (i.e. erased), because we don't use `getGenericExceptionTypes` in favor of just `getExceptionTypes` to stay compatible with the behavior of ClassfileParser. That's a bug, but a separate one and should be fixed separately. Also note that this commit updated javac-artifacts.jar, because we need to test how reflection works with javac-produced classfiles. The sources that were used to produce those classfiles can be found in the jar next to the classfiles. --- .../tools/nsc/symtab/classfile/ClassfileParser.scala | 8 +------- .../scala/reflect/internal/AnnotationInfos.scala | 17 ++++++++++++++--- src/reflect/scala/reflect/runtime/JavaMirrors.scala | 8 ++++++++ 3 files changed, 23 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 4b1d3c34f3..7ac7b4d637 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -1043,13 +1043,7 @@ abstract class ClassfileParser { val nClasses = in.nextChar for (n <- 0 until nClasses) { val cls = pool.getClassSymbol(in.nextChar.toInt) - val tp = if (cls.isMonomorphicType) cls.tpe else { - debuglog(s"Encountered polymorphic exception `${cls.fullName}` while parsing class file.") - // in case we encounter polymorphic exception the best we can do is to convert that type to - // monomorphic one by introducing existientals, see SI-7009 for details - typer.packSymbols(cls.typeParams, cls.tpe) - } - sym.addAnnotation(appliedType(definitions.ThrowsClass, tp), Literal(Constant(tp))) + sym.addThrowsAnnotation(cls) } } diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala index 6a5a742cc7..29879f9806 100644 --- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala +++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala @@ -33,6 +33,17 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => case ThrownException(exc) => exc } + def addThrowsAnnotation(excSym: Symbol): Self = { + val excTpe = if (excSym.isMonomorphicType) excSym.tpe else { + debuglog(s"Encountered polymorphic exception `${excSym.fullName}` while parsing class file.") + // in case we encounter polymorphic exception the best we can do is to convert that type to + // monomorphic one by introducing existentials, see SI-7009 for details + existentialAbstraction(excSym.typeParams, excSym.tpe) + } + val throwsAnn = AnnotationInfo(appliedType(definitions.ThrowsClass, excTpe), List(Literal(Constant(excTpe))), Nil) + withAnnotations(List(throwsAnn)) + } + /** Tests for, get, or remove an annotation */ def hasAnnotation(cls: Symbol): Boolean = //OPT inlined from exists to save on #closures; was: annotations exists (_ matches cls) @@ -330,14 +341,14 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => implicit val AnnotationTag = ClassTag[AnnotationInfo](classOf[AnnotationInfo]) object UnmappableAnnotation extends CompleteAnnotationInfo(NoType, Nil, Nil) - + /** Extracts symbol of thrown exception from AnnotationInfo. - * + * * Supports both “old-style” `@throws(classOf[Exception])` * as well as “new-stye” `@throws[Exception]("cause")` annotations. */ object ThrownException { - def unapply(ann: AnnotationInfo): Option[Symbol] = + def unapply(ann: AnnotationInfo): Option[Symbol] = ann match { case AnnotationInfo(tpe, _, _) if tpe.typeSymbol != ThrowsClass => None diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index 01e0634902..698b60b929 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -610,11 +610,19 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni /** * Copy all annotations of Java annotated element `jann` over to Scala symbol `sym`. + * Also creates `@throws` annotations if necessary. * Pre: `sym` is already initialized with a concrete type. * Note: If `sym` is a method or constructor, its parameter annotations are copied as well. */ private def copyAnnotations(sym: Symbol, jann: AnnotatedElement) { sym setAnnotations (jann.getAnnotations map JavaAnnotationProxy).toList + // FIXME: we're not using getGenericExceptionTypes here to be consistent with ClassfileParser + val jexTpes = jann match { + case jm: jMethod => jm.getExceptionTypes.toList + case jconstr: jConstructor[_] => jconstr.getExceptionTypes.toList + case _ => Nil + } + jexTpes foreach (jexTpe => sym.addThrowsAnnotation(classSymbol(jexTpe))) } /** -- cgit v1.2.3 From 0bcdf71a96d6d0b6276801efbe49081f0ae7749d Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Mon, 4 Feb 2013 22:06:54 +0100 Subject: pullrequest feedback https://github.com/scala/scala/pull/2040 --- .../scala/tools/nsc/symtab/classfile/ClassfileParser.scala | 1 + src/reflect/scala/reflect/internal/AnnotationInfos.scala | 10 +++++----- src/reflect/scala/reflect/runtime/JavaMirrors.scala | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 7ac7b4d637..976f7e038b 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -1042,6 +1042,7 @@ abstract class ClassfileParser { def parseExceptions(len: Int) { val nClasses = in.nextChar for (n <- 0 until nClasses) { + // FIXME: this performs an equivalent of getExceptionTypes instead of getGenericExceptionTypes (SI-7065) val cls = pool.getClassSymbol(in.nextChar.toInt) sym.addThrowsAnnotation(cls) } diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala index 29879f9806..032b45316e 100644 --- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala +++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala @@ -33,14 +33,14 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => case ThrownException(exc) => exc } - def addThrowsAnnotation(excSym: Symbol): Self = { - val excTpe = if (excSym.isMonomorphicType) excSym.tpe else { - debuglog(s"Encountered polymorphic exception `${excSym.fullName}` while parsing class file.") + def addThrowsAnnotation(throwableSym: Symbol): Self = { + val throwableTpe = if (throwableSym.isMonomorphicType) throwableSym.tpe else { + debuglog(s"Encountered polymorphic exception `${throwableSym.fullName}` while parsing class file.") // in case we encounter polymorphic exception the best we can do is to convert that type to // monomorphic one by introducing existentials, see SI-7009 for details - existentialAbstraction(excSym.typeParams, excSym.tpe) + existentialAbstraction(throwableSym.typeParams, throwableSym.tpe) } - val throwsAnn = AnnotationInfo(appliedType(definitions.ThrowsClass, excTpe), List(Literal(Constant(excTpe))), Nil) + val throwsAnn = AnnotationInfo(appliedType(definitions.ThrowsClass, throwableTpe), List(Literal(Constant(throwableTpe))), Nil) withAnnotations(List(throwsAnn)) } diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index 698b60b929..ea2fc4afe9 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -616,7 +616,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni */ private def copyAnnotations(sym: Symbol, jann: AnnotatedElement) { sym setAnnotations (jann.getAnnotations map JavaAnnotationProxy).toList - // FIXME: we're not using getGenericExceptionTypes here to be consistent with ClassfileParser + // SI-7065: we're not using getGenericExceptionTypes here to be consistent with ClassfileParser val jexTpes = jann match { case jm: jMethod => jm.getExceptionTypes.toList case jconstr: jConstructor[_] => jconstr.getExceptionTypes.toList -- cgit v1.2.3