diff options
author | Martin Odersky <odersky@gmail.com> | 2008-07-25 15:28:32 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2008-07-25 15:28:32 +0000 |
commit | c8b3af98b9dd45a358332f60e3bc8f5b8b3c604a (patch) | |
tree | 4bb2bf12c21bef3e3b2983c05179c34d999caccc /src/compiler | |
parent | d1fb9078954b3e35cef3f6967ce39748a1011036 (diff) | |
download | scala-c8b3af98b9dd45a358332f60e3bc8f5b8b3c604a.tar.gz scala-c8b3af98b9dd45a358332f60e3bc8f5b8b3c604a.tar.bz2 scala-c8b3af98b9dd45a358332f60e3bc8f5b8b3c604a.zip |
generating java generics signatures
Diffstat (limited to 'src/compiler')
8 files changed, 177 insertions, 158 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index d47ebd1182..8a96dfbb38 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -207,6 +207,7 @@ abstract class GenJVM extends SubComponent { clasz.fields foreach genField clasz.methods foreach genMethod + addGenericSignature(jclass, c.symbol) addAnnotations(jclass, c.symbol.attributes) emitClass(jclass, c.symbol) @@ -396,6 +397,20 @@ abstract class GenJVM extends SubComponent { nattr } + def addGenericSignature(jmember: JMember, sym: Symbol, tp: Type) { + if (settings.target.value == "jvm-1.5" && erasure.needsJavaSig(tp)) { + val sig = erasure.javaSig(tp) + if (settings.verbose.value) println("add generic sig "+sym+":"+tp+" ==> "+sig) + val buf = ByteBuffer.allocate(2) + buf.putShort(jmember.getConstantPool().addUtf8(sig).toShort) + addAttribute(jmember, nme.SignatureATTR, buf) + } + } + + def addGenericSignature(jmember: JMember, sym: Symbol) { + addGenericSignature(jmember, sym, atPhase(currentRun.erasurePhase)(sym.info)) + } + def addAnnotations(jmember: JMember, attributes: List[AnnotationInfo]) { val toEmit = attributes.filter(shouldEmitAttribute(_)) @@ -494,7 +509,7 @@ abstract class GenJVM extends SubComponent { jclass.addNewField(flags | attributes, javaName(f.symbol), javaType(f.symbol.tpe)); - + addGenericSignature(jfield, f.symbol) addAnnotations(jfield, f.symbol.attributes) } @@ -561,6 +576,7 @@ abstract class GenJVM extends SubComponent { genLocalVariableTable(m); } + addGenericSignature(jmethod, m.symbol) val (excs, others) = splitAnnotations(m.symbol.attributes, ThrowsAttr) addExceptionsAttribute(jmethod, excs) addAnnotations(jmethod, others) @@ -688,6 +704,8 @@ abstract class GenJVM extends SubComponent { mirrorCode.emitRETURN(mirrorMethod.getReturnType()) addRemoteException(mirrorMethod, m) + //todo: how add signature for mirror method? + //addGenericSignature(mirrorMethod, /*which type?*/) val (throws, others) = splitAnnotations(m.attributes, ThrowsAttr) addExceptionsAttribute(mirrorMethod, throws) addAnnotations(mirrorMethod, others) diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index 095ab0c561..3b8c876bd2 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -1156,7 +1156,7 @@ trait ParallelMatching { pats = pats.reverse if (indexOfAlternative == -1) { val res = List(Row(pats, subst, g, bx)) - DBG("finished: result "+res) + DBG("finished: result "/*+res*/) res } else { @@ -1164,7 +1164,7 @@ trait ParallelMatching { val alts = getAlternativeBranches(pats( indexOfAlternative )) val suffix = pats.drop(indexOfAlternative + 1) val intermediary_result = alts map { p => Row(prefix ::: p :: suffix, subst, g, bx) } - DBG("not finished: intermediary_result = "+intermediary_result) + DBG("not finished: intermediary_result = "/*+intermediary_result*/) intermediary_result } } @@ -1288,7 +1288,7 @@ trait ParallelMatching { val restTemp = temp.take(px) ::: temp.drop(px+1) val restRows = row map { case Row(pats, subst, g, bx) => Row(pats.take(px) ::: pats.drop(px+1), subst, g, bx) } val mr = MixtureRule(temps.head, column, rep.make(restTemp,restRows)) - DBG("\n---\nmixture rule is = "+mr.getClass.toString) + DBG("\n---\nmixture rule is = "/*+mr.getClass.toString*/) mr } diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index 26394bac04..1f4e9ec57e 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -207,11 +207,7 @@ trait Types { def isNotNull: Boolean = false /** Does this depend on an enclosing method parameter? */ - def isDependent: Boolean = { - IsDependentTraverser.result = false - IsDependentTraverser.traverse(this) - IsDependentTraverser.result - } + def isDependent: Boolean = IsDependentCollector.collect(this) /** The term symbol associated with the type * Note that the symbol of the normalized type is returned (@see normalize) @@ -329,11 +325,7 @@ trait Types { def isError: Boolean = typeSymbol.isError || termSymbol.isError /** Is this type produced as a repair for an error? */ - def isErroneous: Boolean = { - ErroneousTraverser.result = false - ErroneousTraverser.traverse(this) - ErroneousTraverser.result - } + def isErroneous: Boolean = ErroneousCollector.collect(this) /** Does this type denote a reference type which can be null? */ // def isNullable: Boolean = false @@ -461,16 +453,12 @@ trait Types { new SubstSuperMap(from, to) apply this /** Returns all parts of this type which satisfy predicate `p' */ - def filter(p: Type => Boolean): List[Type] = { - new FilterTypeTraverser(p).traverse(this).hits.toList - } + def filter(p: Type => Boolean): List[Type] = new FilterTypeCollector(p).collect(this).toList /** Returns optionally first type (in a preorder traversal) which satisfies predicate `p', * or None if none exists. */ - def find(p: Type => Boolean): Option[Type] = { - new FindTypeTraverser(p).traverse(this).result - } + def find(p: Type => Boolean): Option[Type] = new FindTypeCollector(p).collect(this) /** Apply `f' to each part of this type */ def foreach(f: Type => Unit) { new ForEachTypeTraverser(f).traverse(this) } @@ -479,12 +467,10 @@ trait Types { def exists(p: Type => Boolean): Boolean = !find(p).isEmpty /** Does this type contain a reference to this symbol? */ - def contains(sym: Symbol): Boolean = - new ContainsTraverser(sym).traverse(this).result + def contains(sym: Symbol): Boolean = new ContainsCollector(sym).collect(this) /** Does this type contain a reference to this type */ - def containsTp(tp: Type): Boolean = - new ContainsTypeTraverser(tp).traverse(this).result + def containsTp(tp: Type): Boolean = new ContainsTypeCollector(tp).collect(this) /** Is this type a subtype of that type? */ def <:<(that: Type): Boolean = { @@ -2488,10 +2474,19 @@ A type's typeSymbol should never be inspected directly. } abstract class TypeTraverser extends TypeMap { - def traverse(tp: Type): TypeTraverser //todo: return Unit instead? + def traverse(tp: Type): Unit def apply(tp: Type): Type = { traverse(tp); tp } } + abstract class TypeCollector[T](initial: T) extends TypeTraverser { + var result: T = _ + def collect(tp: Type) = { + result = initial + traverse(tp) + result + } + } + private val emptySymMap = scala.collection.immutable.Map[Symbol, Symbol]() private val emptySymCount = scala.collection.immutable.Map[Symbol, Int]() @@ -2962,10 +2957,8 @@ A type's typeSymbol should never be inspected directly. } /** A map to implement the `contains' method */ - class ContainsTraverser(sym: Symbol) extends TypeTraverser { - var result = false - - def traverse(tp: Type): ContainsTraverser = { + class ContainsCollector(sym: Symbol) extends TypeCollector(false) { + def traverse(tp: Type) { if (!result) { tp.normalize match { case TypeRef(_, sym1, _) if (sym == sym1) => result = true @@ -2973,7 +2966,6 @@ A type's typeSymbol should never be inspected directly. case _ => mapOver(tp) } } - this } override def mapOver(arg: Tree) = { @@ -2986,16 +2978,13 @@ A type's typeSymbol should never be inspected directly. } } - /** A map to implement the `contains' method */ - class ContainsTypeTraverser(t: Type) extends TypeTraverser { - var result = false - def traverse(tp: Type): ContainsTypeTraverser = { + class ContainsTypeCollector(t: Type) extends TypeCollector(false) { + def traverse(tp: Type) { if (!result) { if (tp eq t) result = true else mapOver(tp) } - this } override def mapOver(arg: Tree) = { for (t <- arg) { @@ -3006,55 +2995,46 @@ A type's typeSymbol should never be inspected directly. } /** A map to implement the `filter' method */ - class FilterTypeTraverser(p: Type => Boolean) extends TypeTraverser { - val hits = new ListBuffer[Type] - def traverse(tp: Type): FilterTypeTraverser = { - if (p(tp)) hits += tp + class FilterTypeCollector(p: Type => Boolean) extends TypeCollector(new ListBuffer[Type]) { + def traverse(tp: Type) { + if (p(tp)) result += tp mapOver(tp) - this } } class ForEachTypeTraverser(f: Type => Unit) extends TypeTraverser { - def traverse(tp: Type): TypeTraverser = { + def traverse(tp: Type) { f(tp) mapOver(tp) - this } } /** A map to implement the `filter' method */ - class FindTypeTraverser(p: Type => Boolean) extends TypeTraverser { - var result: Option[Type] = None - def traverse(tp: Type): FindTypeTraverser = { + class FindTypeCollector(p: Type => Boolean) extends TypeCollector[Option[Type]](None) { + def traverse(tp: Type) { if (result.isEmpty) { if (p(tp)) result = Some(tp) mapOver(tp) } - this } } /** A map to implement the `contains' method */ - object ErroneousTraverser extends TypeTraverser { - var result: Boolean = _ - def traverse(tp: Type): TypeTraverser = { + object ErroneousCollector extends TypeCollector(false) { + def traverse(tp: Type) { if (!result) { result = tp.isError mapOver(tp) } - this } } - object IsDependentTraverser extends TypeTraverser { - var result: Boolean = _ - def traverse(tp: Type): TypeTraverser = { + object IsDependentCollector extends TypeCollector(false) { + def traverse(tp: Type) { tp match { case DeBruijnIndex(_, _) => result = true case _ => if (!result) mapOver(tp) } - this } } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileConstants.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileConstants.scala index 617f847acb..1841f8e488 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileConstants.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileConstants.scala @@ -89,6 +89,7 @@ object ClassfileConstants { final val CLASS_TAG = 'c' final val ARRAY_TAG = '[' final val VOID_TAG = 'V' + final val TVAR_TAG = 'T' final val ANNOTATION_TAG = '@' // tags describing the type of newarray diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 30f0b71545..3bf2931a70 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -6,6 +6,7 @@ package scala.tools.nsc.transform +import scala.tools.nsc.symtab.classfile.ClassfileConstants._ import scala.collection.mutable.{HashMap,ListBuffer} import scala.tools.nsc.util.Position import symtab._ @@ -65,8 +66,6 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { tp match { case ConstantType(_) => tp - case NotNullType(tp) => // BQ to Martin: this used to be below st:SubType and unreachable, moved up - apply(tp) case st: SubType => apply(st.supertype) case TypeRef(pre, sym, args) => @@ -106,12 +105,126 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { else if (clazz == ArrayClass) List(erasedTypeRef(ObjectClass)) else removeDoubleObject(parents map this), decls, clazz) + case WildcardType => + AnyRefClass.tpe case _ => mapOver(tp) } } } + private object NeedsSigCollector extends TypeCollector(false) { + def traverse(tp: Type) { + if (!result) { + tp match { + case st: SubType => + traverse(st.supertype) + case TypeRef(pre, sym, args) => + if (sym == ArrayClass) args foreach traverse + else if (sym.isTypeParameterOrSkolem || sym.isExistential || !args.isEmpty) result = true + else if (!sym.owner.isPackageClass) traverse(pre) + case PolyType(_, _) | ExistentialType(_, _) => + result = true + case RefinedType(parents, decls) => + if (!parents.isEmpty) traverse(parents.head) + case ClassInfoType(parents, _, _) => + parents foreach traverse + case AnnotatedType(_, atp, _) => + traverse(atp) + case _ => + mapOver(tp) + } + } + } + } + + def needsJavaSig(tp: Type) = NeedsSigCollector.collect(tp) + + private lazy val tagOfClass = new HashMap[Symbol,Char] + ( + ByteClass -> BYTE_TAG, + CharClass -> CHAR_TAG, + DoubleClass -> DOUBLE_TAG, + FloatClass -> FLOAT_TAG, + IntClass -> INT_TAG, + LongClass -> LONG_TAG, + ShortClass -> SHORT_TAG, + BooleanClass -> BOOL_TAG, + UnitClass -> VOID_TAG + ) + + def javaSig(sym: Symbol): Option[String] = + if (needsJavaSig(sym.info)) { + Some(javaSig(sym.info)) + } else { + None + } + + def javaSig(tp: Type): String = javaSig(List(), tp) + + def javaSig(tparams: List[Symbol], tp0: Type): String = { + val tp = tp0.normalize + tp match { + case st: SubType => + javaSig(tparams, st.supertype) + case ExistentialType(tparams, tpe) => + javaSig(tparams, tpe) + case TypeRef(pre, sym, args) => + def argSig(tp: Type) = + if (tparams contains tp.typeSymbol) { + val bounds = tp.typeSymbol.info.bounds + if (!(AnyRefClass.tpe <:< bounds.hi)) "+"+javaSig(bounds.hi) + else if (!(bounds.lo <:< NullClass.tpe)) "-"+javaSig(bounds.lo) + else "*" + } else javaSig(tp) + def classSig: String = + "L"+atPhase(currentRun.icodePhase)(sym.fullNameString).replace('.', '/') + def classSigSuffix: String = + "."+atPhase(currentRun.icodePhase)(sym.name) + if (sym == ArrayClass) + ARRAY_TAG.toString+(args map javaSig).mkString + else if (sym.isTypeParameterOrSkolem) + TVAR_TAG.toString+sym.name+";" + else if (isValueClass(sym)) + tagOfClass(sym).toString + else if (sym.isClass) + { + if (needsJavaSig(pre)) { + val s = javaSig(pre) + if (s.charAt(0) == 'L') s.substring(0, s.length - 1) + classSigSuffix + else classSig + } else classSig + } + { + if (args.isEmpty) "" else "<"+(args map argSig).mkString+">" + } + ";" + else javaSig(erasure(tp)) + case PolyType(tparams, restpe) => + def hiBounds(bounds: TypeBounds): List[Type] = bounds.hi.normalize match { + case RefinedType(parents, _) => parents map normalize + case tp => List(tp) + } + def boundSig(bounds: List[Type]) = { + val classBound = bounds find (t => t.typeSymbol.isClass && !t.typeSymbol.isTrait) match { + case Some(t) => javaSig(t) + case None => "" + } + ":"+classBound+(for (t <- bounds if t.typeSymbol.isTrait) yield ":"+javaSig(t)).mkString + } + assert(!tparams.isEmpty) + def paramSig(tsym: Symbol) = tsym.name+boundSig(hiBounds(tsym.info.bounds)) + "<"+(tparams map paramSig).mkString+">"+javaSig(restpe) + case MethodType(formals, restpe) => + "("+(formals map javaSig).mkString+")"+javaSig(restpe) + case RefinedType(parents, decls) if (!parents.isEmpty) => + javaSig(parents.head) + case ClassInfoType(parents, _, _) => + (parents map javaSig).mkString + case AnnotatedType(_, atp, _) => + javaSig(atp) + case _ => + javaSig(erasure(tp)) + } + } + /** Type reference after erasure */ def erasedTypeRef(sym: Symbol): Type = typeRef(erasure(sym.owner.tpe), sym, List()) diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index eccb8f8f4d..5e77092248 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -1207,29 +1207,16 @@ trait Infer { } } - abstract class SymCollector extends TypeTraverser { - private var result: List[Symbol] = _ + abstract class SymCollector extends TypeCollector(List[Symbol]()) { protected def includeCondition(sym: Symbol): Boolean - override def traverse(tp: Type): TypeTraverser = { + def traverse(tp: Type) { tp.normalize match { case TypeRef(_, sym, _) => if (includeCondition(sym) && !result.contains(sym)) result = sym :: result case _ => } mapOver(tp) - this - } - - /** Collect all abstract type symbols referred to by type <code>tp</code>. - * - * @param tp ... - * @return ... - */ - def collect(tp: Type): List[Symbol] = { - result = List() - traverse(tp) - result } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index db79d072c7..d3b08886fb 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -757,43 +757,6 @@ trait Namers { self: Analyzer => } else typer.typedType(tpt).tpe) } - /** If `sym' is an implicit value, check that its type signature `tp' is contractive. - * This means: The type of every implicit parameter is properly contained - * in the type that is obtained by removing all implicit parameters and converting - * the rest to a function type. - * If the check succeeds return `tp' itself, otherwise `ErrorType'. - */ - private def checkContractive(sym: Symbol, tp: Type): Type = { - /* The type signature without implicit parameters converted to function type */ - def provided(tp: Type): Type = tp match { - case PolyType(_, restpe) => provided(restpe) - case mt: ImplicitMethodType => mt.resultType - case MethodType(formals, restpe) => functionType(formals, provided(restpe)) - case _ => tp - } - /* The types of all implicit parameters */ - def required(tp: Type): List[Type] = tp match { - case PolyType(_, restpe) => required(restpe) - case mt: ImplicitMethodType => mt.paramTypes - case MethodType(formals, restpe) => required(restpe) - case _ => List() - } - var result = tp; - if (sym hasFlag IMPLICIT) { - val p = provided(tp); - //Console.println("check contractive: "+sym+" "+p+"/"+required(tp)) - for (r <- required(tp)) { - if (!isContainedIn(r, p) || (r =:= p)) { - context.error(sym.pos, "implicit " + sym + " is not contractive," + - "\n because the implicit parameter type " + r + - "\n is not strictly contained in the signature " + p); - result = ErrorType; - } - } - } - result - } - //@M! an abstract type definition (abstract type member/type parameter) may take type parameters, which are in scope in its bounds private def typeDefSig(tpsym: Symbol, tparams: List[TypeDef], rhs: Tree) = { val tparamSyms = typer.reenterTypeParams(tparams) //@M make tparams available in scope (just for this abstypedef) @@ -878,7 +841,6 @@ trait Namers { self: Analyzer => case DefDef(_, _, tparams, vparamss, tpt, rhs) => //val result = newNamer(context.makeNewScope(tree, sym)).methodSig(tparams, vparamss, tpt, rhs) - //checkContractive(sym, result) case vdef @ ValDef(mods, _, tpt, rhs) => val typer1 = typer.constrTyperIf(sym.hasFlag(PARAM | PRESUPER) && sym.owner.isConstructor) @@ -1006,48 +968,6 @@ trait Namers { self: Analyzer => } } - /* Is type `tp1' properly contained in type `tp2'? */ - def isContainedIn(tp1: Type, tp2: Type) = { - //Console.println("is " + tp1 + " contained in " + tp2 + "?");//DEBUG - new ContainsTraverser(tp1).traverse(tp2).result - } - - /* Type `elemtp' is contained in type `tp' is one of the following holds: - * - elemtp is the same as some proper part of tp - * - tp is a function type and elemtp is not - * - tp and elemtp are function types, and arity of tp is greater than arity of elemtp - * - tp and elemtp are both parameterized types with same type constructor and prefix, - * and each type argument of elemtp is contained in the corresponding type argument of tp. - */ - private class ContainsTraverser(elemtp: Type) extends TypeTraverser { - var nested = false - var result = false - def traverse(tp: Type): ContainsTraverser = { - if (!result) { - if (elemtp =:= tp) - result = nested - else if (isFunctionType(tp) && - (!isFunctionType(elemtp) || tp.normalize.typeArgs.length > elemtp.normalize.typeArgs.length)) - result = true - else (tp, elemtp) match { - case (TypeRef(pre, sym, args), TypeRef(elempre, elemsym, elemargs)) => - if ((sym == elemsym) && (pre =:= elempre) && (args.length == elemargs.length)) - result = List.forall2(elemargs, args) (isContainedIn) - case _ => - } - } - if (!result) { - tp match { - case SingleType(_, _) => nested = true - case TypeRef(_, _, _) => nested = true - case _ => - } - mapOver(tp) - } - this - } - } - abstract class TypeCompleter extends LazyType { val tree: Tree } diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 27f7681a98..d60f7ef97e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -787,13 +787,13 @@ abstract class RefChecks extends InfoTransform { case TypeTree() => if (!inPattern) { new TypeTraverser { - def traverse(tp: Type): TypeTraverser = tp match { - case TypeRef(pre, sym, args) => - checkDeprecated(sym, tree.pos) - if (!tp.isHigherKinded) checkBounds(pre, sym.owner, sym.typeParams, args) - this - case _ => - this + def traverse(tp: Type) { + tp match { + case TypeRef(pre, sym, args) => + checkDeprecated(sym, tree.pos) + if (!tp.isHigherKinded) checkBounds(pre, sym.owner, sym.typeParams, args) + case _ => + } } } traverse tree.tpe } |