From 47167f26473698fb217e30d51316ffd63a3500ca Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Thu, 22 Dec 2011 15:23:20 +0100 Subject: Documented emptyValDef field --- src/library/scala/reflect/api/Trees.scala | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/library') diff --git a/src/library/scala/reflect/api/Trees.scala b/src/library/scala/reflect/api/Trees.scala index 752319d9a4..e5502acb20 100644 --- a/src/library/scala/reflect/api/Trees.scala +++ b/src/library/scala/reflect/api/Trees.scala @@ -625,6 +625,11 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe => def TypeTree(tp: Type): TypeTree = TypeTree() setType tp + /** An empty deferred value definition corresponding to: + * val _: _ + * This is used as a placeholder in the `self` parameter Template if there is + * no definition of a self value of self type. + */ def emptyValDef: ValDef // ------ traversers, copiers, and transformers --------------------------------------------- -- cgit v1.2.3 From 08ec6ba4e4aeb94f6505ecb462b94362ff0af096 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Tue, 29 Nov 2011 00:03:40 +0100 Subject: [vpm] optimized codegen avoids option-boxing introducing two mutable variables per pattern match: matchRes and keepGoing keepGoing denotes whether the result was Some or None, and matchRes holds the Some's contents or the right zero for the match's type Race(() => fastMatch(list), () => virtMatch_no_option(list))(100000).converge() is a virtual tie on my machine after this see https://gist.github.com/1400910 conveniently also works around SI-5245 don't assign to Unit-typed var's, in fact, make matchRes a val when its only prospect in life is to be unit-valued propagate eventual type for matchRes thru codegen so that we can have more robust checks for unit¬hing, when assignment makes no sense also, added a hack to caseResult to avoid boxed units in if(keepGoing) { matchRes = ... } else zero after erasure, we get if(keepGoing) { matchRes = ...; BoxedUNIT } else zero genicode broke because i was sharing trees: [scalacfork] error: java.lang.AssertionError: assertion failed: type error: can't convert from UNIT to REF(class Object) in unit ScalaSig.scala at source-/Users/adriaan/git/scala-dev/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSig.scala,line-26,offset=868 fixed by duplicating -- so be it (for now -- make this more fine-grained, more efficient) dodging inliner issues with one/zero (it won't inline, so also directly inline those methods) --- src/compiler/scala/reflect/internal/TreeGen.scala | 29 +++- .../scala/tools/nsc/transform/UnCurry.scala | 39 +++--- .../tools/nsc/typechecker/PatMatVirtualiser.scala | 156 +++++++++++++++------ src/library/scala/MatchingStrategy.scala | 1 + 4 files changed, 160 insertions(+), 65 deletions(-) (limited to 'src/library') diff --git a/src/compiler/scala/reflect/internal/TreeGen.scala b/src/compiler/scala/reflect/internal/TreeGen.scala index 1c93a904c0..e537c6b83f 100644 --- a/src/compiler/scala/reflect/internal/TreeGen.scala +++ b/src/compiler/scala/reflect/internal/TreeGen.scala @@ -154,9 +154,13 @@ abstract class TreeGen { debuglog("casting " + tree + ":" + tree.tpe + " to " + pt + " at phase: " + phase) assert(!tree.tpe.isInstanceOf[MethodType], tree) assert(!pt.typeSymbol.isPackageClass && !pt.typeSymbol.isPackageObjectClass, pt) - // @MAT only called during erasure, which already takes care of that - // @PP: "only called during erasure" is not very true these days. - // In addition, at least, are: typer, uncurry, explicitouter, cleanup. + // called during (at least): typer, uncurry, explicitouter, cleanup. + // TODO: figure out the truth table for any/wrapInApply + // - the `any` flag seems to relate to erasure's adaptMember: "x.asInstanceOf[T] becomes x.$asInstanceOf[T]", + // where asInstanceOf is Any_asInstanceOf and $asInstanceOf is Object_asInstanceOf + // erasure will only unbox the value in a tree made by mkCast if `any && wrapInApply` + // - the `wrapInApply` flag need not be true if the tree will be adapted to have the empty argument list added before it gets to erasure + // in fact, I think it should be false for trees that will be type checked during typer assert(pt eq pt.normalize, tree +" : "+ debugString(pt) +" ~>"+ debugString(pt.normalize)) atPos(tree.pos)(mkAsInstanceOf(tree, pt, any = false, wrapInApply = true)) } @@ -262,6 +266,25 @@ abstract class TreeGen { tree setType tp } + def mkZeroContravariantAfterTyper(tp: Type): Tree = { + // contravariant -- for replacing an argument in a method call + // must use subtyping, as otherwise we miss types like `Any with Int` + val tree = + if (NullClass.tpe <:< tp) Literal(Constant(null)) + else if (UnitClass.tpe <:< tp) Literal(Constant()) + else if (BooleanClass.tpe <:< tp) Literal(Constant(false)) + else if (FloatClass.tpe <:< tp) Literal(Constant(0.0f)) + else if (DoubleClass.tpe <:< tp) Literal(Constant(0.0d)) + else if (ByteClass.tpe <:< tp) Literal(Constant(0.toByte)) + else if (ShortClass.tpe <:< tp) Literal(Constant(0.toShort)) + else if (IntClass.tpe <:< tp) Literal(Constant(0)) + else if (LongClass.tpe <:< tp) Literal(Constant(0L)) + else if (CharClass.tpe <:< tp) Literal(Constant(0.toChar)) + else mkCast(Literal(Constant(null)), tp) + + tree + } + /** Builds a tuple */ def mkTuple(elems: List[Tree]): Tree = if (elems.isEmpty) Literal(Constant()) diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index f319abd060..769ef79546 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -310,27 +310,34 @@ abstract class UnCurry extends InfoTransform case Apply(fun, List(a)) if fun.symbol == one => // blow one's argument away since all we want to know is whether the match succeeds or not // (the alternative, making `one` CBN, would entail moving away from Option) - val zero = // must use subtyping (no need for equality thanks to covariance), as otherwise we miss types like `Any with Int` - if (UnitClass.tpe <:< a.tpe) Literal(Constant()) - else if (BooleanClass.tpe <:< a.tpe) Literal(Constant(false)) - else if (FloatClass.tpe <:< a.tpe) Literal(Constant(0.0f)) - else if (DoubleClass.tpe <:< a.tpe) Literal(Constant(0.0d)) - else if (ByteClass.tpe <:< a.tpe) Literal(Constant(0.toByte)) - else if (ShortClass.tpe <:< a.tpe) Literal(Constant(0.toShort)) - else if (IntClass.tpe <:< a.tpe) Literal(Constant(0)) - else if (LongClass.tpe <:< a.tpe) Literal(Constant(0L)) - else if (CharClass.tpe <:< a.tpe) Literal(Constant(0.toChar)) - else { - val tpA = a.tpe.normalize - if (NullClass.tpe <:< tpA) NULL - else gen.mkCast(NULL, tpA) // must cast, at least when a.tpe <:< NothingClass.tpe - } - Apply(fun.duplicate, List(zero)) + Apply(fun.duplicate, List(gen.mkZeroContravariantAfterTyper(a.tpe))) case _ => super.transform(tree) } } substTree(Apply(Apply(TypeApply(Select(tgt.duplicate, tgt.tpe.member("isSuccess".toTermName)), targs map (_.duplicate)), args_scrut map (_.duplicate)), args_pm map (noOne.transform))) + // for no-option version of virtpatmat + case Block(List(zero: ValDef, x: ValDef, matchRes: ValDef, keepGoing: ValDef, stats@_*), _) if opt.virtPatmat => import CODE._ + object dropMatchResAssign extends Transformer { + // override val treeCopy = newStrictTreeCopier // will duplicate below + override def transform(tree: Tree): Tree = tree match { + // don't compute the result of the match -- remove the caseResult block, except for the assignment to keepGoing + case Block(List(matchRes, ass@Assign(keepGoingLhs, falseLit)), zero) if keepGoingLhs.symbol eq keepGoing.symbol => + Block(List(ass), zero) + case _ => + super.transform(tree) + } + } + val statsNoMatchRes: List[Tree] = stats map (dropMatchResAssign.transform) toList + val idaBlock = Block( + zero :: + x :: + /* drop matchRes def */ + keepGoing :: + statsNoMatchRes, + NOT(REF(keepGoing.symbol)) // replace `if (keepGoing) throw new MatchError(...) else matchRes` by `!keepGoing` + ) + substTree(idaBlock.duplicate) // duplicate on block as a whole to ensure valdefs are properly cloned and substed }) } diff --git a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala index c04e4796c4..05a85e97fe 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala @@ -88,9 +88,9 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => val scrutType = repeatedToSeq(elimAnonymousClass(scrut.tpe.widen)) val scrutSym = freshSym(scrut.pos, scrutType) - + val okPt = repeatedToSeq(pt) // pt = Any* occurs when compiling test/files/pos/annotDepMethType.scala with -Xexperimental - fixerUpper(context.owner, scrut.pos)(combineCases(scrut, scrutSym, cases map translateCase(scrutSym), repeatedToSeq(pt))) + fixerUpper(context.owner, scrut.pos)(combineCases(scrut, scrutSym, cases map translateCase(scrutSym, okPt), okPt)) } @@ -122,8 +122,8 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => * a function that will take care of binding and substitution of the next ast (to the right). * */ - def translateCase(scrutSym: Symbol)(caseDef: CaseDef) = caseDef match { case CaseDef(pattern, guard, body) => - (translatePattern(scrutSym, pattern) ++ translateGuard(guard), translateBody(body)) + def translateCase(scrutSym: Symbol, pt: Type)(caseDef: CaseDef) = caseDef match { case CaseDef(pattern, guard, body) => + (translatePattern(scrutSym, pattern) ++ translateGuard(guard), translateBody(body, pt)) } def translatePattern(patBinder: Symbol, patTree: Tree): List[TreeMaker] = { @@ -245,7 +245,7 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => // `one(x) : T` where x is the binder before this pattern, which will be replaced by the binder for the alternative by TreeMaker.singleBinder below // T is the widened type of the previous binder -- this ascription is necessary to infer a clean type for `or` -- the alternative combinator -- in the presence of existential types // see pos/virtpatmat_exist1.scala - combineExtractors(translatePattern(patBinder, alt), pmgen.one(CODE.REF(patBinder), patBinder.info.widen)) + combineExtractors(translatePattern(patBinder, alt), pmgen.one(CODE.REF(patBinder), patBinder.info.widen)) // only RHS of actual case should use caseResult, else the optimized codegen breaks } noFurtherSubPats(AlternativesTreeMaker(patBinder, altTrees : _*)) @@ -283,7 +283,7 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => // so that we can return Option's from a match without ambiguity whether this indicates failure in the monad, or just some result in the monad // 2) body.tpe is the type of the body after applying the substitution that represents the solution of GADT type inference // need the explicit cast in case our substitutions in the body change the type to something that doesn't take GADT typing into account - def translateBody(body: Tree): Tree = atPos(body.pos)(pmgen.caseResult(body, body.tpe)) + def translateBody(body: Tree, matchPt: Type): Tree = atPos(body.pos)(pmgen.caseResult(body, body.tpe, matchPt)) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -762,10 +762,15 @@ defined class Foo */ pmgen.or(wrapFunSubst(next), alts.toList) setPos alts.head.pos } - case class GuardTreeMaker(guardTree: Tree) extends SingleExtractorTreeMaker { + case class GuardTreeMaker(guardTree: Tree) extends /*SingleExtractor*/TreeMaker { val initialSubstitution: Substitution = EmptySubstitution - val nextBinder = freshSym(guardTree.pos, UnitClass.tpe) - val extractor = pmgen.guard(guardTree) + // val nextBinder = freshSym(guardTree.pos, UnitClass.tpe) + // val extractor = pmgen.guard(guardTree) + def chainBefore(next: Tree): Tree = { import CODE._ + IF (guardTree) THEN next ELSE pmgen.zero + } + + override def toString = "G("+ guardTree +")" } // combineExtractors changes the current substitution's of the tree makers in `treeMakers` @@ -901,7 +906,7 @@ defined class Foo */ } lazy val pmgen: CommonCodeGen with MatchingStrategyGen with MonadInstGen = - if (matchingMonadType.typeSymbol eq OptionClass) (new CommonCodeGen with MatchingStrategyGenOpt with MonadInstGenOpt {}) + if (matchingMonadType.typeSymbol eq OptionClass) (new CommonCodeGen with OptimizedCodeGen {}) else (new CommonCodeGen with MatchingStrategyGen with MonadInstGen {}) var ctr = 0 @@ -967,13 +972,13 @@ defined class Foo */ trait MatchingStrategyGen { self: CommonCodeGen with MatchingStrategyGen with MonadInstGen => // methods in MatchingStrategy (the monad companion) -- used directly in translation def runOrElse(scrut: Tree, matcher: Tree, scrutTp: Type, resTp: Type): Tree = genTypeApply(matchingStrategy DOT vpmName.runOrElse, scrutTp, resTp) APPLY (scrut) APPLY (matcher) // matchingStrategy.runOrElse(scrut)(matcher) - def zero: Tree = matchingStrategy DOT vpmName.zero // matchingStrategy.zero - def one(res: Tree): Tree = one(res, NoType) + def zero: Tree = matchingStrategy DOT vpmName.zero // matchingStrategy.zero + def one(res: Tree): Tree = one(res, NoType) def one(res: Tree, tp: Type = NoType, oneName: Name = vpmName.one): Tree = genTypeApply(matchingStrategy DOT oneName, tp) APPLY (res) // matchingStrategy.one(res) - def or(f: Tree, as: List[Tree]): Tree = (matchingStrategy DOT vpmName.or)((f :: as): _*) // matchingStrategy.or(f, as) - def guard(c: Tree): Tree = (matchingStrategy DOT vpmName.guard)(c, UNIT) // matchingStrategy.guard(c, then) -- a user-defined guard + def or(f: Tree, as: List[Tree]): Tree = (matchingStrategy DOT vpmName.or)((f :: as): _*) // matchingStrategy.or(f, as) + def guard(c: Tree): Tree = (matchingStrategy DOT vpmName.guard)(c, UNIT) // matchingStrategy.guard(c, then) -- a user-defined guard // TODO: get rid of the cast when it's unnecessary, but this requires type checking `body` -- maybe this should be one of the optimisations we perform after generating the tree - def caseResult(res: Tree, tp: Type): Tree = (matchingStrategy DOT vpmName.caseResult) (_asInstanceOf(res, tp, force = true)) // matchingStrategy.caseResult(res), like one, but blow this one away for isDefinedAt (since it's the RHS of a case) + def caseResult(res: Tree, bodyPt: Type, matchPt: Type): Tree = (matchingStrategy DOT vpmName.caseResult) (_asInstanceOf(res, bodyPt, force = true)) // matchingStrategy.caseResult(res), like one, but blow this one away for isDefinedAt (since it's the RHS of a case) // an internal guard TODO: use different method call so exhaustiveness can distinguish it from user-defined guards def cond(c: Tree, then: Tree = UNIT, tp: Type = NoType): Tree = genTypeApply((matchingStrategy DOT vpmName.guard), repackExistential(tp)) APPLY (c, then) // matchingStrategy.guard(c, then) @@ -991,30 +996,98 @@ defined class Foo */ // `o.flatMap(f)` becomes `if(o == None) None else f(o.get)`, similarly for orElse and guard // this is a special instance of the advanced inlining optimization that takes a method call on // an object of a type that only has two concrete subclasses, and inlines both bodies, guarded by an if to distinguish the two cases - trait MatchingStrategyGenOpt extends MatchingStrategyGen { self: CommonCodeGen with MatchingStrategyGen with MonadInstGen => + trait OptimizedCodeGen extends CommonCodeGen with MatchingStrategyGen with MonadInstGen { override def guard(c: Tree): Tree = condOptimized(c, one(UNIT)) override def cond(c: Tree, then: Tree = UNIT, tp: Type = NoType): Tree = condOptimized(c, one(then, repackExistential(tp))) - // override def runOrElse(scrut: Tree, matcher: Tree): Tree = matcher match { - // case Function(List(x: ValDef), body) => - // val tp = x.symbol.tpe - // val restp = appliedType(matchingMonadType, List(pt)) // don't always know pt.... - // val isEmpty = restp member vpmName.isEmpty - // val get = restp member vpmName.get - // - // val vs = freshSym(scrut.pos, tp, "s") - // val vres = freshSym(scrut.pos, restp, "res") - // val s = VAL(vs) === scrut - // val res = VAL(vres) === typedSubst(body, List(x.symbol), List(REF(vs))) - // - // BLOCK( - // s, - // res, - // IF (res DOT isEmpty) THEN ELSE (res DOT get) - // ) - // } - } - trait MonadInstGenOpt extends MonadInstGen { self: CommonCodeGen with MatchingStrategyGen with MonadInstGen => + lazy val zeroSym = freshSym(NoPosition, optionType(NothingClass.tpe), "zero") + override def zero: Tree = REF(zeroSym) + override def one(res: Tree, tp: Type = NoType, oneName: Name = vpmName.one): Tree = Apply(genTypeApply(REF(SomeModule), tp), List(res)) + + // duplicated out of frustration with cast generation + private def mkZero(tp: Type): Tree = { + tp.typeSymbol match { + case UnitClass => Literal(Constant()) + case BooleanClass => Literal(Constant(false)) + case FloatClass => Literal(Constant(0.0f)) + case DoubleClass => Literal(Constant(0.0d)) + case ByteClass => Literal(Constant(0.toByte)) + case ShortClass => Literal(Constant(0.toShort)) + case IntClass => Literal(Constant(0)) + case LongClass => Literal(Constant(0L)) + case CharClass => Literal(Constant(0.toChar)) + case _ => gen.mkAsInstanceOf(Literal(Constant(null)), tp, any = true, wrapInApply = false) // the magic incantation is true/false here + } + } + + + /** Inline runOrElse and get rid of Option allocations + * + * runOrElse(scrut: scrutTp)(matcher): resTp = matcher(scrut) getOrElse (throw new MatchError(x)) + * the matcher's optional result is encoded as a flag, keepGoing, where keepGoing == true encodes result.isEmpty, + * if keepGoing is false, the result Some(x) of the naive translation is encoded as matchRes == x + */ + @inline private def dontStore(tp: Type) = (tp.typeSymbol eq UnitClass) || (tp.typeSymbol eq NothingClass) + lazy val keepGoing = freshSym(NoPosition, BooleanClass.tpe, "keepGoing") setFlag MUTABLE + lazy val matchRes = freshSym(NoPosition, AnyClass.tpe, "matchRes") setFlag MUTABLE + override def runOrElse(scrut: Tree, matcher: Tree, scrutTp: Type, resTp: Type) = matcher match { + case Function(List(x: ValDef), body) => + matchRes.info = if (resTp ne NoType) resTp.widen else AnyClass.tpe // we don't always know resTp, and it might be AnyVal, in which case we can't assign NULL + if (dontStore(resTp)) matchRes resetFlag MUTABLE // don't assign to Unit-typed var's, in fact, make it a val -- conveniently also works around SI-5245 + BLOCK( + VAL(zeroSym) === REF(NoneModule), // TODO: can we just get rid of explicitly emitted zero? don't know how to do that as a local rewrite... + VAL(x.symbol) === scrut, // reuse the symbol of the function's argument to avoid creating a fresh one and substituting it for x.symbol in body -- the owner structure is repaired by fixerUpper + VAL(matchRes) === mkZero(matchRes.info), // must cast to deal with GADT typing, hence the private mkZero above + VAL(keepGoing) === TRUE, + body, + IF (REF(keepGoing)) THEN MATCHERROR(REF(x.symbol)) ELSE REF(matchRes) + ) + } + + override def caseResult(res: Tree, bodyPt: Type, matchPt: Type): Tree = { + BLOCK( + if (dontStore(matchPt)) res // runOrElse hasn't been called yet, so matchRes.isMutable is irrelevant, also, tp may be a subtype of resTp used in runOrElse... + else (REF(matchRes) === res), // _asInstanceOf(res, tp.widen, force = true) + REF(keepGoing) === FALSE, + zero // to have a nice lub for lubs -- otherwise we'll get a boxed unit here -- TODO: get rid of all those dangling else zero's + ) + } + + override def typedOrElse(pt: Type)(thisCase: Tree, elseCase: Tree): Tree = { + BLOCK( + thisCase, + IF (REF(keepGoing)) THEN elseCase ELSE zero // leave trailing zero for now, otherwise typer adds () anyway + ) + } + + /* TODO: make more efficient -- + val i = 0 + while(keepGoing && i < alts.length) { + val altOpt = @switch i match { case 0 => alt_0 .... case alts.length-1 => alt_N-1 } + if (altOpt ne zero) { + val alt = altOpt.get + nextBody + } + i += 1 + } + */ + override def or(next: Tree, alts: List[Tree]): Tree = { + val Function(List(nextVD: ValDef), nextBody) = next + val thunks = (REF(ListModule) DOT List_apply) APPLY (alts map (Function(Nil, _))) + val alt = nextVD.symbol + val altTp = alt.info + val altThunk = freshSym(alts.head.pos, functionType(List(), optionType(altTp)), "altThunk") + val altOpt = freshSym(alts.head.pos, optionType(altTp), "altOpt") + val altGet = optionType(altTp) member vpmName.get + + (thunks DOT "dropWhile".toTermName) APPLY (Function(List(ValDef(altThunk)), + BLOCK( + VAL(altOpt) === (REF(altThunk) APPLY ()), + IF (REF(altOpt) OBJ_NE zero) THEN BLOCK(VAL(alt) === (REF(altOpt) DOT altGet), nextBody) ENDIF, + REF(keepGoing) + ))) + } + override def flatMap(opt: Tree, fun: Tree): Tree = fun match { case Function(List(x: ValDef), body) => val tp = appliedType(matchingMonadType, List(x.symbol.tpe)) @@ -1025,20 +1098,11 @@ defined class Foo */ BLOCK( v, - IF (vs DOT isEmpty) THEN zero ELSE typedSubst(body, List(x.symbol), List(vs DOT get)) + IF (vs DOT isEmpty) THEN zero ELSE typedSubst(body, List(x.symbol), List(vs DOT get)) // must be isEmpty and get as we don't control the target of the call (could be the result of a user-defined extractor) ) case _ => println("huh?") (opt DOT vpmName.flatMap)(fun) } - override def typedOrElse(pt: Type)(thisCase: Tree, elseCase: Tree): Tree = { - val vs = freshSym(thisCase.pos, pt, "o") - val isEmpty = pt member vpmName.isEmpty - val v = VAL(vs) === thisCase // genTyped(, pt) - BLOCK( - v, - IF (vs DOT isEmpty) THEN elseCase /*genTyped(, pt)*/ ELSE REF(vs) - ) - } } def genTypeApply(tfun: Tree, args: Type*): Tree = if(args contains NoType) tfun else TypeApply(tfun, args.toList map TypeTree) diff --git a/src/library/scala/MatchingStrategy.scala b/src/library/scala/MatchingStrategy.scala index 4eaf7852b8..2c713e4850 100644 --- a/src/library/scala/MatchingStrategy.scala +++ b/src/library/scala/MatchingStrategy.scala @@ -10,6 +10,7 @@ abstract class MatchingStrategy[M[+x]] { // find the first alternative to successfully flatMap f // to avoid code explosion due to alternatives + // TODO: should be alts: => M[T]* def or[T, U](f: T => M[U], alts: M[T]*) = (alts foldLeft (zero: M[U]))(altFlatMap(f)) def caseResult[T](x: T): M[T] = one(x) // used as a marker to distinguish the RHS of a case (case pat => RHS) and intermediate successes -- cgit v1.2.3 From 0be2888938098f26a59115550073dde7f5dd7bd1 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Wed, 14 Dec 2011 14:46:38 +0100 Subject: [vpm] better codegen, especially for alternatives (suggested by Tiark) factored out some of the optimizing codegen that had snuck into treemakers (guardtreemaker) removed `caseResult`, back to just `one` no longer emitting intermediate `one`s (using guard instead -- when not optimizing) so uncurry can't accidentally blow them away (it removes the `one` that represents the case's result, but should leave intermediate computation alone) still TODO: reusing-treemakers sharing prefixes of length 1 helps inlining suffix of alternatives if small enough --- .../scala/tools/nsc/transform/UnCurry.scala | 4 +- .../tools/nsc/typechecker/PatMatVirtualiser.scala | 439 ++++++++++----------- src/library/scala/MatchingStrategy.scala | 24 +- 3 files changed, 221 insertions(+), 246 deletions(-) (limited to 'src/library') diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 2921607c24..6ac28f2fe3 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -325,7 +325,7 @@ abstract class UnCurry extends InfoTransform case Apply(Apply(TypeApply(Select(tgt, nme.runOrElse), targs), args_scrut), args_pm) if opt.virtPatmat => object noOne extends Transformer { override val treeCopy = newStrictTreeCopier // must duplicate everything - val one = tgt.tpe member "caseResult".toTermName + val one = tgt.tpe member "one".toTermName override def transform(tree: Tree): Tree = tree match { case Apply(fun, List(a)) if fun.symbol == one => // blow one's argument away since all we want to know is whether the match succeeds or not @@ -341,7 +341,7 @@ abstract class UnCurry extends InfoTransform object dropMatchResAssign extends Transformer { // override val treeCopy = newStrictTreeCopier // will duplicate below override def transform(tree: Tree): Tree = tree match { - // don't compute the result of the match -- remove the caseResult block, except for the assignment to keepGoing + // don't compute the result of the match -- remove the block for the RHS (emitted by pmgen.one), except for the assignment to keepGoing case Block(List(matchRes, ass@Assign(keepGoingLhs, falseLit)), zero) if keepGoingLhs.symbol eq keepGoing.symbol => Block(List(ass), zero) case _ => diff --git a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala index f563f8bca2..17f2d4f96c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala @@ -239,16 +239,7 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => noFurtherSubPats(EqualityTestTreeMaker(patBinder, patTree, pos)) case Alternative(alts) => - val altTrees = alts map { alt => - // one alternative may still generate multiple trees (e.g., an extractor call + equality test) - // (for now,) alternatives may not bind variables (except wildcards), so we don't care about the final substitution built internally by makeTreeMakers - // `one(x) : T` where x is the binder before this pattern, which will be replaced by the binder for the alternative by TreeMaker.singleBinder below - // T is the widened type of the previous binder -- this ascription is necessary to infer a clean type for `or` -- the alternative combinator -- in the presence of existential types - // see pos/virtpatmat_exist1.scala - combineExtractors(propagateSubstitution(translatePattern(patBinder, alt)), pmgen.one(CODE.REF(patBinder), patBinder.info.widen)) // only RHS of actual case should use caseResult, else the optimized codegen breaks - } - - noFurtherSubPats(AlternativesTreeMaker(patBinder, altTrees : _*)) + noFurtherSubPats(AlternativesTreeMaker(patBinder, alts map (translatePattern(patBinder, _)), alts.head.pos)) /* TODO: Paul says about future version: I think this should work, and always intended to implement if I can get away with it. case class Foo(x: Int, y: String) @@ -277,13 +268,13 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => if (guard == EmptyTree) Nil else List(GuardTreeMaker(guard)) - // TODO: 1) if we want to support a generalisation of Kotlin's patmat continue, must not hard-wire lifting into the monad (which is now done by pmgen.caseResult), + // TODO: 1) if we want to support a generalisation of Kotlin's patmat continue, must not hard-wire lifting into the monad (which is now done by pmgen.one), // so that user can generate failure when needed -- use implicit conversion to lift into monad on-demand? // to enable this, probably need to move away from Option to a monad specific to pattern-match, // so that we can return Option's from a match without ambiguity whether this indicates failure in the monad, or just some result in the monad // 2) body.tpe is the type of the body after applying the substitution that represents the solution of GADT type inference // need the explicit cast in case our substitutions in the body change the type to something that doesn't take GADT typing into account - def translateBody(body: Tree, matchPt: Type): Tree = atPos(body.pos)(pmgen.caseResult(body, body.tpe, matchPt)) + def translateBody(body: Tree, matchPt: Type): Tree = atPos(body.pos)(pmgen.one(body, body.tpe, matchPt)) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -504,16 +495,8 @@ defined class Foo */ def treeMaker(patBinderOrCasted: Symbol, pos: Position): TreeMaker = { // the extractor call (applied to the binder bound by the flatMap corresponding to the previous (i.e., enclosing/outer) pattern) val extractorApply = atPos(pos)(spliceApply(patBinderOrCasted)) - - val patTreeLifted = - if (resultType.typeSymbol == BooleanClass) pmgen.cond(extractorApply) - else extractorApply - - val binder = freshSym(pos, resultInMonad) // can't simplify this when subPatBinders.isEmpty, since UnitClass.tpe is definitely wrong when isSeq, and resultInMonad should always be correct since it comes directly from the extractor's result type - lengthGuard(binder) match { - case None => ExtractorTreeMaker(patTreeLifted, binder, Substitution(subPatBinders, subPatRefs(binder))) - case Some(lenGuard) => FilteredExtractorTreeMaker(patTreeLifted, lenGuard, binder, Substitution(subPatBinders, subPatRefs(binder))) - } + val binder = freshSym(pos, resultInMonad) // can't simplify this when subPatBinders.isEmpty, since UnitClass.tpe is definitely wrong when isSeq, and resultInMonad should always be correct since it comes directly from the extractor's result type + ExtractorTreeMaker(extractorApply, lengthGuard(binder), binder, Substitution(subPatBinders, subPatRefs(binder)))(resultType.typeSymbol == BooleanClass) } override protected def seqTree(binder: Symbol): Tree = @@ -664,6 +647,9 @@ defined class Foo */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// trait TreeMakers { + def inMatchMonad(tp: Type): Type = appliedType(matchingMonadType, List(tp)) + lazy val optimizingCodeGen = matchingMonadType.typeSymbol eq OptionClass + abstract class TreeMaker { def substitution: Substitution = if (currSub eq null) localSubstitution @@ -681,20 +667,20 @@ defined class Foo */ } private[this] var currSub: Substitution = null - def chainBefore(next: Tree): Tree + // build Tree that chains `next` after the current extractor + def chainBefore(next: Tree, pt: Type): Tree def treesToHoist: List[Tree] = Nil } case class SubstOnlyTreeMaker(localSubstitution: Substitution) extends TreeMaker { - def chainBefore(next: Tree): Tree = substitution(next) + def chainBefore(next: Tree, pt: Type): Tree = substitution(next) } abstract class FunTreeMaker extends TreeMaker { val nextBinder: Symbol - // wrap a Fun (with binder nextBinder) around the next tree (unless nextBinder == NoSymbol) and perform our substitution - protected def wrapFunSubst(next: Tree): Tree - = pmgen.fun(nextBinder, substitution(next)) + // for CSE (used iff optimizingCodeGen) + // TODO: factor this out into a separate TreeMaker that gets created when reuse is detected -- don't mutate treemakers var reused: Boolean = false def reusedBinders: List[Symbol] = Nil override def treesToHoist: List[Tree] = { import CODE._ @@ -710,28 +696,21 @@ defined class Foo */ lazy val localSubstitution = Substitution(List(prevBinder), List(CODE.REF(nextBinder))) } - abstract class SingleExtractorTreeMaker extends FunTreeMaker { - val extractor: Tree - // build Tree that chains `next` after the current extractor - def chainBefore(next: Tree): Tree = - pmgen.flatMap(extractor, wrapFunSubst(next)) setPos extractor.pos - - } - // TODO: in the process of shifting optimized code gen into the treemakers: complete and make it conditional in the same way as is happening in pmgen abstract class CondTreeMaker extends FreshFunTreeMaker { import CODE._ val cond: Tree val res: Tree + // for CSE (used iff optimizingCodeGen) // must set reused before! override lazy val reusedBinders = if(reused) List(freshSym(pos, BooleanClass.tpe, "rc") setFlag MUTABLE, nextBinder setFlag MUTABLE) else Nil def storedCond = reusedBinders(0) def storedRes = reusedBinders(1) - def chainBefore(next: Tree): Tree = + def chainBefore(next: Tree, pt: Type): Tree = if (!reused) atPos(pos)(pmgen.flatMapCond(cond, res, nextBinder, nextBinderTp, substitution(next))) - else { + else { // for CSE (used iff optimizingCodeGen) IF (cond) THEN BLOCK( storedCond === TRUE, storedRes === res, @@ -740,6 +719,7 @@ defined class Foo */ } } + // for CSE (used iff optimizingCodeGen) case class ReusingCondTreeMaker(dropped_priors: List[(TreeMaker, Option[TreeMaker])]) extends TreeMaker { import CODE._ lazy val localSubstitution = { val (from, to) = dropped_priors.collect {case (dropped: CondTreeMaker, Some(prior: CondTreeMaker)) => (dropped.nextBinder, REF(prior.storedRes))}.unzip @@ -747,7 +727,7 @@ defined class Foo */ oldSubs.foldLeft(Substitution(from, to))(_ >> _) } - def chainBefore(next: Tree): Tree = { + def chainBefore(next: Tree, pt: Type): Tree = { val cond = REF(dropped_priors.reverse.collectFirst{case (_, Some(ctm: CondTreeMaker)) => ctm}.get.storedCond) IF (cond) THEN BLOCK( @@ -763,13 +743,20 @@ defined class Foo */ * the function's body is determined by the next TreeMaker * in this function's body, and all the subsequent ones, references to the symbols in `from` will be replaced by the corresponding tree in `to` */ - case class ExtractorTreeMaker(extractor: Tree, nextBinder: Symbol, localSubstitution: Substitution) extends SingleExtractorTreeMaker { + case class ExtractorTreeMaker(extractor: Tree, extraCond: Option[Tree], nextBinder: Symbol, localSubstitution: Substitution)(extractorReturnsBoolean: Boolean) extends FunTreeMaker { + def chainBefore(next: Tree, pt: Type): Tree = atPos(extractor.pos)( + if (extractorReturnsBoolean) pmgen.flatMapCond(extractor, CODE.UNIT, nextBinder, nextBinder.info.widen, substitution(condAndNext(next))) + else pmgen.flatMap(extractor, pmgen.fun(nextBinder, substitution(condAndNext(next)))) + ) + + private def condAndNext(next: Tree): Tree = extraCond map (pmgen.condOptimized(_, next)) getOrElse next + override def toString = "X"+(extractor, nextBinder) } // TODO: allow user-defined unapplyProduct case class ProductExtractorTreeMaker(prevBinder: Symbol, extraCond: Option[Tree], localSubstitution: Substitution) extends TreeMaker { import CODE._ - def chainBefore(next: Tree): Tree = { + def chainBefore(next: Tree, pt: Type): Tree = { val nullCheck = REF(prevBinder) OBJ_NE NULL val cond = extraCond match { case None => nullCheck @@ -781,11 +768,6 @@ defined class Foo */ override def toString = "P"+(prevBinder, extraCond getOrElse "", localSubstitution) } - case class FilteredExtractorTreeMaker(extractor: Tree, guard: Tree, nextBinder: Symbol, localSubstitution: Substitution) extends FunTreeMaker { - def chainBefore(next: Tree): Tree = - pmgen.flatMap(extractor, wrapFunSubst(pmgen.condOptimized(guard, next))) setPos extractor.pos - override def toString = "FX"+(extractor, guard, nextBinder) - } // need to substitute since binder may be used outside of the next extractor call (say, in the body of the case) case class TypeTestTreeMaker(prevBinder: Symbol, nextBinderTp: Type, pos: Position) extends CondTreeMaker { @@ -814,26 +796,56 @@ defined class Foo */ override def toString = "ET"+(prevBinder, patTree) } - case class AlternativesTreeMaker(prevBinder: Symbol, alts: Tree*) extends FreshFunTreeMaker { + case class AlternativesTreeMaker(prevBinder: Symbol, altss: List[List[TreeMaker]], pos: Position) extends FreshFunTreeMaker { val nextBinderTp: Type = prevBinder.info.widen - val pos = alts.head.pos - def chainBefore(next: Tree): Tree = - pmgen.or(wrapFunSubst(next), alts.toList) setPos alts.head.pos + private def inlineNext(next: Tree) = { + var okToInline = true + var sizeBudget = 20 // yep, totally arbitrary! + object travOkToInline extends Traverser { override def traverse(tree: Tree): Unit = if (sizeBudget >= 0) { sizeBudget -= 1; tree match { + case TypeApply(_, _) | Apply(_, _) | Select(_, _) + | Block(_, _) | Assign(_, _) | If(_, _, _) | Typed(_, _) => super.traverse(tree) // these are allowed if their subtrees are + case EmptyTree | This(_) | New(_) | Literal(_) | Ident(_) => // these are always ok + case _ if tree.isType => // these are always ok + case _ => okToInline = false //; println("not inlining: "+ (tree, tree.getClass)) + }}} + travOkToInline.traverse(next) + // println("(okToInline, sizeBudget): "+ (okToInline, sizeBudget)) + okToInline && sizeBudget > 0 // must be strict comparison + } + def chainBefore(next: Tree, pt: Type): Tree = { import CODE._ + atPos(pos)( + if (inlineNext(next)) { + altss map (altTreeMakers => + combineExtractors(propagateSubstitution(altTreeMakers), next.duplicate, pt) // don't substitute prevBinder to nextBinder, beta-reduce application to prevBinder + ) reduceLeft pmgen.typedOrElse(pt) + } else { + val rest = freshSym(pos, functionType(List(nextBinderTp), inMatchMonad(pt)), "rest") + // rest.info.member(nme.apply).withAnnotation(AnnotationInfo(ScalaInlineClass.tpe, Nil, Nil)) + + // one alternative may still generate multiple trees (e.g., an extractor call + equality test) + // (for now,) alternatives may not bind variables (except wildcards), so we don't care about the final substitution built internally by makeTreeMakers + val combinedAlts = altss map (altTreeMakers => + combineExtractors(propagateSubstitution(altTreeMakers), REF(rest) APPLY (REF(prevBinder)), pt) + ) + BLOCK( + VAL(rest) === pmgen.fun(nextBinder, substitution(next)), + combinedAlts reduceLeft pmgen.typedOrElse(pt) + ) + } + ) + } } - case class GuardTreeMaker(guardTree: Tree) extends /*SingleExtractor*/TreeMaker { + case class GuardTreeMaker(guardTree: Tree) extends TreeMaker { val localSubstitution: Substitution = EmptySubstitution - // val nextBinder = freshSym(guardTree.pos, UnitClass.tpe) - // val extractor = pmgen.guard(guardTree) - def chainBefore(next: Tree): Tree = { import CODE._ - IF (guardTree) THEN next ELSE pmgen.zero - } + def chainBefore(next: Tree, pt: Type): Tree = pmgen.flatMapGuard(guardTree, next) override def toString = "G("+ guardTree +")" } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // decisions, decisions /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + object Test { var currId = 0 } @@ -996,11 +1008,10 @@ defined class Foo */ case tm@TypeTestTreeMaker(prevBinder, nextBinderTp, _) => TypeCond(binderToUniqueTree(prevBinder), uniqueTp(nextBinderTp)) case tm@TypeAndEqualityTestTreeMaker(_, patBinder, pt, _) => TypeAndEqualityCond(binderToUniqueTree(patBinder), uniqueTp(pt)) case tm@EqualityTestTreeMaker(prevBinder, patTree, _) => EqualityCond(binderToUniqueTree(prevBinder), unique(patTree)) - case ExtractorTreeMaker(_, _, _) + case ExtractorTreeMaker(_, _, _, _) | GuardTreeMaker(_) | ProductExtractorTreeMaker(_, Some(_), _) => Havoc - case FilteredExtractorTreeMaker(x, g, nb, subst) => Havoc - case AlternativesTreeMaker(_, _*) => Havoc // TODO: can do better here + case AlternativesTreeMaker(_, _, _) => Havoc // TODO: can do better here case SubstOnlyTreeMaker(_) => Top }, tm) } @@ -1047,7 +1058,7 @@ defined class Foo */ yield diff).nonEmpty } - val collapsedTreeMakers = if (sharedPrefix.lengthCompare(1) > 0) { // prefix must be longer than one for the optimization to pay off + val collapsedTreeMakers = if (sharedPrefix.nonEmpty) { // even sharing prefixes of length 1 brings some benefit (overhead-percentage for compiler: 26->24%, lib: 19->16%) for (test <- sharedPrefix; reusedTest <- test.reuses; if reusedTest.treeMaker.isInstanceOf[FunTreeMaker]) reusedTest.treeMaker.asInstanceOf[FunTreeMaker].reused = true // println("sharedPrefix: "+ sharedPrefix) @@ -1075,7 +1086,9 @@ defined class Foo */ // calls propagateSubstitution on the treemakers def analyzeCases(prevBinder: Symbol, cases: List[(List[TreeMaker], Tree)], pt: Type): List[(List[TreeMaker], Tree)] = { cases foreach { case (pats, _) => propagateSubstitution(pats) } - doCSE(prevBinder, cases, pt) + if (optimizingCodeGen) { + doCSE(prevBinder, cases, pt) + } else cases } def combineCases(scrut: Tree, scrutSym: Symbol, cases0: List[(List[TreeMaker], Tree)], pt: Type): Tree = { @@ -1084,15 +1097,15 @@ defined class Foo */ if (cases0 nonEmpty) { // when specified, need to propagate pt explicitly (type inferencer can't handle it) val optPt = - if (isFullyDefined(pt)) appliedType(matchingMonadType, List(pt)) + if (isFullyDefined(pt)) inMatchMonad(pt) else NoType val cases = analyzeCases(scrutSym, cases0, pt) // map + foldLeft - var combinedCases = combineExtractors(cases.head._1, cases.head._2) + var combinedCases = combineExtractors(cases.head._1, cases.head._2, pt) cases.tail foreach { case (pats, body) => - combinedCases = pmgen.typedOrElse(optPt)(combinedCases, combineExtractors(pats, body)) + combinedCases = pmgen.typedOrElse(optPt)(combinedCases, combineExtractors(pats, body, pt)) } toHoist = (for ((treeMakers, _) <- cases; tm <- treeMakers; hoisted <- tm.treesToHoist) yield hoisted).toList @@ -1108,10 +1121,14 @@ defined class Foo */ // combineExtractors changes the current substitution's of the tree makers in `treeMakers` // requires propagateSubstitution(treeMakers) has been called - def combineExtractors(treeMakers: List[TreeMaker], body: Tree): Tree = - treeMakers.foldRight (body) (_ chainBefore _) + def combineExtractors(treeMakers: List[TreeMaker], body: Tree, pt: Type): Tree = + treeMakers.foldRight (body) (_.chainBefore(_, pt)) +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// substitution +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + object Substitution { def apply(from: Symbol, to: Tree) = new Substitution(List(from), List(to)) // requires sameLength(from, to) @@ -1137,7 +1154,6 @@ defined class Foo */ } - def matchingMonadType: Type def typedSubst(tree: Tree, from: List[Symbol], to: List[Tree]): Tree def freshSym(pos: Position, tp: Type = NoType, prefix: String = "x"): Symbol @@ -1149,18 +1165,11 @@ defined class Foo */ def runOrElse(scrut: Tree, matcher: Tree, scrutTp: Type, resTp: Type): Tree def flatMap(a: Tree, b: Tree): Tree def flatMapCond(cond: Tree, res: Tree, nextBinder: Symbol, nextBinderTp: Type, next: Tree): Tree + def flatMapGuard(cond: Tree, next: Tree): Tree def fun(arg: Symbol, body: Tree): Tree - def or(f: Tree, as: List[Tree]): Tree def typedOrElse(pt: Type)(thisCase: Tree, elseCase: Tree): Tree - def guard(c: Tree): Tree def zero: Tree - def one(res: Tree): Tree - // TODO: defaults in traits + self types == broken? - // def guard(c: Tree, then: Tree, tp: Type): Tree - // def cond(c: Tree): Tree = cond(c, UNIT, NoType) - def cond(c: Tree, then: Tree, tp: Type): Tree def condOptimized(c: Tree, then: Tree): Tree - def condCast(c: Tree, binder: Symbol, expectedTp: Type): Tree def _equals(checker: Tree, binder: Symbol): Tree def _asInstanceOf(b: Symbol, tp: Type): Tree def mkZero(tp: Type): Tree @@ -1169,10 +1178,115 @@ defined class Foo */ def pmgen: AbsCodeGen } - // generate actual trees +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// generate actual trees +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + trait MatchCodeGen extends TreeMakers { - def matchingStrategy: Tree - def typed(tree: Tree, mode: Int, pt: Type): Tree // implemented in MatchTranslator + lazy val pmgen: CommonCodeGen with MatchingStrategyGen with MonadInstGen = + if (optimizingCodeGen) (new CommonCodeGen with OptimizedCodeGen {}) + else (new CommonCodeGen with MatchingStrategyGen with MonadInstGen {}) + + import CODE._ + + trait MatchingStrategyGen { self: CommonCodeGen with MatchingStrategyGen with MonadInstGen => + // methods in MatchingStrategy (the monad companion) -- used directly in translation + def runOrElse(scrut: Tree, matcher: Tree, scrutTp: Type, resTp: Type): Tree = genTypeApply(matchingStrategy DOT vpmName.runOrElse, scrutTp, resTp) APPLY (scrut) APPLY (matcher) // matchingStrategy.runOrElse(scrut)(matcher) + // *only* used to wrap the RHS of a body (isDefinedAt synthesis relies on this) + def one(res: Tree, bodyPt: Type, matchPt: Type): Tree = (matchingStrategy DOT vpmName.one) (_asInstanceOf(res, bodyPt, force = true)) // matchingStrategy.one(res), like one, but blow this one away for isDefinedAt (since it's the RHS of a case) + def zero: Tree = matchingStrategy DOT vpmName.zero // matchingStrategy.zero + def guard(c: Tree, then: Tree, tp: Type): Tree = genTypeApply((matchingStrategy DOT vpmName.guard), repackExistential(tp)) APPLY (c, then) // matchingStrategy.guard[tp](c, then) + } + + trait MonadInstGen { self: CommonCodeGen with MatchingStrategyGen with MonadInstGen => + // methods in the monad instance -- used directly in translation + def flatMap(a: Tree, b: Tree): Tree = (a DOT vpmName.flatMap)(b) + def typedOrElse(pt: Type)(thisCase: Tree, elseCase: Tree): Tree = (genTypeApply(thisCase DOT vpmName.orElse, pt)) APPLY (elseCase) + + // TODO: the trees generated by flatMapCond and flatMapGuard may need to be distinguishable by exhaustivity checking -- they aren't right now + def flatMapCond(cond: Tree, res: Tree, nextBinder: Symbol, + nextBinderTp: Type, next: Tree): Tree = flatMap(guard(cond, res, nextBinderTp), fun(nextBinder, next)) + def flatMapGuard(guardTree: Tree, next: Tree): Tree = flatMapCond(guardTree, CODE.UNIT, freshSym(guardTree.pos, UnitClass.tpe), UnitClass.tpe, next) + } + + // when we know we're targetting Option, do some inlining the optimizer won't do + // `o.flatMap(f)` becomes `if(o == None) None else f(o.get)`, similarly for orElse and guard + // this is a special instance of the advanced inlining optimization that takes a method call on + // an object of a type that only has two concrete subclasses, and inlines both bodies, guarded by an if to distinguish the two cases + // this trait overrides ALL of the methods of MatchingStrategyGen with MonadInstGen + trait OptimizedCodeGen extends CommonCodeGen with MatchingStrategyGen with MonadInstGen { + lazy val zeroSym = freshSym(NoPosition, optionType(NothingClass.tpe), "zero") + + /** Inline runOrElse and get rid of Option allocations + * + * runOrElse(scrut: scrutTp)(matcher): resTp = matcher(scrut) getOrElse (throw new MatchError(x)) + * the matcher's optional result is encoded as a flag, keepGoing, where keepGoing == true encodes result.isEmpty, + * if keepGoing is false, the result Some(x) of the naive translation is encoded as matchRes == x + */ + @inline private def dontStore(tp: Type) = (tp.typeSymbol eq UnitClass) || (tp.typeSymbol eq NothingClass) + lazy val keepGoing = freshSym(NoPosition, BooleanClass.tpe, "keepGoing") setFlag MUTABLE + lazy val matchRes = freshSym(NoPosition, AnyClass.tpe, "matchRes") setFlag MUTABLE + override def runOrElse(scrut: Tree, matcher: Tree, scrutTp: Type, resTp: Type) = matcher match { + case Function(List(x: ValDef), body) => + matchRes.info = if (resTp ne NoType) resTp.widen else AnyClass.tpe // we don't always know resTp, and it might be AnyVal, in which case we can't assign NULL + if (dontStore(resTp)) matchRes resetFlag MUTABLE // don't assign to Unit-typed var's, in fact, make it a val -- conveniently also works around SI-5245 + BLOCK( + VAL(zeroSym) === REF(NoneModule), // TODO: can we just get rid of explicitly emitted zero? don't know how to do that as a local rewrite... + VAL(x.symbol) === scrut, // reuse the symbol of the function's argument to avoid creating a fresh one and substituting it for x.symbol in body -- the owner structure is repaired by fixerUpper + VAL(matchRes) === mkZero(matchRes.info), // must cast to deal with GADT typing, hence the private mkZero above + VAL(keepGoing) === TRUE, + body, + IF (REF(keepGoing)) THEN MATCHERROR(REF(x.symbol)) ELSE REF(matchRes) + ) + } + + // only used to wrap the RHS of a body + override def one(res: Tree, bodyPt: Type, matchPt: Type): Tree = { + BLOCK( + if (dontStore(matchPt)) res // runOrElse hasn't been called yet, so matchRes.isMutable is irrelevant, also, tp may be a subtype of resTp used in runOrElse... + else (REF(matchRes) === res), // _asInstanceOf(res, tp.widen, force = true) + REF(keepGoing) === FALSE, + zero // to have a nice lub for lubs -- otherwise we'll get a boxed unit here -- TODO: get rid of all those dangling else zero's + ) + } + + override def zero: Tree = REF(zeroSym) + + // guard is only used by flatMapCond and flatMapGuard, which are overridden + override def guard(c: Tree, then: Tree, tp: Type): Tree = throw new NotImplementedError("guard is never called by optimizing codegen") + + override def flatMap(opt: Tree, fun: Tree): Tree = fun match { + case Function(List(x: ValDef), body) => + val tp = inMatchMonad(x.symbol.tpe) + val vs = freshSym(opt.pos, tp, "o") + val isEmpty = tp member vpmName.isEmpty + val get = tp member vpmName.get + val v = VAL(vs) === opt + + BLOCK( + v, + IF (vs DOT isEmpty) THEN zero ELSE typedSubst(body, List(x.symbol), List(vs DOT get)) // must be isEmpty and get as we don't control the target of the call (could be the result of a user-defined extractor) + ) + case _ => println("huh?") + (opt DOT vpmName.flatMap)(fun) + } + + override def typedOrElse(pt: Type)(thisCase: Tree, elseCase: Tree): Tree = { + BLOCK( + thisCase, + IF (REF(keepGoing)) THEN elseCase ELSE zero // leave trailing zero for now, otherwise typer adds () anyway + ) + } + + override def flatMapCond(cond: Tree, res: Tree, nextBinder: Symbol, nextBinderTp: Type, next: Tree): Tree = + IF (cond) THEN BLOCK( + VAL(nextBinder) === res, + next + ) ELSE zero + + override def flatMapGuard(guardTree: Tree, next: Tree): Tree = + IF (guardTree) THEN next ELSE zero + } @inline private def typedIfOrigTyped(to: Tree, origTp: Type): Tree = if (origTp == null || origTp == NoType) to @@ -1201,10 +1315,6 @@ defined class Foo */ }).transform(tree) } - lazy val pmgen: CommonCodeGen with MatchingStrategyGen with MonadInstGen = - if (matchingMonadType.typeSymbol eq OptionClass) (new CommonCodeGen with OptimizedCodeGen {}) - else (new CommonCodeGen with MatchingStrategyGen with MonadInstGen {}) - var ctr = 0 def freshSym(pos: Position, tp: Type = NoType, prefix: String = "x") = {ctr += 1; // assert(owner ne null) @@ -1218,34 +1328,33 @@ defined class Foo */ } object vpmName { - val caseResult = "caseResult".toTermName - val drop = "drop".toTermName - val flatMap = "flatMap".toTermName - val get = "get".toTermName - val guard = "guard".toTermName - val isEmpty = "isEmpty".toTermName - val one = "one".toTermName - val or = "or".toTermName - val orElse = "orElse".toTermName - val outer = "".toTermName - val runOrElse = "runOrElse".toTermName - val zero = "zero".toTermName + val one = "one".toTermName + val drop = "drop".toTermName + val flatMap = "flatMap".toTermName + val get = "get".toTermName + val guard = "guard".toTermName + val isEmpty = "isEmpty".toTermName + val orElse = "orElse".toTermName + val outer = "".toTermName + val runOrElse = "runOrElse".toTermName + val zero = "zero".toTermName def counted(str: String, i: Int) = (str+i).toTermName def tupleIndex(i: Int) = ("_"+i).toTermName } - import CODE._ def typesConform(tp: Type, pt: Type) = ((tp eq pt) || (tp <:< pt)) trait CommonCodeGen extends AbsCodeGen { self: CommonCodeGen with MatchingStrategyGen with MonadInstGen => - def fun(arg: Symbol, body: Tree): Tree = Function(List(ValDef(arg)), body) - def tupleSel(binder: Symbol)(i: Int): Tree = (REF(binder) DOT vpmName.tupleIndex(i)) // make tree that accesses the i'th component of the tuple referenced by binder - def index(tgt: Tree)(i: Int): Tree = tgt APPLY (LIT(i)) - def drop(tgt: Tree)(n: Int): Tree = (tgt DOT vpmName.drop) (LIT(n)) + def fun(arg: Symbol, body: Tree): Tree = Function(List(ValDef(arg)), body) + def genTypeApply(tfun: Tree, args: Type*): Tree = if(args contains NoType) tfun else TypeApply(tfun, args.toList map TypeTree) + def tupleSel(binder: Symbol)(i: Int): Tree = (REF(binder) DOT vpmName.tupleIndex(i)) // make tree that accesses the i'th component of the tuple referenced by binder + def index(tgt: Tree)(i: Int): Tree = tgt APPLY (LIT(i)) + def drop(tgt: Tree)(n: Int): Tree = (tgt DOT vpmName.drop) (LIT(n)) def _equals(checker: Tree, binder: Symbol): Tree = checker MEMBER_== REF(binder) // NOTE: checker must be the target of the ==, that's the patmat semantics for ya - def and(a: Tree, b: Tree): Tree = a AND b + def and(a: Tree, b: Tree): Tree = a AND b + def condOptimized(c: Tree, then: Tree): Tree = IF (c) THEN then ELSE zero // the force is needed mainly to deal with the GADT typing hack (we can't detect it otherwise as tp nor pt need contain an abstract type, we're just casting wildly) def _asInstanceOf(t: Tree, tp: Type, force: Boolean = false): Tree = { val tpX = repackExistential(tp) @@ -1281,136 +1390,8 @@ defined class Foo */ } } - trait MatchingStrategyGen { self: CommonCodeGen with MatchingStrategyGen with MonadInstGen => - // methods in MatchingStrategy (the monad companion) -- used directly in translation - def runOrElse(scrut: Tree, matcher: Tree, scrutTp: Type, resTp: Type): Tree = genTypeApply(matchingStrategy DOT vpmName.runOrElse, scrutTp, resTp) APPLY (scrut) APPLY (matcher) // matchingStrategy.runOrElse(scrut)(matcher) - def zero: Tree = matchingStrategy DOT vpmName.zero // matchingStrategy.zero - def one(res: Tree): Tree = one(res, NoType) - def one(res: Tree, tp: Type = NoType, oneName: Name = vpmName.one): Tree = genTypeApply(matchingStrategy DOT oneName, tp) APPLY (res) // matchingStrategy.one(res) - def or(f: Tree, as: List[Tree]): Tree = (matchingStrategy DOT vpmName.or)((f :: as): _*) // matchingStrategy.or(f, as) - def guard(c: Tree): Tree = (matchingStrategy DOT vpmName.guard)(c, UNIT) // matchingStrategy.guard(c, then) -- a user-defined guard - // TODO: get rid of the cast when it's unnecessary, but this requires type checking `body` -- maybe this should be one of the optimisations we perform after generating the tree - def caseResult(res: Tree, bodyPt: Type, matchPt: Type): Tree = (matchingStrategy DOT vpmName.caseResult) (_asInstanceOf(res, bodyPt, force = true)) // matchingStrategy.caseResult(res), like one, but blow this one away for isDefinedAt (since it's the RHS of a case) - - // an internal guard TODO: use different method call so exhaustiveness can distinguish it from user-defined guards - def cond(c: Tree, then: Tree = UNIT, tp: Type = NoType): Tree = genTypeApply((matchingStrategy DOT vpmName.guard), repackExistential(tp)) APPLY (c, then) // matchingStrategy.guard(c, then) - def condCast(c: Tree, binder: Symbol, expectedTp: Type): Tree = cond(c, _asInstanceOf(binder, expectedTp), expectedTp) - def condOptimized(c: Tree, then: Tree): Tree = IF (c) THEN then ELSE zero - } - - trait MonadInstGen { self: CommonCodeGen with MatchingStrategyGen with MonadInstGen => - // methods in the monad instance -- used directly in translation - def flatMap(a: Tree, b: Tree): Tree = (a DOT vpmName.flatMap)(b) - def flatMapCond(condi: Tree, res: Tree, nextBinder: Symbol, nextBinderTp: Type, next: Tree): Tree = - flatMap(cond(condi, res, nextBinderTp), fun(nextBinder, next)) - def typedOrElse(pt: Type)(thisCase: Tree, elseCase: Tree): Tree = (genTypeApply(thisCase DOT vpmName.orElse, pt)) APPLY (elseCase) - } - - // when we know we're targetting Option, do some inlining the optimizer won't do - // `o.flatMap(f)` becomes `if(o == None) None else f(o.get)`, similarly for orElse and guard - // this is a special instance of the advanced inlining optimization that takes a method call on - // an object of a type that only has two concrete subclasses, and inlines both bodies, guarded by an if to distinguish the two cases - trait OptimizedCodeGen extends CommonCodeGen with MatchingStrategyGen with MonadInstGen { - override def guard(c: Tree): Tree = condOptimized(c, one(UNIT)) - override def cond(c: Tree, then: Tree = UNIT, tp: Type = NoType): Tree = condOptimized(c, one(then, repackExistential(tp))) - - lazy val zeroSym = freshSym(NoPosition, optionType(NothingClass.tpe), "zero") - override def zero: Tree = REF(zeroSym) - override def one(res: Tree, tp: Type = NoType, oneName: Name = vpmName.one): Tree = Apply(genTypeApply(REF(SomeModule), tp), List(res)) - - - /** Inline runOrElse and get rid of Option allocations - * - * runOrElse(scrut: scrutTp)(matcher): resTp = matcher(scrut) getOrElse (throw new MatchError(x)) - * the matcher's optional result is encoded as a flag, keepGoing, where keepGoing == true encodes result.isEmpty, - * if keepGoing is false, the result Some(x) of the naive translation is encoded as matchRes == x - */ - @inline private def dontStore(tp: Type) = (tp.typeSymbol eq UnitClass) || (tp.typeSymbol eq NothingClass) - lazy val keepGoing = freshSym(NoPosition, BooleanClass.tpe, "keepGoing") setFlag MUTABLE - lazy val matchRes = freshSym(NoPosition, AnyClass.tpe, "matchRes") setFlag MUTABLE - override def runOrElse(scrut: Tree, matcher: Tree, scrutTp: Type, resTp: Type) = matcher match { - case Function(List(x: ValDef), body) => - matchRes.info = if (resTp ne NoType) resTp.widen else AnyClass.tpe // we don't always know resTp, and it might be AnyVal, in which case we can't assign NULL - if (dontStore(resTp)) matchRes resetFlag MUTABLE // don't assign to Unit-typed var's, in fact, make it a val -- conveniently also works around SI-5245 - BLOCK( - VAL(zeroSym) === REF(NoneModule), // TODO: can we just get rid of explicitly emitted zero? don't know how to do that as a local rewrite... - VAL(x.symbol) === scrut, // reuse the symbol of the function's argument to avoid creating a fresh one and substituting it for x.symbol in body -- the owner structure is repaired by fixerUpper - VAL(matchRes) === mkZero(matchRes.info), // must cast to deal with GADT typing, hence the private mkZero above - VAL(keepGoing) === TRUE, - body, - IF (REF(keepGoing)) THEN MATCHERROR(REF(x.symbol)) ELSE REF(matchRes) - ) - } - - override def caseResult(res: Tree, bodyPt: Type, matchPt: Type): Tree = { - BLOCK( - if (dontStore(matchPt)) res // runOrElse hasn't been called yet, so matchRes.isMutable is irrelevant, also, tp may be a subtype of resTp used in runOrElse... - else (REF(matchRes) === res), // _asInstanceOf(res, tp.widen, force = true) - REF(keepGoing) === FALSE, - zero // to have a nice lub for lubs -- otherwise we'll get a boxed unit here -- TODO: get rid of all those dangling else zero's - ) - } - - override def typedOrElse(pt: Type)(thisCase: Tree, elseCase: Tree): Tree = { - BLOCK( - thisCase, - IF (REF(keepGoing)) THEN elseCase ELSE zero // leave trailing zero for now, otherwise typer adds () anyway - ) - } - - /* TODO: make more efficient -- - val i = 0 - while(keepGoing && i < alts.length) { - val altOpt = @switch i match { case 0 => alt_0 .... case alts.length-1 => alt_N-1 } - if (altOpt ne zero) { - val alt = altOpt.get - nextBody - } - i += 1 - } - */ - override def or(next: Tree, alts: List[Tree]): Tree = { - val Function(List(nextVD: ValDef), nextBody) = next - val thunks = (REF(ListModule) DOT List_apply) APPLY (alts map (Function(Nil, _))) - val alt = nextVD.symbol - val altTp = alt.info - val altThunk = freshSym(alts.head.pos, functionType(List(), optionType(altTp)), "altThunk") - val altOpt = freshSym(alts.head.pos, optionType(altTp), "altOpt") - val altGet = optionType(altTp) member vpmName.get - - (thunks DOT "dropWhile".toTermName) APPLY (Function(List(ValDef(altThunk)), - BLOCK( - VAL(altOpt) === (REF(altThunk) APPLY ()), - IF (REF(altOpt) OBJ_NE zero) THEN BLOCK(VAL(alt) === (REF(altOpt) DOT altGet), nextBody) ENDIF, - REF(keepGoing) - ))) - } - - override def flatMap(opt: Tree, fun: Tree): Tree = fun match { - case Function(List(x: ValDef), body) => - val tp = appliedType(matchingMonadType, List(x.symbol.tpe)) - val vs = freshSym(opt.pos, tp, "o") - val isEmpty = tp member vpmName.isEmpty - val get = tp member vpmName.get - val v = VAL(vs) === opt - - BLOCK( - v, - IF (vs DOT isEmpty) THEN zero ELSE typedSubst(body, List(x.symbol), List(vs DOT get)) // must be isEmpty and get as we don't control the target of the call (could be the result of a user-defined extractor) - ) - case _ => println("huh?") - (opt DOT vpmName.flatMap)(fun) - } - - override def flatMapCond(cond: Tree, res: Tree, nextBinder: Symbol, nextBinderTp: Type, next: Tree): Tree = - IF (cond) THEN BLOCK( - VAL(nextBinder) === res, - next - ) ELSE zero - } - - def genTypeApply(tfun: Tree, args: Type*): Tree = if(args contains NoType) tfun else TypeApply(tfun, args.toList map TypeTree) - // def genTyped(t: Tree, tp: Type): Tree = if(tp == NoType) t else Typed(t, TypeTree(repackExistential(tp))) + def matchingStrategy: Tree + def typed(tree: Tree, mode: Int, pt: Type): Tree // implemented in MatchTranslator } diff --git a/src/library/scala/MatchingStrategy.scala b/src/library/scala/MatchingStrategy.scala index 2c713e4850..d11598bad6 100644 --- a/src/library/scala/MatchingStrategy.scala +++ b/src/library/scala/MatchingStrategy.scala @@ -1,33 +1,27 @@ package scala abstract class MatchingStrategy[M[+x]] { + // runs the matcher on the given input + def runOrElse[T, U](in: T)(matcher: T => M[U]): U + def zero: M[Nothing] def one[T](x: T): M[T] - def guard[T](cond: Boolean, then: => T): M[T] // = if(cond) one(then) else zero - def altFlatMap[T, U](f: T => M[U])(a: M[U], b: M[T]): M[U] // = a orElse b.flatMap(f) -- can't easily&efficiently express M[T] should have flatMap and orElse - def runOrElse[T, U](x: T)(f: T => M[U]): U - def isSuccess[T, U](x: T)(f: T => M[U]): Boolean - - // find the first alternative to successfully flatMap f - // to avoid code explosion due to alternatives - // TODO: should be alts: => M[T]* - def or[T, U](f: T => M[U], alts: M[T]*) = (alts foldLeft (zero: M[U]))(altFlatMap(f)) + def guard[T](cond: Boolean, then: => T): M[T] + def isSuccess[T, U](x: T)(f: T => M[U]): Boolean // used for isDefinedAt def caseResult[T](x: T): M[T] = one(x) // used as a marker to distinguish the RHS of a case (case pat => RHS) and intermediate successes - // when deriving a partial function from a pattern match, we need to - // distinguish the RHS of a case, which should not be evaluated when computing isDefinedAt, + // when deriving a partial function from a pattern match, + // we need to distinguish the RHS of a case, which should not be evaluated when computing isDefinedAt, // from an intermediate result (which must be computed) - } object MatchingStrategy { implicit object OptionMatchingStrategy extends MatchingStrategy[Option] { type M[+x] = Option[x] - @inline def guard[T](cond: Boolean, then: => T): M[T] = if(cond) Some(then) else None + @inline def runOrElse[T, U](x: T)(f: T => M[U]): U = f(x) getOrElse (throw new MatchError(x)) @inline def zero: M[Nothing] = None @inline def one[T](x: T): M[T] = Some(x) - @inline def altFlatMap[T, U](f: T => M[U])(a: M[U], b: M[T]): M[U] = a orElse b.flatMap(f) - @inline def runOrElse[T, U](x: T)(f: T => M[U]): U = f(x) getOrElse (throw new MatchError(x)) + @inline def guard[T](cond: Boolean, then: => T): M[T] = if(cond) Some(then) else None @inline def isSuccess[T, U](x: T)(f: T => M[U]): Boolean = !f(x).isEmpty } } \ No newline at end of file -- cgit v1.2.3 From 460bbc1276fb4ba83b9bcbdc7f7ba475b352b7c6 Mon Sep 17 00:00:00 2001 From: Szabolcs Berecz Date: Sun, 25 Dec 2011 01:37:02 +0100 Subject: fixes #5104 and related NaN ordering inconsistencies The bug was caused by the inconsistency between j.l.Math.min() and j.l.Double.compareTo() wrt NaN (j.l.Math.min() considers NaN to be less than any other value while j.l.Double.compareTo() says it's greater...) The fix changes Ordering.{FloatOrdering,DoubleOrdering) to base it's results on primitive comparisons and math.{min,max} instead of j.l.{Float,Double}.compareTo() --- src/library/scala/math/Ordering.scala | 40 ++++++++++ test/files/scalacheck/nan-ordering.scala | 130 +++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 test/files/scalacheck/nan-ordering.scala (limited to 'src/library') diff --git a/src/library/scala/math/Ordering.scala b/src/library/scala/math/Ordering.scala index d007ae3780..8fc74a9d5d 100644 --- a/src/library/scala/math/Ordering.scala +++ b/src/library/scala/math/Ordering.scala @@ -262,12 +262,52 @@ object Ordering extends LowPriorityOrderingImplicits { implicit object Long extends LongOrdering trait FloatOrdering extends Ordering[Float] { + outer => + def compare(x: Float, y: Float) = java.lang.Float.compare(x, y) + + override def lteq(x: Float, y: Float): Boolean = x <= y + override def gteq(x: Float, y: Float): Boolean = x >= y + override def lt(x: Float, y: Float): Boolean = x < y + override def gt(x: Float, y: Float): Boolean = x > y + override def equiv(x: Float, y: Float): Boolean = x == y + override def max(x: Float, y: Float): Float = math.max(x, y) + override def min(x: Float, y: Float): Float = math.min(x, y) + + override def reverse: Ordering[Float] = new FloatOrdering { + override def reverse = outer + override def compare(x: Float, y: Float) = outer.compare(y, x) + + override def lteq(x: Float, y: Float): Boolean = outer.lteq(y, x) + override def gteq(x: Float, y: Float): Boolean = outer.gteq(y, x) + override def lt(x: Float, y: Float): Boolean = outer.lt(y, x) + override def gt(x: Float, y: Float): Boolean = outer.gt(y, x) + } } implicit object Float extends FloatOrdering trait DoubleOrdering extends Ordering[Double] { + outer => + def compare(x: Double, y: Double) = java.lang.Double.compare(x, y) + + override def lteq(x: Double, y: Double): Boolean = x <= y + override def gteq(x: Double, y: Double): Boolean = x >= y + override def lt(x: Double, y: Double): Boolean = x < y + override def gt(x: Double, y: Double): Boolean = x > y + override def equiv(x: Double, y: Double): Boolean = x == y + override def max(x: Double, y: Double): Double = math.max(x, y) + override def min(x: Double, y: Double): Double = math.min(x, y) + + override def reverse: Ordering[Double] = new DoubleOrdering { + override def reverse = outer + override def compare(x: Double, y: Double) = outer.compare(y, x) + + override def lteq(x: Double, y: Double): Boolean = outer.lteq(y, x) + override def gteq(x: Double, y: Double): Boolean = outer.gteq(y, x) + override def lt(x: Double, y: Double): Boolean = outer.lt(y, x) + override def gt(x: Double, y: Double): Boolean = outer.gt(y, x) + } } implicit object Double extends DoubleOrdering diff --git a/test/files/scalacheck/nan-ordering.scala b/test/files/scalacheck/nan-ordering.scala new file mode 100644 index 0000000000..2094a46e37 --- /dev/null +++ b/test/files/scalacheck/nan-ordering.scala @@ -0,0 +1,130 @@ +import org.scalacheck._ +import Gen._ +import Prop._ + +object Test extends Properties("NaN-Ordering") { + + val specFloats: Gen[Float] = oneOf( + Float.MaxValue, + Float.MinPositiveValue, + Float.MinValue, + Float.NaN, + Float.NegativeInfinity, + Float.PositiveInfinity, + -0.0f, + +0.0f + ) + + property("Float min") = forAll(specFloats, specFloats) { (d1, d2) => { + val mathmin = math.min(d1, d2) + val numericmin = d1 min d2 + mathmin == numericmin || mathmin.isNaN && numericmin.isNaN + } + } + + property("Float max") = forAll(specFloats, specFloats) { (d1, d2) => { + val mathmax = math.max(d1, d2) + val numericmax = d1 max d2 + mathmax == numericmax || mathmax.isNaN && numericmax.isNaN + } + } + + val numFloat = implicitly[Numeric[Float]] + + property("Float lt") = forAll(specFloats, specFloats) { (d1, d2) => numFloat.lt(d1, d2) == d1 < d2 } + + property("Float lteq") = forAll(specFloats, specFloats) { (d1, d2) => numFloat.lteq(d1, d2) == d1 <= d2 } + + property("Float gt") = forAll(specFloats, specFloats) { (d1, d2) => numFloat.gt(d1, d2) == d1 > d2 } + + property("Float gteq") = forAll(specFloats, specFloats) { (d1, d2) => numFloat.gteq(d1, d2) == d1 >= d2 } + + property("Float equiv") = forAll(specFloats, specFloats) { (d1, d2) => numFloat.equiv(d1, d2) == (d1 == d2) } + + property("Float reverse.min") = forAll(specFloats, specFloats) { (d1, d2) => { + val mathmin = math.min(d1, d2) + val numericmin = numFloat.reverse.min(d1, d2) + mathmin == numericmin || mathmin.isNaN && numericmin.isNaN + } + } + + property("Float reverse.max") = forAll(specFloats, specFloats) { (d1, d2) => { + val mathmax = math.max(d1, d2) + val numericmax = numFloat.reverse.max(d1, d2) + mathmax == numericmax || mathmax.isNaN && numericmax.isNaN + } + } + + property("Float reverse.lt") = forAll(specFloats, specFloats) { (d1, d2) => numFloat.reverse.lt(d1, d2) == d2 < d1 } + + property("Float reverse.lteq") = forAll(specFloats, specFloats) { (d1, d2) => numFloat.reverse.lteq(d1, d2) == d2 <= d1 } + + property("Float reverse.gt") = forAll(specFloats, specFloats) { (d1, d2) => numFloat.reverse.gt(d1, d2) == d2 > d1 } + + property("Float reverse.gteq") = forAll(specFloats, specFloats) { (d1, d2) => numFloat.reverse.gteq(d1, d2) == d2 >= d1 } + + property("Float reverse.equiv") = forAll(specFloats, specFloats) { (d1, d2) => numFloat.reverse.equiv(d1, d2) == (d1 == d2) } + + + val specDoubles: Gen[Double] = oneOf( + Double.MaxValue, + Double.MinPositiveValue, + Double.MinValue, + Double.NaN, + Double.NegativeInfinity, + Double.PositiveInfinity, + -0.0, + +0.0 + ) + + // ticket #5104 + property("Double min") = forAll(specDoubles, specDoubles) { (d1, d2) => { + val mathmin = math.min(d1, d2) + val numericmin = d1 min d2 + mathmin == numericmin || mathmin.isNaN && numericmin.isNaN + } + } + + property("Double max") = forAll(specDoubles, specDoubles) { (d1, d2) => { + val mathmax = math.max(d1, d2) + val numericmax = d1 max d2 + mathmax == numericmax || mathmax.isNaN && numericmax.isNaN + } + } + + val numDouble = implicitly[Numeric[Double]] + + property("Double lt") = forAll(specDoubles, specDoubles) { (d1, d2) => numDouble.lt(d1, d2) == d1 < d2 } + + property("Double lteq") = forAll(specDoubles, specDoubles) { (d1, d2) => numDouble.lteq(d1, d2) == d1 <= d2 } + + property("Double gt") = forAll(specDoubles, specDoubles) { (d1, d2) => numDouble.gt(d1, d2) == d1 > d2 } + + property("Double gteq") = forAll(specDoubles, specDoubles) { (d1, d2) => numDouble.gteq(d1, d2) == d1 >= d2 } + + property("Double equiv") = forAll(specDoubles, specDoubles) { (d1, d2) => numDouble.equiv(d1, d2) == (d1 == d2) } + + property("Double reverse.min") = forAll(specDoubles, specDoubles) { (d1, d2) => { + val mathmin = math.min(d1, d2) + val numericmin = numDouble.reverse.min(d1, d2) + mathmin == numericmin || mathmin.isNaN && numericmin.isNaN + } + } + + property("Double reverse.max") = forAll(specDoubles, specDoubles) { (d1, d2) => { + val mathmax = math.max(d1, d2) + val numericmax = numDouble.reverse.max(d1, d2) + mathmax == numericmax || mathmax.isNaN && numericmax.isNaN + } + } + + property("Double reverse.lt") = forAll(specDoubles, specDoubles) { (d1, d2) => numDouble.reverse.lt(d1, d2) == d2 < d1 } + + property("Double reverse.lteq") = forAll(specDoubles, specDoubles) { (d1, d2) => numDouble.reverse.lteq(d1, d2) == d2 <= d1 } + + property("Double reverse.gt") = forAll(specDoubles, specDoubles) { (d1, d2) => numDouble.reverse.gt(d1, d2) == d2 > d1 } + + property("Double reverse.gteq") = forAll(specDoubles, specDoubles) { (d1, d2) => numDouble.reverse.gteq(d1, d2) == d2 >= d1 } + + property("Double reverse.equiv") = forAll(specDoubles, specDoubles) { (d1, d2) => numDouble.reverse.equiv(d1, d2) == (d1 == d2) } +} -- cgit v1.2.3 From b2b59a124a2a8adf8e88c1e692c96263e0955b16 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 21 Dec 2011 12:48:39 -0800 Subject: Better hunting for tools.jar. Attempting to make the repl find it based on fewer clues so all can enjoy the javap goodness. --- src/compiler/scala/tools/nsc/Properties.scala | 5 --- .../scala/tools/nsc/interpreter/ILoop.scala | 46 +++++++++++++++------- src/compiler/scala/tools/util/Javap.scala | 22 +++++++---- src/library/scala/util/Properties.scala | 5 +++ 4 files changed, 51 insertions(+), 27 deletions(-) (limited to 'src/library') diff --git a/src/compiler/scala/tools/nsc/Properties.scala b/src/compiler/scala/tools/nsc/Properties.scala index d33be5bca0..c83ccfeef1 100644 --- a/src/compiler/scala/tools/nsc/Properties.scala +++ b/src/compiler/scala/tools/nsc/Properties.scala @@ -22,9 +22,4 @@ object Properties extends scala.util.PropertiesTrait { // derived values def isEmacsShell = propOrEmpty("env.emacs") != "" def fileEndings = fileEndingString.split("""\|""").toList - - // System property java.home is the JRE root. - // Environment variable JAVA_HOME is (supposed to be) the jdk root. - // We need the latter to find javac, tools.jar, etc. - def jdkHome = envOrElse("JAVA_HOME", javaHome) } diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala index 3ddbffa75e..2159ecbb8a 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala @@ -11,6 +11,7 @@ import java.io.{ BufferedReader, FileReader } import java.util.concurrent.locks.ReentrantLock import scala.sys.process.Process import session._ +import scala.util.Properties.{ jdkHome, javaVersion } import scala.tools.util.{ Signallable, Javap } import scala.annotation.tailrec import scala.collection.mutable.ListBuffer @@ -377,14 +378,29 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) } } + private def findToolsJar() = { + val jdkPath = Directory(jdkHome) + val jar = jdkPath / "lib" / "tools.jar" toFile; + + if (jar isFile) + Some(jar) + else if (jdkPath.isDirectory) + jdkPath.deepFiles find (_.name == "tools.jar") + else None + } private def addToolsJarToLoader() = { - val javaHome = Directory(sys.env("JAVA_HOME")) - val tools = javaHome / "lib" / "tools.jar" - if (tools.isFile) { - echo("Found tools.jar, adding for use by javap.") - ScalaClassLoader.fromURLs(Seq(tools.toURL), intp.classLoader) + val cl = findToolsJar match { + case Some(tools) => ScalaClassLoader.fromURLs(Seq(tools.toURL), intp.classLoader) + case _ => intp.classLoader + } + if (Javap.isAvailable(cl)) { + repldbg(":javap available.") + cl + } + else { + repldbg(":javap unavailable: no tools.jar at " + jdkHome) + intp.classLoader } - else intp.classLoader } protected def newJavap() = new JavapClass(addToolsJarToLoader(), new IMain.ReplStrippingWriter(intp)) { @@ -431,14 +447,16 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) private def javapCommand(line: String): Result = { if (javap == null) - return ":javap unavailable on this platform." - if (line == "") - return ":javap [-lcsvp] [path1 path2 ...]" - - javap(words(line)) foreach { res => - if (res.isError) return "Failed: " + res.value - else res.show() - } + ":javap unavailable, no tools.jar at %s. Set JDK_HOME.".format(jdkHome) + else if (javaVersion startsWith "1.7") + ":javap not yet working with java 1.7" + else if (line == "") + ":javap [-lcsvp] [path1 path2 ...]" + else + javap(words(line)) foreach { res => + if (res.isError) return "Failed: " + res.value + else res.show() + } } private def keybindingsCommand(): Result = { if (in.keyBindings.isEmpty) "Key bindings unavailable." diff --git a/src/compiler/scala/tools/util/Javap.scala b/src/compiler/scala/tools/util/Javap.scala index 0c359a2619..6d5988d1dd 100644 --- a/src/compiler/scala/tools/util/Javap.scala +++ b/src/compiler/scala/tools/util/Javap.scala @@ -36,17 +36,21 @@ class JavapClass( lazy val parser = new JpOptions - val EnvClass = loader.tryToInitializeClass[FakeEnvironment](Env).orNull - val EnvCtr = EnvClass.getConstructor(List[Class[_]](): _*) - + val EnvClass = loader.tryToInitializeClass[FakeEnvironment](Env).orNull val PrinterClass = loader.tryToInitializeClass[FakePrinter](Printer).orNull - val PrinterCtr = PrinterClass.getConstructor(classOf[InputStream], classOf[PrintWriter], EnvClass) + private def failed = (EnvClass eq null) || (PrinterClass eq null) + + val PrinterCtr = ( + if (failed) null + else PrinterClass.getConstructor(classOf[InputStream], classOf[PrintWriter], EnvClass) + ) def findBytes(path: String): Array[Byte] = tryFile(path) getOrElse tryClass(path) def apply(args: Seq[String]): List[JpResult] = { - args.toList filterNot (_ startsWith "-") map { path => + if (failed) Nil + else args.toList filterNot (_ startsWith "-") map { path => val bytes = findBytes(path) if (bytes.isEmpty) new JpError("Could not find class bytes for '%s'".format(path)) else new JpSuccess(newPrinter(new ByteArrayInputStream(bytes), newEnv(args))) @@ -54,12 +58,14 @@ class JavapClass( } def newPrinter(in: InputStream, env: FakeEnvironment): FakePrinter = - PrinterCtr.newInstance(in, printWriter, env) + if (failed) null + else PrinterCtr.newInstance(in, printWriter, env) def newEnv(opts: Seq[String]): FakeEnvironment = { - val env: FakeEnvironment = EnvClass.newInstance() + lazy val env: FakeEnvironment = EnvClass.newInstance() - parser(opts) foreach { case (name, value) => + if (failed) null + else parser(opts) foreach { case (name, value) => val field = EnvClass getDeclaredField name field setAccessible true field.set(env, value.asInstanceOf[AnyRef]) diff --git a/src/library/scala/util/Properties.scala b/src/library/scala/util/Properties.scala index 998661895b..22de5544a8 100644 --- a/src/library/scala/util/Properties.scala +++ b/src/library/scala/util/Properties.scala @@ -142,6 +142,11 @@ private[scala] trait PropertiesTrait { */ def isWin = osName startsWith "Windows" def isMac = javaVendor startsWith "Apple" + + // This is looking for javac, tools.jar, etc. + // Tries JDK_HOME first, then the more common but likely jre JAVA_HOME, + // and finally the system property based javaHome. + def jdkHome = envOrElse("JDK_HOME", envOrElse("JAVA_HOME", javaHome)) def versionMsg = "Scala %s %s -- %s".format(propCategory, versionString, copyrightString) def scalaCmd = if (isWin) "scala.bat" else "scala" -- cgit v1.2.3 From 6150b589993fc58817d6d1d2e4326c8ff135a0ea Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Fri, 30 Dec 2011 21:06:46 -0800 Subject: Low-level optimization. Eliminated a bunch of unnecessary array expense. --- src/compiler/scala/reflect/internal/Names.scala | 2 +- .../nsc/symtab/classfile/ClassfileParser.scala | 25 +++++++++++----------- src/library/scala/io/Codec.scala | 7 +++--- .../scala/tools/scalap/ByteArrayReader.scala | 2 +- .../scalax/rules/scalasig/ClassFileParser.scala | 7 ++++-- 5 files changed, 23 insertions(+), 20 deletions(-) (limited to 'src/library') diff --git a/src/compiler/scala/reflect/internal/Names.scala b/src/compiler/scala/reflect/internal/Names.scala index 11be9c80d1..8453b1e758 100644 --- a/src/compiler/scala/reflect/internal/Names.scala +++ b/src/compiler/scala/reflect/internal/Names.scala @@ -93,7 +93,7 @@ trait Names extends api.Names { /** Create a term name from the UTF8 encoded bytes in bs[offset..offset+len-1]. */ def newTermName(bs: Array[Byte], offset: Int, len: Int): TermName = { - val chars = Codec fromUTF8 bs.slice(offset, offset + len) + val chars = Codec.fromUTF8(bs, offset, len) newTermName(chars, 0, chars.length) } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index b73eaff524..94eb6d2afd 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -365,6 +365,13 @@ abstract class ClassfileParser { case arr: Type => Constant(arr) } } + + private def getSubArray(bytes: Array[Byte]): Array[Byte] = { + val decodedLength = ByteCodecs.decode(bytes) + val arr = new Array[Byte](decodedLength) + System.arraycopy(bytes, 0, arr, 0, decodedLength) + arr + } def getBytes(index: Int): Array[Byte] = { if (index <= 0 || len <= index) errorBadIndex(index) @@ -372,11 +379,10 @@ abstract class ClassfileParser { if (value eq null) { val start = starts(index) if (in.buf(start).toInt != CONSTANT_UTF8) errorBadTag(start) - val len = in.getChar(start + 1) + val len = in.getChar(start + 1) val bytes = new Array[Byte](len) - Array.copy(in.buf, start + 3, bytes, 0, len) - val decodedLength = ByteCodecs.decode(bytes) - value = bytes.take(decodedLength) + System.arraycopy(in.buf, start + 3, bytes, 0, len) + value = getSubArray(bytes) values(index) = value } value @@ -394,9 +400,7 @@ abstract class ClassfileParser { val len = in.getChar(start + 1) bytesBuffer ++= in.buf.view(start + 3, start + 3 + len) } - val bytes = bytesBuffer.toArray - val decodedLength = ByteCodecs.decode(bytes) - value = bytes.take(decodedLength) + value = getSubArray(bytesBuffer.toArray) values(indices.head) = value } value @@ -968,7 +972,7 @@ abstract class ClassfileParser { Some(ScalaSigBytes(pool getBytes in.nextChar)) } - def parseScalaLongSigBytes: Option[ScalaSigBytes] = try { + def parseScalaLongSigBytes: Option[ScalaSigBytes] = { val tag = in.nextByte.toChar assert(tag == ARRAY_TAG) val stringCount = in.nextChar @@ -980,11 +984,6 @@ abstract class ClassfileParser { } Some(ScalaSigBytes(pool.getBytes(entries.toList))) } - catch { - case e: Throwable => - e.printStackTrace - throw e - } /** Parse and return a single annotation. If it is malformed, * return None. diff --git a/src/library/scala/io/Codec.scala b/src/library/scala/io/Codec.scala index 8533ed493f..fa17f3eaeb 100644 --- a/src/library/scala/io/Codec.scala +++ b/src/library/scala/io/Codec.scala @@ -98,10 +98,11 @@ object Codec extends LowPriorityCodecImplicits { } @migration("This method was previously misnamed `toUTF8`. Converts from Array[Byte] to Array[Char].", "2.9.0") - def fromUTF8(bytes: Array[Byte]): Array[Char] = { - val bbuffer = java.nio.ByteBuffer wrap bytes + def fromUTF8(bytes: Array[Byte]): Array[Char] = fromUTF8(bytes, 0, bytes.length) + def fromUTF8(bytes: Array[Byte], offset: Int, len: Int): Array[Char] = { + val bbuffer = java.nio.ByteBuffer.wrap(bytes, offset, len) val cbuffer = UTF8.charSet decode bbuffer - val chars = new Array[Char](cbuffer.remaining()) + val chars = new Array[Char](cbuffer.remaining()) cbuffer get chars chars diff --git a/src/scalap/scala/tools/scalap/ByteArrayReader.scala b/src/scalap/scala/tools/scalap/ByteArrayReader.scala index 73220d1048..466ec53c79 100644 --- a/src/scalap/scala/tools/scalap/ByteArrayReader.scala +++ b/src/scalap/scala/tools/scalap/ByteArrayReader.scala @@ -72,7 +72,7 @@ class ByteArrayReader(content: Array[Byte]) { /** read an UTF8 encoded string */ def nextUTF8(len: Int): String = { - val cs = scala.io.Codec.fromUTF8(buf.slice(bp, bp + len)) + val cs = scala.io.Codec.fromUTF8(buf, bp, len) bp += len new String(cs) } diff --git a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala index d53d8e1fc1..84f28af7ce 100644 --- a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala @@ -65,8 +65,11 @@ class ByteCode(val bytes : Array[Byte], val pos : Int, val length : Int) { * stores and array of bytes for the decompiler */ def fromUTF8StringAndBytes = { - val chunk: Array[Byte] = bytes drop pos take length - StringBytesPair(io.Codec.fromUTF8(chunk).mkString, chunk) + val chunk: Array[Byte] = new Array[Byte](length) + System.arraycopy(bytes, pos, chunk, 0, length) + val str = new String(io.Codec.fromUTF8(bytes, pos, length)) + + StringBytesPair(str, chunk) } def byte(i : Int) = bytes(pos) & 0xFF -- cgit v1.2.3 From 82c793a438c7bd802daf96c8b2012f54fbd737ba Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Fri, 23 Dec 2011 03:52:03 -0800 Subject: More performance work. Custom versions of collections which methods which operate on 2 or 3 collections. Eliminated most users of zip/zipped. Cleaned up the kinds checking code somewhat. Reduced the number of silent typechecks being performed at named argument sites. --- src/compiler/scala/reflect/internal/Kinds.scala | 223 ++++++++++++++++ .../scala/reflect/internal/SymbolTable.scala | 2 + src/compiler/scala/reflect/internal/TreeInfo.scala | 64 +++-- src/compiler/scala/reflect/internal/Types.scala | 297 ++++++--------------- .../scala/reflect/internal/util/Collections.scala | 138 ++++++++++ src/compiler/scala/tools/nsc/ast/Trees.scala | 13 +- .../scala/tools/nsc/symtab/SymbolTable.scala | 3 +- .../scala/tools/nsc/transform/LiftCode.scala | 2 +- .../tools/nsc/transform/SpecializeTypes.scala | 16 +- .../scala/tools/nsc/transform/UnCurry.scala | 8 +- .../scala/tools/nsc/typechecker/Infer.scala | 80 ++---- .../tools/nsc/typechecker/NamesDefaults.scala | 243 ++++++++--------- .../scala/tools/nsc/typechecker/RefChecks.scala | 10 +- .../tools/nsc/typechecker/SuperAccessors.scala | 2 +- .../scala/tools/nsc/typechecker/Typers.scala | 25 +- src/compiler/scala/tools/util/EditDistance.scala | 38 ++- src/library/scala/collection/LinearSeqLike.scala | 6 + test/files/neg/names-defaults-neg.check | 15 +- 18 files changed, 705 insertions(+), 480 deletions(-) create mode 100644 src/compiler/scala/reflect/internal/Kinds.scala create mode 100644 src/compiler/scala/reflect/internal/util/Collections.scala (limited to 'src/library') diff --git a/src/compiler/scala/reflect/internal/Kinds.scala b/src/compiler/scala/reflect/internal/Kinds.scala new file mode 100644 index 0000000000..15fcb5f94d --- /dev/null +++ b/src/compiler/scala/reflect/internal/Kinds.scala @@ -0,0 +1,223 @@ +/* NSC -- new scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.reflect +package internal + +import scala.collection.{ mutable, immutable } +import scala.tools.util.StringOps.{ countAsString, countElementsAsString } + +trait Kinds { + self: SymbolTable => + + import definitions._ + + private type SymPair = ((Symbol, Symbol)) // ((Argument, Parameter)) + + case class KindErrors( + arity: List[SymPair] = Nil, + variance: List[SymPair] = Nil, + strictness: List[SymPair] = Nil + ) { + def isEmpty = arity.isEmpty && variance.isEmpty && strictness.isEmpty + + def arityError(syms: SymPair) = copy(arity = arity :+ syms) + def varianceError(syms: SymPair) = copy(variance = variance :+ syms) + def strictnessError(syms: SymPair) = copy(strictness = strictness :+ syms) + + def ++(errs: KindErrors) = KindErrors( + arity ++ errs.arity, + variance ++ errs.variance, + strictness ++ errs.strictness + ) + // @M TODO this method is duplicated all over the place (varianceString) + private def varStr(s: Symbol): String = + if (s.isCovariant) "covariant" + else if (s.isContravariant) "contravariant" + else "invariant"; + + private def qualify(a0: Symbol, b0: Symbol): String = if (a0.toString != b0.toString) "" else { + if((a0 eq b0) || (a0.owner eq b0.owner)) "" + else { + var a = a0; var b = b0 + while (a.owner.name == b.owner.name) { a = a.owner; b = b.owner} + if (a.locationString ne "") " (" + a.locationString.trim + ")" else "" + } + } + private def kindMessage(a: Symbol, p: Symbol)(f: (String, String) => String): String = + f(a+qualify(a,p), p+qualify(p,a)) + + private def strictnessMessage(a: Symbol, p: Symbol) = + kindMessage(a, p)("%s's bounds %s are stricter than %s's declared bounds %s".format( + _, a.info, _, p.info)) + + private def varianceMessage(a: Symbol, p: Symbol) = + kindMessage(a, p)("%s is %s, but %s is declared %s".format(_, varStr(a), _, varStr(p))) + + private def arityMessage(a: Symbol, p: Symbol) = + kindMessage(a, p)("%s has %s, but %s has %s".format( + _, countElementsAsString(a.typeParams.length, "type parameter"), + _, countAsString(p.typeParams.length)) + ) + + def errorMessage(targ: Type, tparam: Symbol): String = ( + (targ+"'s type parameters do not match "+tparam+"'s expected parameters: ") + + (arity map { case (a, p) => arityMessage(a, p) } mkString ", ") + + (variance map { case (a, p) => varianceMessage(a, p) } mkString ", ") + + (strictness map { case (a, p) => strictnessMessage(a, p) } mkString ", ") + ) + } + val NoKindErrors = KindErrors(Nil, Nil, Nil) + + // TODO: this desperately needs to be cleaned up + // plan: split into kind inference and subkinding + // every Type has a (cached) Kind + def kindsConform(tparams: List[Symbol], targs: List[Type], pre: Type, owner: Symbol): Boolean = + checkKindBounds0(tparams, targs, pre, owner, false).isEmpty + + /** Check whether `sym1`'s variance conforms to `sym2`'s variance. + * + * If `sym2` is invariant, `sym1`'s variance is irrelevant. Otherwise they must be equal. + */ + private def variancesMatch(sym1: Symbol, sym2: Symbol) = ( + sym2.variance==0 + || sym1.variance==sym2.variance + ) + + /** Check well-kindedness of type application (assumes arities are already checked) -- @M + * + * This check is also performed when abstract type members become concrete (aka a "type alias") -- then tparams.length==1 + * (checked one type member at a time -- in that case, prefix is the name of the type alias) + * + * Type application is just like value application: it's "contravariant" in the sense that + * the type parameters of the supplied type arguments must conform to the type parameters of + * the required type parameters: + * - their bounds must be less strict + * - variances must match (here, variances are absolute, the variance of a type parameter does not influence the variance of its higher-order parameters) + * - @M TODO: are these conditions correct,sufficient&necessary? + * + * e.g. class Iterable[t, m[+x <: t]] --> the application Iterable[Int, List] is okay, since + * List's type parameter is also covariant and its bounds are weaker than <: Int + */ + def checkKindBounds0( + tparams: List[Symbol], + targs: List[Type], + pre: Type, + owner: Symbol, + explainErrors: Boolean + ): List[(Type, Symbol, KindErrors)] = { + + // instantiate type params that come from outside the abstract type we're currently checking + def transform(tp: Type, clazz: Symbol): Type = + tp.asSeenFrom(pre, clazz) + def transformedBounds(p: Symbol, o: Symbol) = + transform(p.info.instantiateTypeParams(tparams, targs).bounds, o) + + // check that the type parameters hkargs to a higher-kinded type conform to the + // expected params hkparams + def checkKindBoundsHK( + hkargs: List[Symbol], + arg: Symbol, + param: Symbol, + paramowner: Symbol, + underHKParams: List[Symbol], + withHKArgs: List[Symbol] + ): KindErrors = { + + var kindErrors: KindErrors = NoKindErrors + def bindHKParams(tp: Type) = tp.substSym(underHKParams, withHKArgs) + // @M sometimes hkargs != arg.typeParams, the symbol and the type may + // have very different type parameters + val hkparams = param.typeParams + def kindCheck(cond: Boolean, f: KindErrors => KindErrors) { + if (!cond) + kindErrors = f(kindErrors) + } + + if (settings.debug.value) { + log("checkKindBoundsHK expected: "+ param +" with params "+ hkparams +" by definition in "+ paramowner) + log("checkKindBoundsHK supplied: "+ arg +" with params "+ hkargs +" from "+ owner) + log("checkKindBoundsHK under params: "+ underHKParams +" with args "+ withHKArgs) + } + + if (!sameLength(hkargs, hkparams)) { + // Any and Nothing are kind-overloaded + if (arg == AnyClass || arg == NothingClass) NoKindErrors + // shortcut: always set error, whether explainTypesOrNot + else return kindErrors.arityError(arg -> param) + } + else foreach2(hkargs, hkparams) { (hkarg, hkparam) => + if (hkparam.typeParams.isEmpty && hkarg.typeParams.isEmpty) { // base-case: kind * + kindCheck(variancesMatch(hkarg, hkparam), _ varianceError (hkarg -> hkparam)) + // instantiateTypeParams(tparams, targs) + // higher-order bounds, may contain references to type arguments + // substSym(hkparams, hkargs) + // these types are going to be compared as types of kind * + // + // Their arguments use different symbols, but are + // conceptually the same. Could also replace the types by + // polytypes, but can't just strip the symbols, as ordering + // is lost then. + val declaredBounds = transformedBounds(hkparam, paramowner) + val declaredBoundsInst = bindHKParams(declaredBounds) + val argumentBounds = transform(hkarg.info.bounds, owner) + + kindCheck(declaredBoundsInst <:< argumentBounds, _ strictnessError (hkarg -> hkparam)) + + debuglog( + "checkKindBoundsHK base case: " + hkparam + + " declared bounds: " + declaredBounds + + " after instantiating earlier hkparams: " + declaredBoundsInst + "\n" + + "checkKindBoundsHK base case: "+ hkarg + + " has bounds: " + argumentBounds + ) + } + else { + debuglog("checkKindBoundsHK recursing to compare params of "+ hkparam +" with "+ hkarg) + kindErrors ++= checkKindBoundsHK( + hkarg.typeParams, + hkarg, + hkparam, + paramowner, + underHKParams ++ hkparam.typeParams, + withHKArgs ++ hkarg.typeParams + ) + } + if (!explainErrors && !kindErrors.isEmpty) + return kindErrors + } + if (explainErrors) kindErrors + else NoKindErrors + } + + if (settings.debug.value && (tparams.nonEmpty || targs.nonEmpty)) log( + "checkKindBounds0(" + tparams + ", " + targs + ", " + pre + ", " + + owner + ", " + explainErrors + ")" + ) + + flatMap2(tparams, targs) { (tparam, targ) => + // Prevent WildcardType from causing kind errors, as typevars may be higher-order + if (targ == WildcardType) Nil else { + // force symbol load for #4205 + targ.typeSymbolDirect.info + // @M must use the typeParams of the *type* targ, not of the *symbol* of targ!! + val tparamsHO = targ.typeParams + if (targ.isHigherKinded || tparam.typeParams.nonEmpty) { + // NOTE: *not* targ.typeSymbol, which normalizes + val kindErrors = checkKindBoundsHK( + tparamsHO, targ.typeSymbolDirect, tparam, + tparam.owner, tparam.typeParams, tparamsHO + ) + if (kindErrors.isEmpty) Nil else { + if (explainErrors) List((targ, tparam, kindErrors)) + // Return as soon as an error is seen if there's nothing to explain. + else return List((NoType, NoSymbol, NoKindErrors)) + } + } + else Nil + } + } + } +} \ No newline at end of file diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala index 29ac5fe539..5be69e06ad 100644 --- a/src/compiler/scala/reflect/internal/SymbolTable.scala +++ b/src/compiler/scala/reflect/internal/SymbolTable.scala @@ -10,9 +10,11 @@ import scala.collection.{ mutable, immutable } import util._ abstract class SymbolTable extends api.Universe + with Collections with Names with Symbols with Types + with Kinds with Scopes with Definitions with Constants diff --git a/src/compiler/scala/reflect/internal/TreeInfo.scala b/src/compiler/scala/reflect/internal/TreeInfo.scala index 1dc93a7add..14bf36fb47 100644 --- a/src/compiler/scala/reflect/internal/TreeInfo.scala +++ b/src/compiler/scala/reflect/internal/TreeInfo.scala @@ -107,7 +107,15 @@ abstract class TreeInfo { @deprecated("Use isExprSafeToInline instead", "2.10.0") def isPureExpr(tree: Tree) = isExprSafeToInline(tree) - def zipMethodParamsAndArgs(params: List[Symbol], args: List[Tree]): List[(Symbol, Tree)] = { + def zipMethodParamsAndArgs(params: List[Symbol], args: List[Tree]): List[(Symbol, Tree)] = + mapMethodParamsAndArgs(params, args)((param, arg) => ((param, arg))) + + def mapMethodParamsAndArgs[R](params: List[Symbol], args: List[Tree])(f: (Symbol, Tree) => R): List[R] = { + val b = List.newBuilder[R] + foreachMethodParamAndArg(params, args)((param, arg) => b += f(param, arg)) + b.result + } + def foreachMethodParamAndArg(params: List[Symbol], args: List[Tree])(f: (Symbol, Tree) => Unit): Boolean = { val plen = params.length val alen = args.length def fail() = { @@ -116,27 +124,29 @@ abstract class TreeInfo { " params = " + params + "\n" + " args = " + args + "\n" ) - params zip args + false } - if (plen == alen) params zip args - else if (params.isEmpty) fail + if (plen == alen) foreach2(params, args)(f) + else if (params.isEmpty) return fail else if (isVarArgsList(params)) { val plenInit = plen - 1 if (alen == plenInit) { if (alen == 0) Nil // avoid calling mismatched zip - else params.init zip args + else foreach2(params.init, args)(f) } - else if (alen < plenInit) fail + else if (alen < plenInit) return fail else { - val front = params.init zip (args take plenInit) - val back = args drop plenInit map (a => (params.last, a)) - front ++ back + foreach2(params.init, args take plenInit)(f) + val remainingArgs = args drop plenInit + foreach2(List.fill(remainingArgs.size)(params.last), remainingArgs)(f) } } - else fail - } + else return fail + true + } + /** * Selects the correct parameter list when there are nested applications. * Given Apply(fn, args), args might correspond to any of fn.symbol's parameter @@ -144,22 +154,28 @@ abstract class TreeInfo { * applies: for instance Apply(fn @ Apply(Apply(_, _), _), args) implies args * correspond to the third parameter list. * + * The argument fn is the function part of the apply node being considered. + * * Also accounts for varargs. */ + private def applyMethodParameters(fn: Tree): List[Symbol] = { + val depth = applyDepth(fn) + // There could be applies which go beyond the parameter list(s), + // being applied to the result of the method call. + // !!! Note that this still doesn't seem correct, although it should + // be closer than what it replaced. + if (depth < fn.symbol.paramss.size) fn.symbol.paramss(depth) + else if (fn.symbol.paramss.isEmpty) Nil + else fn.symbol.paramss.last + } + def zipMethodParamsAndArgs(t: Tree): List[(Symbol, Tree)] = t match { - case Apply(fn, args) => - val depth = applyDepth(fn) - // There could be applies which go beyond the parameter list(s), - // being applied to the result of the method call. - // !!! Note that this still doesn't seem correct, although it should - // be closer than what it replaced. - val params = ( - if (depth < fn.symbol.paramss.size) fn.symbol.paramss(depth) - else if (fn.symbol.paramss.isEmpty) Nil - else fn.symbol.paramss.last - ) - zipMethodParamsAndArgs(params, args) - case _ => Nil + case Apply(fn, args) => zipMethodParamsAndArgs(applyMethodParameters(fn), args) + case _ => Nil + } + def foreachMethodParamAndArg(t: Tree)(f: (Symbol, Tree) => Unit): Unit = t match { + case Apply(fn, args) => foreachMethodParamAndArg(applyMethodParameters(fn), args)(f) + case _ => } /** Is symbol potentially a getter of a variable? diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index d7caebbb0a..690f9b7204 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -578,7 +578,7 @@ trait Types extends api.Types { self: SymbolTable => * T.asSeenFrom(ThisType(C), D) (where D is owner of m) * = Int */ - def asSeenFrom(pre: Type, clazz: Symbol): Type = + def asSeenFrom(pre: Type, clazz: Symbol): Type = { if (isTrivial || phase.erasedTypes && pre.typeSymbol != ArrayClass) this else { // scala.tools.nsc.util.trace.when(pre.isInstanceOf[ExistentialType])("X "+this+".asSeenfrom("+pre+","+clazz+" = ") { @@ -594,6 +594,7 @@ trait Types extends api.Types { self: SymbolTable => stopTimer(asSeenFromNanos, start) result } + } /** The info of `sym`, seen as a member of this type. * @@ -1623,29 +1624,40 @@ trait Types extends api.Types { self: SymbolTable => // (this can happen only for erroneous programs). } + private object enterRefs extends TypeMap { + private var tparam: Symbol = _ + + def apply(tp: Type): Type = { + tp match { + case TypeRef(_, sym, args) if args.nonEmpty => + if (settings.debug.value && !sameLength(sym.info.typeParams, args)) + debugwarn("Mismatched zip in computeRefs(): " + sym.info.typeParams + ", " + args) + + foreach2(sym.info.typeParams, args) { (tparam1, arg) => + if (arg contains tparam) { + addRef(NonExpansive, tparam, tparam1) + if (arg.typeSymbol != tparam) + addRef(Expansive, tparam, tparam1) + } + } + case _ => + } + mapOver(tp) + } + def enter(tparam0: Symbol, parent: Type) { + this.tparam = tparam0 + this(parent) + } + } + /** Compute initial (one-step) references and set state to `Initializing`. */ private def computeRefs() { refs = Array(Map(), Map()) - for (tparam <- typeSymbol.typeParams) { - val enterRefs = new TypeMap { - def apply(tp: Type): Type = { - tp match { - case TypeRef(_, sym, args) if args.nonEmpty => - if (settings.debug.value && !sameLength(sym.info.typeParams, args)) - debugwarn("Mismatched zip in computeRefs(): " + sym.info.typeParams + ", " + args) - - for ((tparam1, arg) <- sym.info.typeParams zip args; if arg contains tparam) { - addRef(NonExpansive, tparam, tparam1) - if (arg.typeSymbol != tparam) - addRef(Expansive, tparam, tparam1) - } - case _ => - } - mapOver(tp) - } + typeSymbol.typeParams foreach { tparam => + parents foreach { p => + enterRefs.enter(tparam, p) } - for (p <- parents) enterRefs(p) } state = Initializing } @@ -3592,9 +3604,9 @@ A type's typeSymbol should never be inspected directly. // val containsContravariantExistentialCollector = new ContainsVariantExistentialCollector(-1) def typeParamsToExistentials(clazz: Symbol, tparams: List[Symbol]): List[Symbol] = { - val eparams = for ((tparam, i) <- tparams.zipWithIndex) yield { - clazz.newExistential(clazz.pos, newTypeName("?"+i)).setInfo(tparam.info.bounds) - } + val eparams = mapWithIndex(tparams)((tparam, i) => + clazz.newExistential(clazz.pos, newTypeName("?"+i)) setInfo tparam.info.bounds) + eparams map (_ substInfo (tparams, eparams)) } @@ -4425,8 +4437,7 @@ A type's typeSymbol should never be inspected directly. case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) => assert(sym1 == sym2) pre1 =:= pre2 && - ((args1, args2, sym1.typeParams).zipped forall { - (arg1, arg2, tparam) => + forall3(args1, args2, sym1.typeParams) { (arg1, arg2, tparam) => //if (tparam.variance == 0 && !(arg1 =:= arg2)) Console.println("inconsistent: "+arg1+"!="+arg2)//DEBUG if (tparam.variance == 0) arg1 =:= arg2 else if (arg1.isInstanceOf[TypeVar]) @@ -4436,7 +4447,7 @@ A type's typeSymbol should never be inspected directly. // also: think what happens if there are embedded typevars? if (tparam.variance < 0) arg1 <:< arg2 else arg2 <:< arg1 else true - }) + } case (et: ExistentialType, _) => et.withTypeVars(isConsistent(_, tp2)) case (_, et: ExistentialType) => @@ -4959,19 +4970,11 @@ A type's typeSymbol should never be inspected directly. // --> thus, cannot be subtypes (Any/Nothing has already been checked) })) - /** True if all three arguments have the same number of elements and - * the function is true for all the triples. - */ - @tailrec final def corresponds3[A, B, C](xs1: List[A], xs2: List[B], xs3: List[C], f: (A, B, C) => Boolean): Boolean = { - if (xs1.isEmpty) xs2.isEmpty && xs3.isEmpty - else !xs2.isEmpty && !xs3.isEmpty && f(xs1.head, xs2.head, xs3.head) && corresponds3(xs1.tail, xs2.tail, xs3.tail, f) - } - def isSubArg(t1: Type, t2: Type, variance: Int) = (variance > 0 || t2 <:< t1) && (variance < 0 || t1 <:< t2) def isSubArgs(tps1: List[Type], tps2: List[Type], tparams: List[Symbol]): Boolean = - corresponds3(tps1, tps2, tparams map (_.variance), isSubArg) + corresponds3(tps1, tps2, tparams map (_.variance))(isSubArg) def differentOrNone(tp1: Type, tp2: Type) = if (tp1 eq tp2) NoType else tp1 @@ -5343,7 +5346,6 @@ A type's typeSymbol should never be inspected directly. def solve(tvars: List[TypeVar], tparams: List[Symbol], variances: List[Int], upper: Boolean, depth: Int): Boolean = { - val config = tvars zip (tparams zip variances) def solveOne(tvar: TypeVar, tparam: Symbol, variance: Int) { if (tvar.constr.inst == NoType) { @@ -5352,15 +5354,17 @@ A type's typeSymbol should never be inspected directly. val bound: Type = if (up) tparam.info.bounds.hi else tparam.info.bounds.lo //Console.println("solveOne0(tv, tp, v, b)="+(tvar, tparam, variance, bound)) var cyclic = bound contains tparam - for ((tvar2, (tparam2, variance2)) <- config) { - if (tparam2 != tparam && - ((bound contains tparam2) || - up && (tparam2.info.bounds.lo =:= tparam.tpe) || - !up && (tparam2.info.bounds.hi =:= tparam.tpe))) { + foreach3(tvars, tparams, variances)((tvar2, tparam2, variance2) => { + val ok = (tparam2 != tparam) && ( + (bound contains tparam2) + || up && (tparam2.info.bounds.lo =:= tparam.tpe) + || !up && (tparam2.info.bounds.hi =:= tparam.tpe) + ) + if (ok) { if (tvar2.constr.inst eq null) cyclic = true solveOne(tvar2, tparam2, variance2) } - } + }) if (!cyclic) { if (up) { if (bound.typeSymbol != AnyClass) @@ -5399,9 +5403,7 @@ A type's typeSymbol should never be inspected directly. } // println("solving "+tvars+"/"+tparams+"/"+(tparams map (_.info))) - for ((tvar, (tparam, variance)) <- config) - solveOne(tvar, tparam, variance) - + foreach3(tvars, tparams, variances)(solveOne) tvars forall (tvar => tvar.constr.isWithinBounds(tvar.constr.inst)) } @@ -5684,8 +5686,8 @@ A type's typeSymbol should never be inspected directly. case List() => NothingClass.tpe case List(t) => t case ts @ PolyType(tparams, _) :: _ => - val tparams1 = (tparams, matchingBounds(ts, tparams).transpose).zipped map - ((tparam, bounds) => tparam.cloneSymbol.setInfo(glb(bounds, depth))) + val tparams1 = map2(tparams, matchingBounds(ts, tparams).transpose)((tparam, bounds) => + tparam.cloneSymbol.setInfo(glb(bounds, depth))) PolyType(tparams1, lub0(matchingInstTypes(ts, tparams1))) case ts @ MethodType(params, _) :: rest => MethodType(params, lub0(matchingRestypes(ts, params map (_.tpe)))) @@ -5724,7 +5726,7 @@ A type's typeSymbol should never be inspected directly. if (syms contains NoSymbol) NoSymbol else { val symtypes = - (narrowts, syms).zipped map ((t, sym) => t.memberInfo(sym).substThis(t.typeSymbol, lubThisType)) + map2(narrowts, syms)((t, sym) => t.memberInfo(sym).substThis(t.typeSymbol, lubThisType)) if (proto.isTerm) // possible problem: owner of info is still the old one, instead of new refinement class proto.cloneSymbol(lubRefined.typeSymbol).setInfoOwnerAdjusted(lub(symtypes, decr(depth))) else if (symtypes.tail forall (symtypes.head =:=)) @@ -5829,8 +5831,8 @@ A type's typeSymbol should never be inspected directly. case List() => AnyClass.tpe case List(t) => t case ts @ PolyType(tparams, _) :: _ => - val tparams1 = (tparams, matchingBounds(ts, tparams).transpose).zipped map - ((tparam, bounds) => tparam.cloneSymbol.setInfo(lub(bounds, depth))) + val tparams1 = map2(tparams, matchingBounds(ts, tparams).transpose)((tparam, bounds) => + tparam.cloneSymbol.setInfo(lub(bounds, depth))) PolyType(tparams1, glbNorm(matchingInstTypes(ts, tparams1), depth)) case ts @ MethodType(params, _) :: rest => MethodType(params, glbNorm(matchingRestypes(ts, params map (_.tpe)), depth)) @@ -5961,38 +5963,39 @@ A type's typeSymbol should never be inspected directly. else if (args exists (arg => isValueClass(arg.typeSymbol))) Some(ObjectClass.tpe) else Some(typeRef(pre, sym, List(lub(args)))) } - } else { - val args = (sym.typeParams, argss.transpose).zipped map { (tparam, as) => - if (depth == 0) { - if (tparam.variance == variance) { - // Take the intersection of the upper bounds of the type parameters - // rather than falling all the way back to "Any", otherwise we end up not - // conforming to bounds. - val bounds0 = sym.typeParams map (_.info.bounds.hi) filterNot (_.typeSymbol == AnyClass) - if (bounds0.isEmpty) AnyClass.tpe - else intersectionType(bounds0) - } - else if (tparam.variance == -variance) NothingClass.tpe - else NoType + } + else { + val args = map2(sym.typeParams, argss.transpose) { (tparam, as) => + if (depth == 0) { + if (tparam.variance == variance) { + // Take the intersection of the upper bounds of the type parameters + // rather than falling all the way back to "Any", otherwise we end up not + // conforming to bounds. + val bounds0 = sym.typeParams map (_.info.bounds.hi) filterNot (_.typeSymbol == AnyClass) + if (bounds0.isEmpty) AnyClass.tpe + else intersectionType(bounds0) } + else if (tparam.variance == -variance) NothingClass.tpe + else NoType + } + else { + if (tparam.variance == variance) lub(as, decr(depth)) + else if (tparam.variance == -variance) glb(as, decr(depth)) else { - if (tparam.variance == variance) lub(as, decr(depth)) - else if (tparam.variance == -variance) glb(as, decr(depth)) - else { - val l = lub(as, decr(depth)) - val g = glb(as, decr(depth)) - if (l <:< g) l - else { // Martin: I removed this, because incomplete. Not sure there is a good way to fix it. For the moment we - // just err on the conservative side, i.e. with a bound that is too high. - // if(!(tparam.info.bounds contains tparam)){ //@M can't deal with f-bounds, see #2251 - - val qvar = commonOwner(as) freshExistential "" setInfo TypeBounds(g, l) - capturedParams += qvar - qvar.tpe - } + val l = lub(as, decr(depth)) + val g = glb(as, decr(depth)) + if (l <:< g) l + else { // Martin: I removed this, because incomplete. Not sure there is a good way to fix it. For the moment we + // just err on the conservative side, i.e. with a bound that is too high. + // if(!(tparam.info.bounds contains tparam)) //@M can't deal with f-bounds, see #2251 + + val qvar = commonOwner(as) freshExistential "" setInfo TypeBounds(g, l) + capturedParams += qvar + qvar.tpe } } } + } if (args contains NoType) None else Some(existentialAbstraction(capturedParams.toList, typeRef(pre, sym, args))) } @@ -6077,148 +6080,6 @@ A type's typeSymbol should never be inspected directly. throw new NoCommonType(tps) } - - // TODO: this desperately needs to be cleaned up - // plan: split into kind inference and subkinding - // every Type has a (cached) Kind - def kindsConform(tparams: List[Symbol], targs: List[Type], pre: Type, owner: Symbol): Boolean = - checkKindBounds0(tparams, targs, pre, owner, false).isEmpty - - /** Check well-kindedness of type application (assumes arities are already checked) -- @M - * - * This check is also performed when abstract type members become concrete (aka a "type alias") -- then tparams.length==1 - * (checked one type member at a time -- in that case, prefix is the name of the type alias) - * - * Type application is just like value application: it's "contravariant" in the sense that - * the type parameters of the supplied type arguments must conform to the type parameters of - * the required type parameters: - * - their bounds must be less strict - * - variances must match (here, variances are absolute, the variance of a type parameter does not influence the variance of its higher-order parameters) - * - @M TODO: are these conditions correct,sufficient&necessary? - * - * e.g. class Iterable[t, m[+x <: t]] --> the application Iterable[Int, List] is okay, since - * List's type parameter is also covariant and its bounds are weaker than <: Int - */ - def checkKindBounds0(tparams: List[Symbol], targs: List[Type], pre: Type, owner: Symbol, explainErrors: Boolean): List[(Type, Symbol, List[(Symbol, Symbol)], List[(Symbol, Symbol)], List[(Symbol, Symbol)])] = { - var error = false - - def transform(tp: Type, clazz: Symbol): Type = tp.asSeenFrom(pre, clazz) // instantiate type params that come from outside the abstract type we're currently checking - def transformedBounds(p: Symbol, o: Symbol) = transform(p.info.instantiateTypeParams(tparams, targs).bounds, o) - - /** Check whether `sym1`'s variance conforms to `sym2`'s variance. - * - * If `sym2` is invariant, `sym1`'s variance is irrelevant. Otherwise they must be equal. - */ - def variancesMatch(sym1: Symbol, sym2: Symbol): Boolean = (sym2.variance==0 || sym1.variance==sym2.variance) - - // check that the type parameters hkargs to a higher-kinded type conform to the expected params hkparams - def checkKindBoundsHK( - hkargs: List[Symbol], - arg: Symbol, - param: Symbol, - paramowner: Symbol, - underHKParams: List[Symbol], - withHKArgs: List[Symbol] - ): (List[(Symbol, Symbol)], List[(Symbol, Symbol)], List[(Symbol, Symbol)]) = { - - def bindHKParams(tp: Type) = tp.substSym(underHKParams, withHKArgs) - // @M sometimes hkargs != arg.typeParams, the symbol and the type may have very different type parameters - val hkparams = param.typeParams - - if (settings.debug.value) { - log("checkKindBoundsHK expected: "+ param +" with params "+ hkparams +" by definition in "+ paramowner) - log("checkKindBoundsHK supplied: "+ arg +" with params "+ hkargs +" from "+ owner) - log("checkKindBoundsHK under params: "+ underHKParams +" with args "+ withHKArgs) - } - - if (!sameLength(hkargs, hkparams)) { - if (arg == AnyClass || arg == NothingClass) (Nil, Nil, Nil) // Any and Nothing are kind-overloaded - else {error = true; (List((arg, param)), Nil, Nil) } // shortcut: always set error, whether explainTypesOrNot - } - else { - val _arityMismatches = if (explainErrors) new ListBuffer[(Symbol, Symbol)] else null - val _varianceMismatches = if (explainErrors) new ListBuffer[(Symbol, Symbol)] else null - val _stricterBounds = if (explainErrors) new ListBuffer[(Symbol, Symbol)] else null - - def varianceMismatch(a: Symbol, p: Symbol) { if(explainErrors) _varianceMismatches += ((a, p)) else error = true} - def stricterBound(a: Symbol, p: Symbol) { if(explainErrors) _stricterBounds += ((a, p)) else error = true } - def arityMismatches(as: Iterable[(Symbol, Symbol)]) { if(explainErrors) _arityMismatches ++= as } - def varianceMismatches(as: Iterable[(Symbol, Symbol)]) { if(explainErrors) _varianceMismatches ++= as } - def stricterBounds(as: Iterable[(Symbol, Symbol)]) { if(explainErrors) _stricterBounds ++= as } - - for ((hkarg, hkparam) <- hkargs zip hkparams) { - if (hkparam.typeParams.isEmpty && hkarg.typeParams.isEmpty) { // base-case: kind * - if (!variancesMatch(hkarg, hkparam)) - varianceMismatch(hkarg, hkparam) - - // instantiateTypeParams(tparams, targs) --> higher-order bounds may contain references to type arguments - // substSym(hkparams, hkargs) --> these types are going to be compared as types of kind * - // --> their arguments use different symbols, but are conceptually the same - // (could also replace the types by polytypes, but can't just strip the symbols, as ordering is lost then) - val declaredBounds = transformedBounds(hkparam, paramowner) - val declaredBoundsInst = bindHKParams(declaredBounds) - val argumentBounds = transform(hkarg.info.bounds, owner) - if (!(declaredBoundsInst <:< argumentBounds)) - stricterBound(hkarg, hkparam) - - debuglog( - "checkKindBoundsHK base case: " + hkparam + - " declared bounds: " + declaredBounds + - " after instantiating earlier hkparams: " + declaredBoundsInst + "\n" + - "checkKindBoundsHK base case: "+ hkarg + - " has bounds: " + argumentBounds - ) - } - else { - debuglog("checkKindBoundsHK recursing to compare params of "+ hkparam +" with "+ hkarg) - val (am, vm, sb) = checkKindBoundsHK( - hkarg.typeParams, - hkarg, - hkparam, - paramowner, - underHKParams ++ hkparam.typeParams, - withHKArgs ++ hkarg.typeParams - ) - arityMismatches(am) - varianceMismatches(vm) - stricterBounds(sb) - } - if (!explainErrors && error) return (Nil, Nil, Nil) // stop as soon as we encountered an error - } - if (!explainErrors) (Nil, Nil, Nil) - else (_arityMismatches.toList, _varianceMismatches.toList, _stricterBounds.toList) - } - } - - val errors = new ListBuffer[(Type, Symbol, List[(Symbol, Symbol)], List[(Symbol, Symbol)], List[(Symbol, Symbol)])] - if (settings.debug.value &&(tparams.nonEmpty || targs.nonEmpty)) - log("checkKindBounds0(" + tparams + ", " + targs + ", " + pre + ", " + owner + ", " + explainErrors + ")") - - for { - (tparam, targ) <- tparams zip targs - // Prevent WildcardType from causing kind errors, as typevars may be higher-order - if (targ != WildcardType) && (targ.isHigherKinded || tparam.typeParams.nonEmpty) - } { - // @M must use the typeParams of the *type* targ, not of the *symbol* of targ!! - targ.typeSymbolDirect.info // force symbol load for #4205 - val tparamsHO = targ.typeParams - - val (arityMismatches, varianceMismatches, stricterBounds) = ( - // NOTE: *not* targ.typeSymbol, which normalizes - checkKindBoundsHK(tparamsHO, targ.typeSymbolDirect, tparam, tparam.owner, tparam.typeParams, tparamsHO) - ) - if (explainErrors) { - if (arityMismatches.nonEmpty || varianceMismatches.nonEmpty || stricterBounds.nonEmpty) { - errors += ((targ, tparam, arityMismatches, varianceMismatches, stricterBounds)) - } - } - else if (error) - return List((NoType, NoSymbol, Nil, Nil, Nil)) - } - - errors.toList - } - // Errors and Diagnostics ----------------------------------------------------- /** A throwable signalling a type error */ diff --git a/src/compiler/scala/reflect/internal/util/Collections.scala b/src/compiler/scala/reflect/internal/util/Collections.scala new file mode 100644 index 0000000000..28a17c7821 --- /dev/null +++ b/src/compiler/scala/reflect/internal/util/Collections.scala @@ -0,0 +1,138 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.reflect.internal.util + +import scala.collection.{ mutable, immutable } +import scala.annotation.tailrec +import mutable.ListBuffer + +/** Profiler driven changes. + */ +trait Collections { + /** True if all three arguments have the same number of elements and + * the function is true for all the triples. + */ + @tailrec final def corresponds3[A, B, C](xs1: List[A], xs2: List[B], xs3: List[C]) + (f: (A, B, C) => Boolean): Boolean = ( + if (xs1.isEmpty) xs2.isEmpty && xs3.isEmpty + else !xs2.isEmpty && !xs3.isEmpty && f(xs1.head, xs2.head, xs3.head) && corresponds3(xs1.tail, xs2.tail, xs3.tail)(f) + ) + + final def map2[A, B, C](xs1: List[A], xs2: List[B])(f: (A, B) => C): List[C] = { + val lb = new ListBuffer[C] + var ys1 = xs1 + var ys2 = xs2 + while (!ys1.isEmpty && !ys2.isEmpty) { + lb += f(ys1.head, ys2.head) + ys1 = ys1.tail + ys2 = ys2.tail + } + lb.toList + } + final def map3[A, B, C, D](xs1: List[A], xs2: List[B], xs3: List[C])(f: (A, B, C) => D): List[D] = { + if (xs1.isEmpty || xs2.isEmpty || xs3.isEmpty) Nil + else f(xs1.head, xs2.head, xs3.head) :: map3(xs1.tail, xs2.tail, xs3.tail)(f) + } + final def flatMap2[A, B, C](xs1: List[A], xs2: List[B])(f: (A, B) => List[C]): List[C] = { + val lb = new ListBuffer[C] + var ys1 = xs1 + var ys2 = xs2 + while (!ys1.isEmpty && !ys2.isEmpty) { + lb ++= f(ys1.head, ys2.head) + ys1 = ys1.tail + ys2 = ys2.tail + } + lb.toList + } + + final def mapWithIndex[A, B](xs: List[A])(f: (A, Int) => B): List[B] = { + val lb = new ListBuffer[B] + var index = 0 + var ys = xs + while (!ys.isEmpty) { + lb += f(ys.head, index) + ys = ys.tail + index += 1 + } + lb.toList + } + final def collectMap2[A, B, C](xs1: List[A], xs2: List[B])(p: (A, B) => Boolean): Map[A, B] = { + if (xs1.isEmpty || xs2.isEmpty) + return Map() + + val buf = immutable.Map.newBuilder[A, B] + var ys1 = xs1 + var ys2 = xs2 + while (!ys1.isEmpty && !ys2.isEmpty) { + val x1 = ys1.head + val x2 = ys2.head + if (p(x1, x2)) + buf += ((x1, x2)) + + ys1 = ys1.tail + ys2 = ys2.tail + } + buf.result + } + final def foreach2[A, B](xs1: List[A], xs2: List[B])(f: (A, B) => Unit): Unit = { + var ys1 = xs1 + var ys2 = xs2 + while (!ys1.isEmpty && !ys2.isEmpty) { + f(ys1.head, ys2.head) + ys1 = ys1.tail + ys2 = ys2.tail + } + } + final def foreach3[A, B, C](xs1: List[A], xs2: List[B], xs3: List[C])(f: (A, B, C) => Unit): Unit = { + var ys1 = xs1 + var ys2 = xs2 + var ys3 = xs3 + while (!ys1.isEmpty && !ys2.isEmpty && !ys3.isEmpty) { + f(ys1.head, ys2.head, ys3.head) + ys1 = ys1.tail + ys2 = ys2.tail + ys3 = ys3.tail + } + } + final def exists2[A, B](xs1: List[A], xs2: List[B])(f: (A, B) => Boolean): Boolean = { + var ys1 = xs1 + var ys2 = xs2 + while (!ys1.isEmpty && !ys2.isEmpty) { + if (f(ys1.head, ys2.head)) + return true + + ys1 = ys1.tail + ys2 = ys2.tail + } + false + } + final def forall2[A, B](xs1: List[A], xs2: List[B])(f: (A, B) => Boolean): Boolean = { + var ys1 = xs1 + var ys2 = xs2 + while (!ys1.isEmpty && !ys2.isEmpty) { + if (!f(ys1.head, ys2.head)) + return false + + ys1 = ys1.tail + ys2 = ys2.tail + } + true + } + final def forall3[A, B, C](xs1: List[A], xs2: List[B], xs3: List[C])(f: (A, B, C) => Boolean): Boolean = { + var ys1 = xs1 + var ys2 = xs2 + var ys3 = xs3 + while (!ys1.isEmpty && !ys2.isEmpty && !ys3.isEmpty) { + if (!f(ys1.head, ys2.head, ys3.head)) + return false + + ys1 = ys1.tail + ys2 = ys2.tail + ys3 = ys3.tail + } + true + } +} diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index f3eaff8db0..30ee7fc885 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -77,16 +77,17 @@ trait Trees extends reflect.internal.Trees { self: Global => }}) val (edefs, rest) = body span treeInfo.isEarlyDef val (evdefs, etdefs) = edefs partition treeInfo.isEarlyValDef - val (lvdefs, gvdefs) = evdefs map { + val gvdefs = evdefs map { case vdef @ ValDef(mods, name, tpt, rhs) => - val fld = treeCopy.ValDef( + treeCopy.ValDef( vdef.duplicate, mods, name, atPos(focusPos(vdef.pos)) { TypeTree() setOriginal tpt setPos focusPos(tpt.pos) }, // atPos in case EmptyTree) - val local = treeCopy.ValDef(vdef, Modifiers(PRESUPER), name, tpt, rhs) - (local, fld) - } unzip - + } + val lvdefs = evdefs map { + case vdef @ ValDef(mods, name, tpt, rhs) => + treeCopy.ValDef(vdef, Modifiers(PRESUPER), name, tpt, rhs) + } val constrs = { if (constrMods hasFlag TRAIT) { if (body forall treeInfo.isInterfaceMember) List() diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala index 9fbf649525..a47bfda8c1 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala @@ -7,7 +7,6 @@ package scala.tools.nsc package symtab import ast.{Trees, TreePrinters, DocComments} - import util._ -abstract class SymbolTable extends reflect.internal.SymbolTable +abstract class SymbolTable extends reflect.internal.SymbolTable \ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/transform/LiftCode.scala b/src/compiler/scala/tools/nsc/transform/LiftCode.scala index 9404f0f699..720509644b 100644 --- a/src/compiler/scala/tools/nsc/transform/LiftCode.scala +++ b/src/compiler/scala/tools/nsc/transform/LiftCode.scala @@ -202,7 +202,7 @@ abstract class LiftCode extends Transform with TypingTransformers { /** A method call with a by-name parameter represents escape. */ case Apply(fn, args) if fn.symbol.paramss.nonEmpty => traverse(fn) - for ((param, arg) <- treeInfo.zipMethodParamsAndArgs(tree)) { + treeInfo.foreachMethodParamAndArg(tree) { (param, arg) => if (param.tpe != null && isByNameParamType(param.tpe)) withEscaping(traverse(arg)) else diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 9c4889eba9..bbe803a3fb 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -102,7 +102,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { def fromSpecialization(sym: Symbol, args: List[Type]): TypeEnv = { ifDebug(assert(sym.info.typeParams.length == args.length, sym + " args: " + args)) - emptyEnv ++ (sym.info.typeParams zip args filter (kv => isSpecialized(kv._1))) + emptyEnv ++ collectMap2(sym.info.typeParams, args)((k, v) => isSpecialized(k)) } /** Does typeenv `t1` include `t2`? All type variables in `t1` @@ -255,7 +255,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val pre1 = this(pre) // when searching for a specialized class, take care to map all // type parameters that are subtypes of AnyRef to AnyRef - val args1 = (args zip sym.typeParams) map { + val args1 = map2(args, sym.typeParams) { case (tp, orig) if isSpecializedAnyRefSubtype(tp, orig) => AnyRefClass.tpe case (tp, _) => tp } @@ -341,7 +341,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { case set :: sets => for (x <- set ; xs <- loop(sets)) yield x :: xs } // zip the keys with each permutation to create a TypeEnv - loop(keys map concreteTypes) map (keys zip _ toMap) + loop(keys map concreteTypes) map (xss => Map(keys zip xss: _*)) } /** Does the given 'sym' need to be specialized in the environment 'env'? @@ -445,7 +445,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { def produceTypeParameters(syms: List[Symbol], nowner: Symbol, env: TypeEnv) = { val cloned = for (s <- syms) yield if (!env.contains(s)) s.cloneSymbol(nowner) else env(s).typeSymbol // log("producing type params: " + cloned.map(t => (t, t.tpe.bounds.hi))) - for ((orig, cln) <- syms zip cloned) { + foreach2(syms, cloned) { (orig, cln) => cln.removeAnnotation(SpecializedClass) if (env.contains(orig)) cln modifyInfo (info => TypeBounds(info.bounds.lo, AnyRefClass.tpe)) @@ -889,7 +889,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { */ def needsSpecialOverride(overriding: Symbol): (Symbol, TypeEnv) = { def checkOverriddenTParams(overridden: Symbol) { - for ((baseTvar, derivedTvar) <- overridden.info.typeParams.zip(overriding.info.typeParams)) { + foreach2(overridden.info.typeParams, overriding.info.typeParams) { (baseTvar, derivedTvar) => val missing = concreteTypes(baseTvar).toSet -- concreteTypes(derivedTvar).toSet if (missing.nonEmpty) { reporter.error(derivedTvar.pos, @@ -1391,9 +1391,9 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val specMembers = makeSpecializedMembers(tree.symbol.enclClass) ::: (implSpecClasses(body) map localTyper.typed) if (!symbol.isPackageClass) (new CollectMethodBodies)(tree) - val parents1 = currentOwner.info.parents.zipWithIndex.map { - case (tpe, idx) => TypeTree(tpe) setPos parents(idx).pos - } + val parents1 = map2(currentOwner.info.parents, parents)((tpe, parent) => + TypeTree(tpe) setPos parent.pos) + treeCopy.Template(tree, parents1 /*currentOwner.info.parents.map(tpe => TypeTree(tpe) setPos parents.head.pos)*/ , self, diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 90f46206c5..13516037f5 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -461,7 +461,7 @@ abstract class UnCurry extends InfoTransform val args1 = if (isVarArgTypes(formals)) transformVarargs(formals.last.typeArgs.head) else args - (formals, args1).zipped map { (formal, arg) => + map2(formals, args1) { (formal, arg) => if (!isByNameParamType(formal)) { arg } else if (isByNameRef(arg)) { @@ -771,7 +771,7 @@ abstract class UnCurry extends InfoTransform case p => p.symbol.tpe } val forwresult = dd.symbol.tpe.finalResultType - val forwformsyms = (forwformals, flatparams).zipped map ((tp, oldparam) => + val forwformsyms = map2(forwformals, flatparams)((tp, oldparam) => currentClass.newValueParameter(oldparam.symbol.pos, oldparam.name).setInfo(tp) ) def mono = MethodType(forwformsyms, forwresult) @@ -789,7 +789,7 @@ abstract class UnCurry extends InfoTransform // create the tree val forwtree = theTyper.typedPos(dd.pos) { - val locals = (forwsym ARGS, flatparams).zipped map { + val locals = map2(forwsym ARGS, flatparams) { case (_, fp) if !rpsymbols(fp.symbol) => null case (argsym, fp) => Block(Nil, @@ -799,7 +799,7 @@ abstract class UnCurry extends InfoTransform ) ) } - val seqargs = (locals, forwsym ARGS).zipped map { + val seqargs = map2(locals, forwsym ARGS) { case (null, argsym) => Ident(argsym) case (l, _) => l } diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 67fa67b0f3..2bd307e31a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -9,7 +9,6 @@ package typechecker import scala.collection.{ mutable, immutable } import scala.collection.mutable.ListBuffer import scala.util.control.ControlThrowable -import scala.tools.util.StringOps.{ countAsString, countElementsAsString } import symtab.Flags._ import scala.annotation.tailrec @@ -459,13 +458,14 @@ trait Infer { } val tvars = tparams map freshVar if (isConservativelyCompatible(restpe.instantiateTypeParams(tparams, tvars), pt)) - (tparams, tvars).zipped map ((tparam, tvar) => + map2(tparams, tvars)((tparam, tvar) => instantiateToBound(tvar, varianceInTypes(formals)(tparam))) else tvars map (tvar => WildcardType) } object AdjustedTypeArgs { + val Result = collection.mutable.LinkedHashMap type Result = collection.mutable.LinkedHashMap[Symbol, Option[Type]] def unapply(m: Result): Some[(List[Symbol], List[Type])] = Some(toLists( @@ -508,24 +508,27 @@ trait Infer { * type parameters that are inferred as `scala.Nothing` and that are not covariant in restpe are taken to be undetermined */ def adjustTypeArgs(tparams: List[Symbol], tvars: List[TypeVar], targs: List[Type], restpe: Type = WildcardType): AdjustedTypeArgs.Result = { - @inline def keep(targ: Type, tparam: Symbol) = ( - targ.typeSymbol != NothingClass // definitely not retracting, it's not Nothing! - || (!restpe.isWildcard && (varianceInType(restpe)(tparam) & COVARIANT) != 0)) // occured covariantly --> don't retract - - @inline def adjusted(targ: Type, tvar: TypeVar) = - if (targ.typeSymbol == RepeatedParamClass) - targ.baseType(SeqClass) - else if (targ.typeSymbol == JavaRepeatedParamClass) - targ.baseType(ArrayClass) - // checks opt.virtPatmat directly so one need not run under -Xexperimental to use virtpatmat - else if (targ.typeSymbol.isModuleClass || ((opt.experimental || opt.virtPatmat) && tvar.constr.avoidWiden)) - targ // this infers Foo.type instead of "object Foo" (see also widenIfNecessary) - else - targ.widen + val buf = AdjustedTypeArgs.Result.newBuilder[Symbol, Option[Type]] + + foreach3(tparams, tvars, targs) { (tparam, tvar, targ) => + val retract = ( + targ.typeSymbol == NothingClass // only retract Nothings + && (restpe.isWildcard || (varianceInType(restpe)(tparam) & COVARIANT) == 0) // don't retract covariant occurrences + ) - (tparams, tvars, targs).zipped.map { (tparam, tvar, targ) => - tparam -> (if(keep(targ, tparam)) Some(adjusted(targ, tvar)) else None) - }(collection.breakOut) + // checks opt.virtPatmat directly so one need not run under -Xexperimental to use virtpatmat + buf += ((tparam, + if (retract) None + else Some( + if (targ.typeSymbol == RepeatedParamClass) targ.baseType(SeqClass) + else if (targ.typeSymbol == JavaRepeatedParamClass) targ.baseType(ArrayClass) + // this infers Foo.type instead of "object Foo" (see also widenIfNecessary) + else if (targ.typeSymbol.isModuleClass || ((opt.experimental || opt.virtPatmat) && tvar.constr.avoidWiden)) targ + else targ.widen + ) + )) + } + buf.result } /** Return inferred type arguments, given type parameters, formal parameters, @@ -584,7 +587,7 @@ trait Infer { if (!isFullyDefined(tvar)) tvar.constr.inst = NoType // Then define remaining type variables from argument types. - (argtpes, formals).zipped map { (argtpe, formal) => + map2(argtpes, formals) { (argtpe, formal) => val tp1 = argtpe.deconst.instantiateTypeParams(tparams, tvars) val pt1 = formal.instantiateTypeParams(tparams, tvars) @@ -756,7 +759,8 @@ trait Infer { typesCompatible(reorderArgs(argtpes1, argPos)) ) } - } else { + } + else { // not enough arguments, check if applicable using defaults val missing = missingParams[Type](argtpes0, params, { case NamedType(name, _) => Some(name) @@ -994,39 +998,13 @@ trait Infer { } } - def checkKindBounds(tparams: List[Symbol], targs: List[Type], pre: Type, owner: Symbol): List[String] = { - // @M TODO this method is duplicated all over the place (varianceString) - def varStr(s: Symbol): String = - if (s.isCovariant) "covariant" - else if (s.isContravariant) "contravariant" - else "invariant"; - - def qualify(a0: Symbol, b0: Symbol): String = if (a0.toString != b0.toString) "" else { - if((a0 eq b0) || (a0.owner eq b0.owner)) "" - else { - var a = a0; var b = b0 - while (a.owner.name == b.owner.name) { a = a.owner; b = b.owner} - if (a.locationString ne "") " (" + a.locationString.trim + ")" else "" - } + checkKindBounds0(tparams, targs, pre, owner, true) map { + case (targ, tparam, kindErrors) => + kindErrors.errorMessage(targ, tparam) } - - val errors = checkKindBounds0(tparams, targs, pre, owner, true) - val errorMessages = new ListBuffer[String] - errors foreach {case (targ, tparam, arityMismatches, varianceMismatches, stricterBounds) => errorMessages += - (targ+"'s type parameters do not match "+tparam+"'s expected parameters: "+ - (for ((a, p) <- arityMismatches) - yield a+qualify(a,p)+ " has "+countElementsAsString(a.typeParams.length, "type parameter")+", but "+ - p+qualify(p,a)+" has "+countAsString(p.typeParams.length)).toList.mkString(", ") + - (for ((a, p) <- varianceMismatches) - yield a+qualify(a,p)+ " is "+varStr(a)+", but "+ - p+qualify(p,a)+" is declared "+varStr(p)).toList.mkString(", ") + - (for ((a, p) <- stricterBounds) - yield a+qualify(a,p)+"'s bounds "+a.info+" are stricter than "+ - p+qualify(p,a)+"'s declared bounds "+p.info).toList.mkString(", ")) - } - errorMessages.toList } + /** Substitute free type variables `undetparams` of polymorphic argument * expression `tree`, given two prototypes `strictPt`, and `lenientPt`. * `strictPt` is the first attempt prototype where type parameters diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 8611fafe52..a8dfea02ec 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -260,7 +260,7 @@ trait NamesDefaults { self: Analyzer => */ def argValDefs(args: List[Tree], paramTypes: List[Type], blockTyper: Typer): List[ValDef] = { val context = blockTyper.context - val symPs = (args, paramTypes).zipped map ((arg, tpe) => { + val symPs = map2(args, paramTypes)((arg, tpe) => { val byName = isByNameParamType(tpe) val (argTpe, repeated) = if (isScalaRepeatedParamType(tpe)) arg match { @@ -276,7 +276,7 @@ trait NamesDefaults { self: Analyzer => s.setInfo(valType) (context.scope.enter(s), byName, repeated) }) - (symPs, args).zipped map { + map2(symPs, args) { case ((sym, byName, repeated), arg) => val body = if (byName) { @@ -326,13 +326,15 @@ trait NamesDefaults { self: Analyzer => reorderArgsInv(formals, argPos), blockTyper) // refArgs: definition-site order again - val refArgs = (reorderArgs(valDefs, argPos), formals).zipped map ((vDef, tpe) => { + val refArgs = map2(reorderArgs(valDefs, argPos), formals)((vDef, tpe) => { val ref = gen.mkAttributedRef(vDef.symbol) atPos(vDef.pos.focus) { // for by-name parameters, the local value is a nullary function returning the argument - if (isByNameParamType(tpe)) Apply(ref, List()) - else if (isScalaRepeatedParamType(tpe)) Typed(ref, Ident(tpnme.WILDCARD_STAR)) - else ref + tpe.typeSymbol match { + case ByNameParamClass => Apply(ref, Nil) + case RepeatedParamClass => Typed(ref, Ident(tpnme.WILDCARD_STAR)) + case _ => ref + } } }) // cannot call blockTyper.typedBlock here, because the method expr might be partially applied only @@ -340,7 +342,7 @@ trait NamesDefaults { self: Analyzer => res.setPos(res.pos.makeTransparent) val block = Block(stats ::: valDefs, res).setType(res.tpe).setPos(tree.pos) context.namedApplyBlockInfo = - Some((block, NamedApplyInfo(qual, targs, vargss ::: List(refArgs), blockTyper))) + Some((block, NamedApplyInfo(qual, targs, vargss :+ refArgs, blockTyper))) block } } @@ -430,6 +432,80 @@ trait NamesDefaults { self: Analyzer => } } else NoSymbol } + + private def savingUndeterminedTParams[T](context: Context)(fn: List[Symbol] => T): T = { + val savedParams = context.extractUndetparams() + val savedReporting = context.reportAmbiguousErrors + + context.reportAmbiguousErrors = false + try fn(savedParams) + finally { + context.reportAmbiguousErrors = savedReporting + //@M note that we don't get here when an ambiguity was detected (during the computation of res), + // as errorTree throws an exception + context.undetparams = savedParams + } + } + + /** Fast path for ambiguous assignment check. + */ + private def isNameInScope(context: Context, name: Name) = ( + context.enclosingContextChain exists (ctx => + (ctx.scope.lookupEntry(name) != null) + || (ctx.owner.rawInfo.member(name) != NoSymbol) + ) + ) + + /** A full type check is very expensive; let's make sure there's a name + * somewhere which could potentially be ambiguous before we go that route. + */ + private def isAmbiguousAssignment(typer: Typer, param: Symbol, arg: Tree) = { + import typer.context + isNameInScope(context, param.name) && { + // for named arguments, check whether the assignment expression would + // typecheck. if it does, report an ambiguous error. + val paramtpe = param.tpe.cloneInfo(param) + // replace type parameters by wildcard. in the below example we need to + // typecheck (x = 1) with wildcard (not T) so that it succeeds. + // def f[T](x: T) = x + // var x = 0 + // f(x = 1) << "x = 1" typechecks with expected type WildcardType + savingUndeterminedTParams(context) { udp => + val subst = new SubstTypeMap(udp, udp map (_ => WildcardType)) { + override def apply(tp: Type): Type = super.apply(tp match { + case TypeRef(_, ByNameParamClass, x :: Nil) => x + case _ => tp + }) + } + // This throws an exception which is caught in `tryTypedApply` (as it + // uses `silent`) - unfortunately, tryTypedApply recovers from the + // exception if you use errorTree(arg, ...) and conforms is allowed as + // a view (see tryImplicit in Implicits) because it tries to produce a + // new qualifier (if the old one was P, the new one will be + // conforms.apply(P)), and if that works, it pretends nothing happened. + // + // To make sure tryTypedApply fails, we would like to pass EmptyTree + // instead of arg, but can't do that because eventually setType(ErrorType) + // is called, and EmptyTree can only be typed NoType. Thus we need to + // disable conforms as a view... + try typer.silent(_.typed(arg, subst(paramtpe))) match { + case t: Tree => !t.isErroneous + case _ => false + } + catch { + // `silent` only catches and returns TypeErrors which are not + // CyclicReferences. Fix for #3685 + case cr @ CyclicReference(sym, _) => + (sym.name == param.name) && sym.accessedOrSelf.isVariable && { + context.error(sym.pos, + "variable definition needs type because '%s' is used as a named argument in its body.".format(sym.name)) + typer.infer.setError(arg) + true + } + } + } + } + } /** * Removes name assignments from args. Additionally, returns an array mapping @@ -439,71 +515,38 @@ trait NamesDefaults { self: Analyzer => * after named ones. */ def removeNames(typer: Typer)(args: List[Tree], params: List[Symbol]): (List[Tree], Array[Int]) = { - import typer.infer.errorTree - - // maps indicies from (order written by user) to (order of definition) - val argPos = (new Array[Int](args.length)) map (x => -1) + import typer.context + // maps indices from (order written by user) to (order of definition) + val argPos = Array.fill(args.length)(-1) var positionalAllowed = true - val namelessArgs = for ((arg, index) <- (args.zipWithIndex)) yield arg match { - case a @ AssignOrNamedArg(Ident(name), rhs) => - val (pos, newName) = paramPos(params, name) - newName.foreach(n => { - typer.context.unit.deprecationWarning(arg.pos, "the parameter name "+ name +" has been deprecated. Use "+ n +" instead.") - }) - if (pos == -1) { - if (positionalAllowed) { - argPos(index) = index - // prevent isNamed from being true when calling doTypedApply recursively, - // treat the arg as an assignment of type Unit - Assign(a.lhs, rhs).setPos(arg.pos) - } else { - errorTree(arg, "unknown parameter name: "+ name) - } - } else if (argPos contains pos) { - errorTree(arg, "parameter specified twice: "+ name) - } else { - // for named arguments, check whether the assignment expression would - // typecheck. if it does, report an ambiguous error. - val param = params(pos) - val paramtpe = params(pos).tpe.cloneInfo(param) - // replace type parameters by wildcard. in the below example we need to - // typecheck (x = 1) with wildcard (not T) so that it succeeds. - // def f[T](x: T) = x - // var x = 0 - // f(x = 1) << "x = 1" typechecks with expected type WildcardType - val udp = typer.context.extractUndetparams() - val subst = new SubstTypeMap(udp, udp map (_ => WildcardType)) { - override def apply(tp: Type): Type = tp match { - case TypeRef(_, ByNameParamClass, List(arg)) => super.apply(arg) - case _ => super.apply(tp) + val namelessArgs = mapWithIndex(args) { (arg, index) => + def fail(msg: String) = typer.infer.errorTree(arg, msg) + arg match { + case arg @ AssignOrNamedArg(Ident(name), rhs) => + def matchesName(param: Symbol) = !param.isSynthetic && ( + (param.name == name) || (param.deprecatedParamName match { + case Some(`name`) => + context.unit.deprecationWarning(arg.pos, + "the parameter name "+ name +" has been deprecated. Use "+ param.name +" instead.") + true + case _ => false + }) + ) + val pos = params indexWhere matchesName + if (pos == -1) { + if (positionalAllowed) { + argPos(index) = index + // prevent isNamed from being true when calling doTypedApply recursively, + // treat the arg as an assignment of type Unit + Assign(arg.lhs, rhs) setPos arg.pos } + else fail("unknown parameter name: " + name) } - val reportAmbiguousErrors = typer.context.reportAmbiguousErrors - typer.context.reportAmbiguousErrors = false - - var variableNameClash = false - val typedAssign = try { - typer.silent(_.typed(arg, subst(paramtpe))) - } catch { - // `silent` only catches and returns TypeErrors which are not - // CyclicReferences. Fix for #3685 - case cr @ CyclicReference(sym, info) if sym.name == param.name => - if (sym.isVariable || sym.isGetter && sym.accessed.isVariable) { - // named arg not allowed - variableNameClash = true - typer.context.error(sym.pos, - "%s definition needs %s because '%s' is used as a named argument in its body.".format( - "variable", // "method" - "type", // "result type" - sym.name - ) - ) - typer.infer.setError(arg) - } - else cr - } - - def applyNamedArg = { + else if (argPos contains pos) + fail("parameter specified twice: " + name) + else if (isAmbiguousAssignment(typer, params(pos), arg)) + fail("reference to " + name + " is ambiguous; it is both a method parameter and a variable in scope.") + else { // if the named argument is on the original parameter // position, positional after named is allowed. if (index != pos) @@ -511,63 +554,13 @@ trait NamesDefaults { self: Analyzer => argPos(index) = pos rhs } - - val res = typedAssign match { - case _: TypeError => applyNamedArg - - case t: Tree => - if (t.isErroneous && !variableNameClash) { - applyNamedArg - } else if (t.isErroneous) { - t // name clash with variable. error was already reported above. - } else { - // This throws an exception which is caught in `tryTypedApply` (as it - // uses `silent`) - unfortunately, tryTypedApply recovers from the - // exception if you use errorTree(arg, ...) and conforms is allowed as - // a view (see tryImplicit in Implicits) because it tries to produce a - // new qualifier (if the old one was P, the new one will be - // conforms.apply(P)), and if that works, it pretends nothing happened. - // - // To make sure tryTypedApply fails, we would like to pass EmptyTree - // instead of arg, but can't do that because eventually setType(ErrorType) - // is called, and EmptyTree can only be typed NoType. Thus we need to - // disable conforms as a view... - errorTree(arg, "reference to "+ name +" is ambiguous; it is both, a parameter\n"+ - "name of the method and the name of a variable currently in scope.") - } - } - - typer.context.reportAmbiguousErrors = reportAmbiguousErrors - //@M note that we don't get here when an ambiguity was detected (during the computation of res), - // as errorTree throws an exception - typer.context.undetparams = udp - res - } - case _ => - argPos(index) = index - if (positionalAllowed) arg - else errorTree(arg, "positional after named argument.") - } - (namelessArgs, argPos) - } - - /** - * Returns - * - the position of the parameter named `name` - * - optionally, if `name` is @deprecatedName, the new name - */ - def paramPos(params: List[Symbol], name: Name): (Int, Option[Name]) = { - var i = 0 - var rest = params - while (!rest.isEmpty) { - val p = rest.head - if (!p.isSynthetic) { - if (p.name == name) return (i, None) - if (p.deprecatedParamName == Some(name)) return (i, Some(p.name)) + case _ => + argPos(index) = index + if (positionalAllowed) arg + else fail("positional after named argument.") } - i += 1 - rest = rest.tail } - (-1, None) + + (namelessArgs, argPos) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 59a1a254c6..ace38bb4cb 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -410,8 +410,6 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R } } - - def checkOverrideTypes() { if (other.isAliasType) { //if (!member.typeParams.isEmpty) (1.5) @MAT @@ -420,14 +418,14 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R // overrideError("may not override parameterized type"); // @M: substSym - if( !(sameLength(member.typeParams, other.typeParams) && (self.memberType(member).substSym(member.typeParams, other.typeParams) =:= self.memberType(other))) ) // (1.6) + if( !(sameLength(member.typeParams, other.typeParams) && (memberTp.substSym(member.typeParams, other.typeParams) =:= otherTp)) ) // (1.6) overrideTypeError(); - } else if (other.isAbstractType) { + } + else if (other.isAbstractType) { //if (!member.typeParams.isEmpty) // (1.7) @MAT // overrideError("may not be parameterized"); - - val memberTp = self.memberType(member) val otherTp = self.memberInfo(other) + if (!(otherTp.bounds containsType memberTp)) { // (1.7.1) overrideTypeError(); // todo: do an explaintypes with bounds here explainTypes(_.bounds containsType _, otherTp, memberTp) diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index c9991614e4..a0ef2f5e2e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -43,7 +43,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT } private def transformArgs(params: List[Symbol], args: List[Tree]) = { - treeInfo.zipMethodParamsAndArgs(params, args) map { case (param, arg) => + treeInfo.mapMethodParamsAndArgs(params, args) { (param, arg) => if (isByNameParamType(param.tpe)) withInvalidOwner { checkPackedConforms(transform(arg), param.tpe.typeArgs.head) } else transform(arg) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index a4c00e9f89..6b6b905e16 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1207,7 +1207,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { if (preSuperVals.isEmpty && preSuperStats.nonEmpty) debugwarn("Wanted to zip empty presuper val list with " + preSuperStats) else - (preSuperStats, preSuperVals).zipped map { case (ldef, gdef) => gdef.tpt.tpe = ldef.symbol.tpe } + map2(preSuperStats, preSuperVals)((ldef, gdef) => gdef.tpt.tpe = ldef.symbol.tpe) case _ => if (!supertparams.isEmpty) error(supertpt.pos, "missing type arguments") @@ -1959,7 +1959,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { if (argpts.lengthCompare(numVparams) != 0) errorTree(fun, "wrong number of parameters; expected = " + argpts.length) else { - val vparamSyms = (fun.vparams, argpts).zipped map { (vparam, argpt) => + val vparamSyms = map2(fun.vparams, argpts) { (vparam, argpt) => if (vparam.tpt.isEmpty) { vparam.tpt.tpe = if (isFullyDefined(argpt)) argpt @@ -2195,15 +2195,16 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { def needsInstantiation(tparams: List[Symbol], formals: List[Type], args: List[Tree]) = { def isLowerBounded(tparam: Symbol) = !tparam.info.bounds.lo.typeSymbol.isBottomClass - (formals, args).zipped exists { + exists2(formals, args) { case (formal, Function(vparams, _)) => (vparams exists (_.tpt.isEmpty)) && vparams.length <= MaxFunctionArity && (formal baseType FunctionClass(vparams.length) match { case TypeRef(_, _, formalargs) => - (formalargs, vparams).zipped.exists ((formalarg, vparam) => - vparam.tpt.isEmpty && (tparams exists (formalarg contains))) && - (tparams forall isLowerBounded) + ( exists2(formalargs, vparams)((formal, vparam) => + vparam.tpt.isEmpty && (tparams exists formal.contains)) + && (tparams forall isLowerBounded) + ) case _ => false }) @@ -2460,7 +2461,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } else { assert(!inPatternMode(mode)) // this case cannot arise for patterns val lenientTargs = protoTypeArgs(tparams, formals, mt.resultApprox, pt) - val strictTargs = (lenientTargs, tparams).zipped map ((targ, tparam) => + val strictTargs = map2(lenientTargs, tparams)((targ, tparam) => if (targ == WildcardType) tparam.tpe else targ) //@M TODO: should probably be .tpeHK var remainingParams = paramTypes def typedArgToPoly(arg: Tree, formal: Type): Tree = { //TR TODO: cleanup @@ -2477,7 +2478,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } arg1 } - val args1 = (args, formals).zipped map typedArgToPoly + val args1 = map2(args, formals)(typedArgToPoly) if (args1 exists (_.tpe.isError)) errTree else { debuglog("infer method inst "+fun+", tparams = "+tparams+", args = "+args1.map(_.tpe)+", pt = "+pt+", lobounds = "+tparams.map(_.tpe.bounds.lo)+", parambounds = "+tparams.map(_.info)) //debug @@ -2926,7 +2927,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { override val typeParams = tparams map (_.symbol) val typeSkolems = typeParams map (_.newTypeSkolem setInfo this) // Replace the symbols - def substitute() = (tparams, typeSkolems).zipped map (_ setSymbol _) + def substitute() = map2(tparams, typeSkolems)(_ setSymbol _) override def complete(sym: Symbol) { // The info of a skolem is the skolemized info of the // actual type parameter of the skolem @@ -3972,7 +3973,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } val argtypes = args1 map (_.tpe) - (args, tparams).zipped foreach { (arg, tparam) => arg match { + foreach2(args, tparams)((arg, tparam) => arg match { // note: can't use args1 in selector, because Bind's got replaced case Bind(_, _) => if (arg.symbol.isAbstractType) @@ -3981,7 +3982,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { lub(List(arg.symbol.info.bounds.lo, tparam.info.bounds.lo.subst(tparams, argtypes))), glb(List(arg.symbol.info.bounds.hi, tparam.info.bounds.hi.subst(tparams, argtypes)))) case _ => - }} + }) val original = treeCopy.AppliedTypeTree(tree, tpt1, args1) val result = TypeTree(appliedType(tpt1.tpe, argtypes)) setOriginal original if(tpt1.tpe.isInstanceOf[PolyType]) // did the type application (performed by appliedType) involve an unchecked beta-reduction? @@ -4079,7 +4080,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case UnApply(fun, args) => val fun1 = typed(fun) val tpes = formalTypes(unapplyTypeList(fun.symbol, fun1.tpe), args.length) - val args1 = (args, tpes).zipped map typedPattern + val args1 = map2(args, tpes)(typedPattern) treeCopy.UnApply(tree, fun1, args1) setType pt case ArrayValue(elemtpt, elems) => diff --git a/src/compiler/scala/tools/util/EditDistance.scala b/src/compiler/scala/tools/util/EditDistance.scala index b705a1eac4..5067dce384 100644 --- a/src/compiler/scala/tools/util/EditDistance.scala +++ b/src/compiler/scala/tools/util/EditDistance.scala @@ -30,23 +30,37 @@ object EditDistance { if (m == 0) return n val d = Array.ofDim[Int](n + 1, m + 1) - 0 to n foreach (x => d(x)(0) = x) - 0 to m foreach (x => d(0)(x) = x) + var i = 0 + val max = math.max(m, n) + while (i <= max) { + if (i <= n) + d(i)(0) = i + if (i <= m) + d(0)(i) = i + i += 1 + } + i = 1 - for (i <- 1 to n ; s_i = s(i - 1) ; j <- 1 to m) { - val t_j = t(j - 1) - val cost = if (s_i == t_j) 0 else 1 + while (i <= n) { + val s_i = s(i - 1) + var j = 1 + while (j <= m) { + val t_j = t(j - 1) + val cost = if (s_i == t_j) 0 else 1 - val c1 = d(i - 1)(j) + 1 - val c2 = d(i)(j - 1) + 1 - val c3 = d(i - 1)(j - 1) + cost + val c1 = d(i - 1)(j) + 1 + val c2 = d(i)(j - 1) + 1 + val c3 = d(i - 1)(j - 1) + cost - d(i)(j) = c1 min c2 min c3 + d(i)(j) = c1 min c2 min c3 - if (transpositions) { - if (i > 1 && j > 1 && s(i - 1) == t(j - 2) && s(i - 2) == t(j - 1)) - d(i)(j) = d(i)(j) min (d(i - 2)(j - 2) + cost) + if (transpositions) { + if (i > 1 && j > 1 && s(i - 1) == t(j - 2) && s(i - 2) == t(j - 1)) + d(i)(j) = d(i)(j) min (d(i - 2)(j - 2) + cost) + } + j += 1 } + i += 1 } d(n)(m) diff --git a/src/library/scala/collection/LinearSeqLike.scala b/src/library/scala/collection/LinearSeqLike.scala index 75c1edac66..ceb980ff80 100644 --- a/src/library/scala/collection/LinearSeqLike.scala +++ b/src/library/scala/collection/LinearSeqLike.scala @@ -13,6 +13,7 @@ import generic._ import mutable.ListBuffer import immutable.List import scala.util.control.Breaks._ +import annotation.tailrec /** A template trait for linear sequences of type `LinearSeq[A]`. * @@ -69,4 +70,9 @@ trait LinearSeqLike[+A, +Repr <: LinearSeqLike[A, Repr]] extends SeqLike[A, Repr xs } } + + @tailrec override final def corresponds[B](that: GenSeq[B])(p: (A,B) => Boolean): Boolean = { + if (this.isEmpty) that.isEmpty + else that.nonEmpty && p(head, that.head) && (tail corresponds that.tail)(p) + } } diff --git a/test/files/neg/names-defaults-neg.check b/test/files/neg/names-defaults-neg.check index 03e44f745d..01ef54e0ea 100644 --- a/test/files/neg/names-defaults-neg.check +++ b/test/files/neg/names-defaults-neg.check @@ -10,8 +10,7 @@ names-defaults-neg.scala:5: error: type mismatch; names-defaults-neg.scala:8: error: positional after named argument. test1(b = "(*", 23) ^ -names-defaults-neg.scala:13: error: reference to x is ambiguous; it is both, a parameter -name of the method and the name of a variable currently in scope. +names-defaults-neg.scala:13: error: reference to x is ambiguous; it is both a method parameter and a variable in scope. test2(x = 1) ^ names-defaults-neg.scala:15: error: not found: value c @@ -26,8 +25,7 @@ names-defaults-neg.scala:17: error: not found: value m names-defaults-neg.scala:18: error: not found: value m test7 { m = 1 } // no named arguments in argument block ^ -names-defaults-neg.scala:19: error: reference to x is ambiguous; it is both, a parameter -name of the method and the name of a variable currently in scope. +names-defaults-neg.scala:19: error: reference to x is ambiguous; it is both a method parameter and a variable in scope. test8(x = 1) ^ names-defaults-neg.scala:22: error: parameter specified twice: a @@ -118,8 +116,7 @@ names-defaults-neg.scala:93: error: parameter specified twice: b names-defaults-neg.scala:98: error: unknown parameter name: m f3818(y = 1, m = 1) ^ -names-defaults-neg.scala:131: error: reference to var2 is ambiguous; it is both, a parameter -name of the method and the name of a variable currently in scope. +names-defaults-neg.scala:131: error: reference to var2 is ambiguous; it is both a method parameter and a variable in scope. delay(var2 = 40) ^ names-defaults-neg.scala:134: error: missing parameter type for expanded function ((x$1) => a = x$1) @@ -146,15 +143,13 @@ names-defaults-neg.scala:164: error: variable definition needs type because 'x' names-defaults-neg.scala:167: error: variable definition needs type because 'x' is used as a named argument in its body. def u6 { var x = u.f(x = "32") } ^ -names-defaults-neg.scala:170: error: reference to x is ambiguous; it is both, a parameter -name of the method and the name of a variable currently in scope. +names-defaults-neg.scala:170: error: reference to x is ambiguous; it is both a method parameter and a variable in scope. def u9 { var x: Int = u.f(x = 1) } ^ names-defaults-neg.scala:177: error: variable definition needs type because 'x' is used as a named argument in its body. class u15 { var x = u.f(x = 1) } ^ -names-defaults-neg.scala:180: error: reference to x is ambiguous; it is both, a parameter -name of the method and the name of a variable currently in scope. +names-defaults-neg.scala:180: error: reference to x is ambiguous; it is both a method parameter and a variable in scope. class u18 { var x: Int = u.f(x = 1) } ^ one warning found -- cgit v1.2.3 From 4ec2e7163774bddd6bc61ad08429e1daa3dd8a78 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 2 Jan 2012 19:10:41 +0100 Subject: Changed boxing of free mutable variables to be flexible wrt when liftcode takes place. A major redesign that unifies the various different approaches to boxing of free variables. Free variables are marked with CAPTURED and eliminated by LambdaLift. I also added some hooks in MacroContext that a reifier needs to use. --- src/compiler/scala/tools/nsc/Global.scala | 3 +- src/compiler/scala/tools/nsc/MacroContext.scala | 10 ++ src/compiler/scala/tools/nsc/ast/Trees.scala | 22 +++++ .../scala/tools/nsc/transform/LambdaLift.scala | 67 ++++++++----- .../scala/tools/nsc/transform/LiftCode.scala | 104 ++------------------- .../scala/tools/nsc/typechecker/Duplicators.scala | 2 +- .../scala/tools/nsc/typechecker/Typers.scala | 4 + src/library/scala/reflect/api/MacroContext.scala | 15 +++ 8 files changed, 105 insertions(+), 122 deletions(-) create mode 100644 src/compiler/scala/tools/nsc/MacroContext.scala create mode 100644 src/library/scala/reflect/api/MacroContext.scala (limited to 'src/library') diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index f70aa60309..2dd32e355b 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -39,6 +39,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb with Trees with TreePrinters with DocComments + with MacroContext with symtab.Positions { override def settings = currentSettings @@ -151,7 +152,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb /** Register top level class (called on entering the class) */ def registerTopLevelSym(sym: Symbol) {} - + // ------------------ Reporting ------------------------------------- // not deprecated yet, but a method called "error" imported into diff --git a/src/compiler/scala/tools/nsc/MacroContext.scala b/src/compiler/scala/tools/nsc/MacroContext.scala new file mode 100644 index 0000000000..e739eade3a --- /dev/null +++ b/src/compiler/scala/tools/nsc/MacroContext.scala @@ -0,0 +1,10 @@ +package scala.tools.nsc + +import symtab.Flags._ + +trait MacroContext extends reflect.api.MacroContext { self: Global => + + def captureVariable(vble: Symbol): Unit = vble setFlag CAPTURED + + def referenceCapturedVariable(id: Ident): Tree = ReferenceToBoxed(id) +} diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 30ee7fc885..88a9b5e18b 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -44,6 +44,15 @@ trait Trees extends reflect.internal.Trees { self: Global => /** emitted by typer, eliminated by refchecks */ case class TypeTreeWithDeferredRefCheck()(val check: () => TypeTree) extends TypTree + + /** Marks underlying reference to id as boxed. + * @pre: id must refer to a captured variable + * A reference such marked will refer to the boxed entity, no dereferencing + * with `.elem` is done on it. + * This tree node can be emitted by macros such as reify that call markBoxedReference. + * It is eliminated in LambdaLift, where the boxing conversion takes place. + */ + case class ReferenceToBoxed(idt: Ident) extends TermTree // --- factory methods ---------------------------------------------------------- @@ -152,6 +161,8 @@ trait Trees extends reflect.internal.Trees { self: Global => traverser.traverse(lhs); traverser.traverse(rhs) case SelectFromArray(qualifier, selector, erasure) => traverser.traverse(qualifier) + case ReferenceToBoxed(idt) => + traverser.traverse(idt) case TypeTreeWithDeferredRefCheck() => // TODO: should we traverse the wrapped tree? // (and rewrap the result? how to update the deferred check? would need to store wrapped tree instead of returning it from check) case _ => super.xtraverse(traverser, tree) @@ -161,6 +172,7 @@ trait Trees extends reflect.internal.Trees { self: Global => def DocDef(tree: Tree, comment: DocComment, definition: Tree): DocDef def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree): AssignOrNamedArg def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type): SelectFromArray + def ReferenceToBoxed(tree: Tree, idt: Ident): ReferenceToBoxed def TypeTreeWithDeferredRefCheck(tree: Tree): TypeTreeWithDeferredRefCheck } @@ -174,6 +186,8 @@ trait Trees extends reflect.internal.Trees { self: Global => new AssignOrNamedArg(lhs, rhs).copyAttrs(tree) def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type) = new SelectFromArray(qualifier, selector, erasure).copyAttrs(tree) + def ReferenceToBoxed(tree: Tree, idt: Ident) = + new ReferenceToBoxed(idt).copyAttrs(tree) def TypeTreeWithDeferredRefCheck(tree: Tree) = tree match { case dc@TypeTreeWithDeferredRefCheck() => new TypeTreeWithDeferredRefCheck()(dc.check).copyAttrs(tree) } @@ -195,6 +209,11 @@ trait Trees extends reflect.internal.Trees { self: Global => if (qualifier0 == qualifier) && (selector0 == selector) => t case _ => this.treeCopy.SelectFromArray(tree, qualifier, selector, erasure) } + def ReferenceToBoxed(tree: Tree, idt: Ident) = tree match { + case t @ ReferenceToBoxed(idt0) + if (idt0 == idt) => t + case _ => this.treeCopy.ReferenceToBoxed(tree, idt) + } def TypeTreeWithDeferredRefCheck(tree: Tree) = tree match { case t @ TypeTreeWithDeferredRefCheck() => t case _ => this.treeCopy.TypeTreeWithDeferredRefCheck(tree) @@ -220,6 +239,9 @@ trait Trees extends reflect.internal.Trees { self: Global => case SelectFromArray(qualifier, selector, erasure) => transformer.treeCopy.SelectFromArray( tree, transformer.transform(qualifier), selector, erasure) + case ReferenceToBoxed(idt) => + transformer.treeCopy.ReferenceToBoxed( + tree, transformer.transform(idt) match { case idt1: Ident => idt1 }) case TypeTreeWithDeferredRefCheck() => transformer.treeCopy.TypeTreeWithDeferredRefCheck(tree) } diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala index 2310eae9bb..2180fd4f3a 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -17,6 +17,19 @@ abstract class LambdaLift extends InfoTransform { /** the following two members override abstract members in Transform */ val phaseName: String = "lambdalift" + + /** Converts types of captured variables to *Ref types. + */ + def boxIfCaptured(sym: Symbol, tpe: Type, erasedTypes: Boolean) = + if (sym.isCapturedVariable) { + val symClass = tpe.typeSymbol + def refType(valueRef: Map[Symbol, Symbol], objectRefClass: Symbol) = + if (isValueClass(symClass) && symClass != UnitClass) valueRef(symClass).tpe + else if (erasedTypes) objectRefClass.tpe + else appliedType(objectRefClass.typeConstructor, List(tpe)) + if (sym.hasAnnotation(VolatileAttr)) refType(volatileRefClass, VolatileObjectRefClass) + else refType(refClass, ObjectRefClass) + } else tpe private val lifted = new TypeMap { def apply(tp: Type): Type = tp match { @@ -31,7 +44,8 @@ abstract class LambdaLift extends InfoTransform { } } - def transformInfo(sym: Symbol, tp: Type): Type = lifted(tp) + def transformInfo(sym: Symbol, tp: Type): Type = + boxIfCaptured(sym, lifted(tp), erasedTypes = true) protected def newTransformer(unit: CompilationUnit): Transformer = new LambdaLifter(unit) @@ -55,7 +69,10 @@ abstract class LambdaLift extends InfoTransform { /** Buffers for lifted out classes and methods */ private val liftedDefs = new LinkedHashMap[Symbol, List[Tree]] - + + /** True if we are transforming under a ReferenceToBoxed node */ + private var isBoxedRef = false + private type SymSet = TreeSet[Symbol] private def newSymSet = new TreeSet[Symbol](_ isLess _) @@ -116,22 +133,7 @@ abstract class LambdaLift extends InfoTransform { } changedFreeVars = true debuglog("" + sym + " is free in " + enclosure); - if (sym.isVariable && !sym.hasFlag(CAPTURED)) { - // todo: We should merge this with the lifting done in liftCode. - // We do have to lift twice: in liftCode, because Code[T] needs to see the lifted version - // and here again because lazy bitmaps are introduced later and get lifted here. - // But we should factor out the code and run it twice. - sym setFlag CAPTURED - val symClass = sym.tpe.typeSymbol - atPhase(phase.next) { - sym updateInfo ( - if (sym.hasAnnotation(VolatileAttr)) - if (isValueClass(symClass)) volatileRefClass(symClass).tpe else VolatileObjectRefClass.tpe - else - if (isValueClass(symClass)) refClass(symClass).tpe else ObjectRefClass.tpe - ) - } - } + if (sym.isVariable) sym setFlag CAPTURED } !enclosure.isClass } @@ -340,7 +342,7 @@ abstract class LambdaLift extends InfoTransform { EmptyTree } - private def postTransform(tree: Tree): Tree = { + private def postTransform(tree: Tree, isBoxedRef: Boolean = false): Tree = { val sym = tree.symbol tree match { case ClassDef(_, _, _, _) => @@ -363,8 +365,19 @@ abstract class LambdaLift extends InfoTransform { } case arg => arg } + /** Wrap expr argument in new *Ref(..) constructor, but make + * sure that Try expressions stay at toplevel. + */ + def refConstr(expr: Tree): Tree = expr match { + case Try(block, catches, finalizer) => + Try(refConstr(block), catches map refConstrCase, finalizer) + case _ => + Apply(Select(New(TypeTree(sym.tpe)), nme.CONSTRUCTOR), List(expr)) + } + def refConstrCase(cdef: CaseDef): CaseDef = + CaseDef(cdef.pat, cdef.guard, refConstr(cdef.body)) treeCopy.ValDef(tree, mods, name, tpt1, typer.typedPos(rhs.pos) { - Apply(Select(New(TypeTree(sym.tpe)), nme.CONSTRUCTOR), List(constructorArg)) + refConstr(constructorArg) }) } else tree case Return(Block(stats, value)) => @@ -388,7 +401,7 @@ abstract class LambdaLift extends InfoTransform { atPos(tree.pos)(proxyRef(sym)) else tree else tree - if (sym.isCapturedVariable) + if (sym.isCapturedVariable && !isBoxedRef) atPos(tree.pos) { val tp = tree.tpe val elemTree = typer typed Select(tree1 setType sym.tpe, nme.elem) @@ -406,10 +419,16 @@ abstract class LambdaLift extends InfoTransform { tree } } + + private def preTransform(tree: Tree) = super.transform(tree) setType lifted(tree.tpe) - override def transform(tree: Tree): Tree = - postTransform(super.transform(tree) setType lifted(tree.tpe)) - + override def transform(tree: Tree): Tree = tree match { + case ReferenceToBoxed(idt) => + postTransform(preTransform(idt), isBoxedRef = true) + case _ => + postTransform(preTransform(tree)) + } + /** Transform statements and add lifted definitions to them. */ override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = { def addLifted(stat: Tree): Tree = stat match { diff --git a/src/compiler/scala/tools/nsc/transform/LiftCode.scala b/src/compiler/scala/tools/nsc/transform/LiftCode.scala index 720509644b..171d1df975 100644 --- a/src/compiler/scala/tools/nsc/transform/LiftCode.scala +++ b/src/compiler/scala/tools/nsc/transform/LiftCode.scala @@ -110,18 +110,10 @@ abstract class LiftCode extends Transform with TypingTransformers { } } - /** Set of mutable local variables that are free in some inner method. */ - private val freeMutableVars: mutable.Set[Symbol] = new mutable.HashSet - private val converted: mutable.Set[Symbol] = new mutable.HashSet // debug - override def transformUnit(unit: CompilationUnit) { - freeMutableVars.clear() - freeLocalsTraverser(unit.body) atPhase(phase.next) { super.transformUnit(unit) } - for (v <- freeMutableVars) //!!! remove - assert(converted contains v, "unconverted: " + v + " in " + v.owner + " in unit " + unit) } override def transform(tree: Tree): Tree = { @@ -137,24 +129,6 @@ abstract class LiftCode extends Transform with TypingTransformers { result } } finally printTypings = saved - case ValDef(mods, name, tpt, rhs) if (freeMutableVars(sym)) => // box mutable variables that are accessed from a local closure - val tpt1 = TypeTree(sym.tpe) setPos tpt.pos - /* Creating a constructor argument if one isn't present. */ - val constructorArg = rhs match { - case EmptyTree => gen.mkZero(atPhase(phase.prev)(sym.tpe)) - case _ => transform(rhs) - } - val rhs1 = typer.typedPos(rhs.pos) { - Apply(Select(New(TypeTree(sym.tpe)), nme.CONSTRUCTOR), List(constructorArg)) - } - sym resetFlag MUTABLE - sym removeAnnotation VolatileAttr - converted += sym // dereference boxed variables - treeCopy.ValDef(tree, mods &~ MUTABLE, name, tpt1, rhs1) - case Ident(name) if freeMutableVars(sym) => - localTyper.typedPos(tree.pos) { - Select(tree setType sym.tpe, nme.elem) - } case _ => super.transform(tree) } @@ -170,74 +144,6 @@ abstract class LiftCode extends Transform with TypingTransformers { New(TypeTree(appliedType(definitions.CodeClass.typeConstructor, List(treetpe.widen))), List(List(arg))) } - - /** - * PP: There is apparently some degree of overlap between the CAPTURED - * flag and the role being filled here. I think this is how this was able - * to go for so long looking only at DefDef and Ident nodes, as bugs - * would only emerge under more complicated conditions such as #3855. - * I'll try to figure it all out, but if someone who already knows the - * whole story wants to fill it in, that too would be great. - * - * XXX I found this had been cut and pasted between LiftCode and UnCurry, - * and seems to be running in both. - */ - private val freeLocalsTraverser = new Traverser { - var currentMethod: Symbol = NoSymbol - var maybeEscaping = false - - def withEscaping(body: => Unit) { - val saved = maybeEscaping - maybeEscaping = true - try body - finally maybeEscaping = saved - } - - override def traverse(tree: Tree) = tree match { - case DefDef(_, _, _, _, _, _) => - val lastMethod = currentMethod - currentMethod = tree.symbol - try super.traverse(tree) - finally currentMethod = lastMethod - /** A method call with a by-name parameter represents escape. */ - case Apply(fn, args) if fn.symbol.paramss.nonEmpty => - traverse(fn) - treeInfo.foreachMethodParamAndArg(tree) { (param, arg) => - if (param.tpe != null && isByNameParamType(param.tpe)) - withEscaping(traverse(arg)) - else - traverse(arg) - } - - /** The rhs of a closure represents escape. */ - case Function(vparams, body) => - vparams foreach traverse - withEscaping(traverse(body)) - - /** - * The appearance of an ident outside the method where it was defined or - * anytime maybeEscaping is true implies escape. - */ - case Ident(_) => - val sym = tree.symbol - if (sym.isVariable && sym.owner.isMethod && (maybeEscaping || sym.owner != currentMethod)) { - freeMutableVars += sym - val symTpe = sym.tpe - val symClass = symTpe.typeSymbol - atPhase(phase.next) { - def refType(valueRef: Map[Symbol, Symbol], objectRefClass: Symbol) = - if (isValueClass(symClass) && symClass != UnitClass) valueRef(symClass).tpe - else appliedType(objectRefClass.typeConstructor, List(symTpe)) - - sym updateInfo ( - if (sym.hasAnnotation(VolatileAttr)) refType(volatileRefClass, VolatileObjectRefClass) - else refType(refClass, ObjectRefClass)) - } - } - case _ => - super.traverse(tree) - } - } } /** @@ -385,7 +291,10 @@ abstract class LiftCode extends Transform with TypingTransformers { else { if (sym.isTerm) { if (reifyDebug) println("Free: " + sym) - mirrorCall("freeVar", reify(sym.name.toString), reify(sym.tpe), Ident(sym)) + val symtpe = lambdaLift.boxIfCaptured(sym, sym.tpe, erasedTypes = false) + def markIfCaptured(arg: Ident): Tree = + if (sym.isCapturedVariable) referenceCapturedVariable(arg) else arg + mirrorCall("freeVar", reify(sym.name.toString), reify(symtpe), markIfCaptured(Ident(sym))) } else { if (reifyDebug) println("Late local: " + sym) registerReifiableSymbol(sym) @@ -471,7 +380,10 @@ abstract class LiftCode extends Transform with TypingTransformers { case This(_) if !(boundSyms contains tree.symbol) => reifyFree(tree) case Ident(_) if !(boundSyms contains tree.symbol) => - reifyFree(tree) + if (tree.symbol.isVariable && tree.symbol.owner.isTerm) { + captureVariable(tree.symbol) // Note order dependency: captureVariable needs to come before reifyTree here. + mirrorCall("Select", reifyFree(tree), reifyName(nme.elem)) + } else reifyFree(tree) case tt: TypeTree if (tt.tpe != null) => if (!(boundSyms exists (tt.tpe contains _))) mirrorCall("TypeTree", reifyType(tt.tpe)) else if (tt.original != null) reify(tt.original) diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala index 2bed5bffd4..3536608efd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala @@ -248,7 +248,7 @@ abstract class Duplicators extends Analyzer { case vdef @ ValDef(mods, name, tpt, rhs) => // log("vdef fixing tpe: " + tree.tpe + " with sym: " + tree.tpe.typeSymbol + " and " + invalidSyms) - if (mods.hasFlag(Flags.LAZY)) vdef.symbol.resetFlag(Flags.MUTABLE) + //if (mods.hasFlag(Flags.LAZY)) vdef.symbol.resetFlag(Flags.MUTABLE) // Martin to Iulian: lazy vars can now appear because they are no longer boxed; Please check that deleting this statement is OK. vdef.tpt.tpe = fixType(vdef.tpt.tpe) vdef.tpe = null super.typed(vdef, mode, pt) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 6b6b905e16..9991836344 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -4271,6 +4271,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { else typedIdent(name) + case ReferenceToBoxed(idt @ Ident(_)) => + val id1 = typed1(idt, mode, pt) match { case id: Ident => id } + treeCopy.ReferenceToBoxed(tree, id1) setType AnyRefClass.tpe + case Literal(value) => tree setType ( if (value.tag == UnitTag) UnitClass.tpe diff --git a/src/library/scala/reflect/api/MacroContext.scala b/src/library/scala/reflect/api/MacroContext.scala new file mode 100644 index 0000000000..e23357d26e --- /dev/null +++ b/src/library/scala/reflect/api/MacroContext.scala @@ -0,0 +1,15 @@ +package scala.reflect +package api + +trait MacroContext extends Universe { + + /** Mark a variable as captured; i.e. force boxing in a *Ref type. + */ + def captureVariable(vble: Symbol): Unit + + /** Mark given identifier as a reference to a captured variable itself + * suppressing dereferencing with the `elem` field. + */ + def referenceCapturedVariable(id: Ident): Tree + +} \ No newline at end of file -- cgit v1.2.3 From beb875187914b12b1b9dbb5621447067e2926c7c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 2 Jan 2012 19:10:41 +0100 Subject: Changed boxing of free mutable variables to be flexible wrt when liftcode takes place. A major redesign that unifies the various different approaches to boxing of free variables. Free variables are marked with CAPTURED and eliminated by LambdaLift. I also added some hooks in MacroContext that a reifier needs to use. --- src/compiler/scala/tools/nsc/Global.scala | 3 +- src/compiler/scala/tools/nsc/MacroContext.scala | 10 ++ src/compiler/scala/tools/nsc/ast/Trees.scala | 22 +++++ .../scala/tools/nsc/transform/LambdaLift.scala | 67 ++++++++----- .../scala/tools/nsc/transform/LiftCode.scala | 104 ++------------------- .../scala/tools/nsc/typechecker/Duplicators.scala | 2 +- .../scala/tools/nsc/typechecker/Typers.scala | 4 + src/library/scala/reflect/api/MacroContext.scala | 15 +++ 8 files changed, 105 insertions(+), 122 deletions(-) create mode 100644 src/compiler/scala/tools/nsc/MacroContext.scala create mode 100644 src/library/scala/reflect/api/MacroContext.scala (limited to 'src/library') diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index f70aa60309..2dd32e355b 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -39,6 +39,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb with Trees with TreePrinters with DocComments + with MacroContext with symtab.Positions { override def settings = currentSettings @@ -151,7 +152,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb /** Register top level class (called on entering the class) */ def registerTopLevelSym(sym: Symbol) {} - + // ------------------ Reporting ------------------------------------- // not deprecated yet, but a method called "error" imported into diff --git a/src/compiler/scala/tools/nsc/MacroContext.scala b/src/compiler/scala/tools/nsc/MacroContext.scala new file mode 100644 index 0000000000..e739eade3a --- /dev/null +++ b/src/compiler/scala/tools/nsc/MacroContext.scala @@ -0,0 +1,10 @@ +package scala.tools.nsc + +import symtab.Flags._ + +trait MacroContext extends reflect.api.MacroContext { self: Global => + + def captureVariable(vble: Symbol): Unit = vble setFlag CAPTURED + + def referenceCapturedVariable(id: Ident): Tree = ReferenceToBoxed(id) +} diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 30ee7fc885..88a9b5e18b 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -44,6 +44,15 @@ trait Trees extends reflect.internal.Trees { self: Global => /** emitted by typer, eliminated by refchecks */ case class TypeTreeWithDeferredRefCheck()(val check: () => TypeTree) extends TypTree + + /** Marks underlying reference to id as boxed. + * @pre: id must refer to a captured variable + * A reference such marked will refer to the boxed entity, no dereferencing + * with `.elem` is done on it. + * This tree node can be emitted by macros such as reify that call markBoxedReference. + * It is eliminated in LambdaLift, where the boxing conversion takes place. + */ + case class ReferenceToBoxed(idt: Ident) extends TermTree // --- factory methods ---------------------------------------------------------- @@ -152,6 +161,8 @@ trait Trees extends reflect.internal.Trees { self: Global => traverser.traverse(lhs); traverser.traverse(rhs) case SelectFromArray(qualifier, selector, erasure) => traverser.traverse(qualifier) + case ReferenceToBoxed(idt) => + traverser.traverse(idt) case TypeTreeWithDeferredRefCheck() => // TODO: should we traverse the wrapped tree? // (and rewrap the result? how to update the deferred check? would need to store wrapped tree instead of returning it from check) case _ => super.xtraverse(traverser, tree) @@ -161,6 +172,7 @@ trait Trees extends reflect.internal.Trees { self: Global => def DocDef(tree: Tree, comment: DocComment, definition: Tree): DocDef def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree): AssignOrNamedArg def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type): SelectFromArray + def ReferenceToBoxed(tree: Tree, idt: Ident): ReferenceToBoxed def TypeTreeWithDeferredRefCheck(tree: Tree): TypeTreeWithDeferredRefCheck } @@ -174,6 +186,8 @@ trait Trees extends reflect.internal.Trees { self: Global => new AssignOrNamedArg(lhs, rhs).copyAttrs(tree) def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type) = new SelectFromArray(qualifier, selector, erasure).copyAttrs(tree) + def ReferenceToBoxed(tree: Tree, idt: Ident) = + new ReferenceToBoxed(idt).copyAttrs(tree) def TypeTreeWithDeferredRefCheck(tree: Tree) = tree match { case dc@TypeTreeWithDeferredRefCheck() => new TypeTreeWithDeferredRefCheck()(dc.check).copyAttrs(tree) } @@ -195,6 +209,11 @@ trait Trees extends reflect.internal.Trees { self: Global => if (qualifier0 == qualifier) && (selector0 == selector) => t case _ => this.treeCopy.SelectFromArray(tree, qualifier, selector, erasure) } + def ReferenceToBoxed(tree: Tree, idt: Ident) = tree match { + case t @ ReferenceToBoxed(idt0) + if (idt0 == idt) => t + case _ => this.treeCopy.ReferenceToBoxed(tree, idt) + } def TypeTreeWithDeferredRefCheck(tree: Tree) = tree match { case t @ TypeTreeWithDeferredRefCheck() => t case _ => this.treeCopy.TypeTreeWithDeferredRefCheck(tree) @@ -220,6 +239,9 @@ trait Trees extends reflect.internal.Trees { self: Global => case SelectFromArray(qualifier, selector, erasure) => transformer.treeCopy.SelectFromArray( tree, transformer.transform(qualifier), selector, erasure) + case ReferenceToBoxed(idt) => + transformer.treeCopy.ReferenceToBoxed( + tree, transformer.transform(idt) match { case idt1: Ident => idt1 }) case TypeTreeWithDeferredRefCheck() => transformer.treeCopy.TypeTreeWithDeferredRefCheck(tree) } diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala index 2310eae9bb..2180fd4f3a 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -17,6 +17,19 @@ abstract class LambdaLift extends InfoTransform { /** the following two members override abstract members in Transform */ val phaseName: String = "lambdalift" + + /** Converts types of captured variables to *Ref types. + */ + def boxIfCaptured(sym: Symbol, tpe: Type, erasedTypes: Boolean) = + if (sym.isCapturedVariable) { + val symClass = tpe.typeSymbol + def refType(valueRef: Map[Symbol, Symbol], objectRefClass: Symbol) = + if (isValueClass(symClass) && symClass != UnitClass) valueRef(symClass).tpe + else if (erasedTypes) objectRefClass.tpe + else appliedType(objectRefClass.typeConstructor, List(tpe)) + if (sym.hasAnnotation(VolatileAttr)) refType(volatileRefClass, VolatileObjectRefClass) + else refType(refClass, ObjectRefClass) + } else tpe private val lifted = new TypeMap { def apply(tp: Type): Type = tp match { @@ -31,7 +44,8 @@ abstract class LambdaLift extends InfoTransform { } } - def transformInfo(sym: Symbol, tp: Type): Type = lifted(tp) + def transformInfo(sym: Symbol, tp: Type): Type = + boxIfCaptured(sym, lifted(tp), erasedTypes = true) protected def newTransformer(unit: CompilationUnit): Transformer = new LambdaLifter(unit) @@ -55,7 +69,10 @@ abstract class LambdaLift extends InfoTransform { /** Buffers for lifted out classes and methods */ private val liftedDefs = new LinkedHashMap[Symbol, List[Tree]] - + + /** True if we are transforming under a ReferenceToBoxed node */ + private var isBoxedRef = false + private type SymSet = TreeSet[Symbol] private def newSymSet = new TreeSet[Symbol](_ isLess _) @@ -116,22 +133,7 @@ abstract class LambdaLift extends InfoTransform { } changedFreeVars = true debuglog("" + sym + " is free in " + enclosure); - if (sym.isVariable && !sym.hasFlag(CAPTURED)) { - // todo: We should merge this with the lifting done in liftCode. - // We do have to lift twice: in liftCode, because Code[T] needs to see the lifted version - // and here again because lazy bitmaps are introduced later and get lifted here. - // But we should factor out the code and run it twice. - sym setFlag CAPTURED - val symClass = sym.tpe.typeSymbol - atPhase(phase.next) { - sym updateInfo ( - if (sym.hasAnnotation(VolatileAttr)) - if (isValueClass(symClass)) volatileRefClass(symClass).tpe else VolatileObjectRefClass.tpe - else - if (isValueClass(symClass)) refClass(symClass).tpe else ObjectRefClass.tpe - ) - } - } + if (sym.isVariable) sym setFlag CAPTURED } !enclosure.isClass } @@ -340,7 +342,7 @@ abstract class LambdaLift extends InfoTransform { EmptyTree } - private def postTransform(tree: Tree): Tree = { + private def postTransform(tree: Tree, isBoxedRef: Boolean = false): Tree = { val sym = tree.symbol tree match { case ClassDef(_, _, _, _) => @@ -363,8 +365,19 @@ abstract class LambdaLift extends InfoTransform { } case arg => arg } + /** Wrap expr argument in new *Ref(..) constructor, but make + * sure that Try expressions stay at toplevel. + */ + def refConstr(expr: Tree): Tree = expr match { + case Try(block, catches, finalizer) => + Try(refConstr(block), catches map refConstrCase, finalizer) + case _ => + Apply(Select(New(TypeTree(sym.tpe)), nme.CONSTRUCTOR), List(expr)) + } + def refConstrCase(cdef: CaseDef): CaseDef = + CaseDef(cdef.pat, cdef.guard, refConstr(cdef.body)) treeCopy.ValDef(tree, mods, name, tpt1, typer.typedPos(rhs.pos) { - Apply(Select(New(TypeTree(sym.tpe)), nme.CONSTRUCTOR), List(constructorArg)) + refConstr(constructorArg) }) } else tree case Return(Block(stats, value)) => @@ -388,7 +401,7 @@ abstract class LambdaLift extends InfoTransform { atPos(tree.pos)(proxyRef(sym)) else tree else tree - if (sym.isCapturedVariable) + if (sym.isCapturedVariable && !isBoxedRef) atPos(tree.pos) { val tp = tree.tpe val elemTree = typer typed Select(tree1 setType sym.tpe, nme.elem) @@ -406,10 +419,16 @@ abstract class LambdaLift extends InfoTransform { tree } } + + private def preTransform(tree: Tree) = super.transform(tree) setType lifted(tree.tpe) - override def transform(tree: Tree): Tree = - postTransform(super.transform(tree) setType lifted(tree.tpe)) - + override def transform(tree: Tree): Tree = tree match { + case ReferenceToBoxed(idt) => + postTransform(preTransform(idt), isBoxedRef = true) + case _ => + postTransform(preTransform(tree)) + } + /** Transform statements and add lifted definitions to them. */ override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = { def addLifted(stat: Tree): Tree = stat match { diff --git a/src/compiler/scala/tools/nsc/transform/LiftCode.scala b/src/compiler/scala/tools/nsc/transform/LiftCode.scala index 720509644b..171d1df975 100644 --- a/src/compiler/scala/tools/nsc/transform/LiftCode.scala +++ b/src/compiler/scala/tools/nsc/transform/LiftCode.scala @@ -110,18 +110,10 @@ abstract class LiftCode extends Transform with TypingTransformers { } } - /** Set of mutable local variables that are free in some inner method. */ - private val freeMutableVars: mutable.Set[Symbol] = new mutable.HashSet - private val converted: mutable.Set[Symbol] = new mutable.HashSet // debug - override def transformUnit(unit: CompilationUnit) { - freeMutableVars.clear() - freeLocalsTraverser(unit.body) atPhase(phase.next) { super.transformUnit(unit) } - for (v <- freeMutableVars) //!!! remove - assert(converted contains v, "unconverted: " + v + " in " + v.owner + " in unit " + unit) } override def transform(tree: Tree): Tree = { @@ -137,24 +129,6 @@ abstract class LiftCode extends Transform with TypingTransformers { result } } finally printTypings = saved - case ValDef(mods, name, tpt, rhs) if (freeMutableVars(sym)) => // box mutable variables that are accessed from a local closure - val tpt1 = TypeTree(sym.tpe) setPos tpt.pos - /* Creating a constructor argument if one isn't present. */ - val constructorArg = rhs match { - case EmptyTree => gen.mkZero(atPhase(phase.prev)(sym.tpe)) - case _ => transform(rhs) - } - val rhs1 = typer.typedPos(rhs.pos) { - Apply(Select(New(TypeTree(sym.tpe)), nme.CONSTRUCTOR), List(constructorArg)) - } - sym resetFlag MUTABLE - sym removeAnnotation VolatileAttr - converted += sym // dereference boxed variables - treeCopy.ValDef(tree, mods &~ MUTABLE, name, tpt1, rhs1) - case Ident(name) if freeMutableVars(sym) => - localTyper.typedPos(tree.pos) { - Select(tree setType sym.tpe, nme.elem) - } case _ => super.transform(tree) } @@ -170,74 +144,6 @@ abstract class LiftCode extends Transform with TypingTransformers { New(TypeTree(appliedType(definitions.CodeClass.typeConstructor, List(treetpe.widen))), List(List(arg))) } - - /** - * PP: There is apparently some degree of overlap between the CAPTURED - * flag and the role being filled here. I think this is how this was able - * to go for so long looking only at DefDef and Ident nodes, as bugs - * would only emerge under more complicated conditions such as #3855. - * I'll try to figure it all out, but if someone who already knows the - * whole story wants to fill it in, that too would be great. - * - * XXX I found this had been cut and pasted between LiftCode and UnCurry, - * and seems to be running in both. - */ - private val freeLocalsTraverser = new Traverser { - var currentMethod: Symbol = NoSymbol - var maybeEscaping = false - - def withEscaping(body: => Unit) { - val saved = maybeEscaping - maybeEscaping = true - try body - finally maybeEscaping = saved - } - - override def traverse(tree: Tree) = tree match { - case DefDef(_, _, _, _, _, _) => - val lastMethod = currentMethod - currentMethod = tree.symbol - try super.traverse(tree) - finally currentMethod = lastMethod - /** A method call with a by-name parameter represents escape. */ - case Apply(fn, args) if fn.symbol.paramss.nonEmpty => - traverse(fn) - treeInfo.foreachMethodParamAndArg(tree) { (param, arg) => - if (param.tpe != null && isByNameParamType(param.tpe)) - withEscaping(traverse(arg)) - else - traverse(arg) - } - - /** The rhs of a closure represents escape. */ - case Function(vparams, body) => - vparams foreach traverse - withEscaping(traverse(body)) - - /** - * The appearance of an ident outside the method where it was defined or - * anytime maybeEscaping is true implies escape. - */ - case Ident(_) => - val sym = tree.symbol - if (sym.isVariable && sym.owner.isMethod && (maybeEscaping || sym.owner != currentMethod)) { - freeMutableVars += sym - val symTpe = sym.tpe - val symClass = symTpe.typeSymbol - atPhase(phase.next) { - def refType(valueRef: Map[Symbol, Symbol], objectRefClass: Symbol) = - if (isValueClass(symClass) && symClass != UnitClass) valueRef(symClass).tpe - else appliedType(objectRefClass.typeConstructor, List(symTpe)) - - sym updateInfo ( - if (sym.hasAnnotation(VolatileAttr)) refType(volatileRefClass, VolatileObjectRefClass) - else refType(refClass, ObjectRefClass)) - } - } - case _ => - super.traverse(tree) - } - } } /** @@ -385,7 +291,10 @@ abstract class LiftCode extends Transform with TypingTransformers { else { if (sym.isTerm) { if (reifyDebug) println("Free: " + sym) - mirrorCall("freeVar", reify(sym.name.toString), reify(sym.tpe), Ident(sym)) + val symtpe = lambdaLift.boxIfCaptured(sym, sym.tpe, erasedTypes = false) + def markIfCaptured(arg: Ident): Tree = + if (sym.isCapturedVariable) referenceCapturedVariable(arg) else arg + mirrorCall("freeVar", reify(sym.name.toString), reify(symtpe), markIfCaptured(Ident(sym))) } else { if (reifyDebug) println("Late local: " + sym) registerReifiableSymbol(sym) @@ -471,7 +380,10 @@ abstract class LiftCode extends Transform with TypingTransformers { case This(_) if !(boundSyms contains tree.symbol) => reifyFree(tree) case Ident(_) if !(boundSyms contains tree.symbol) => - reifyFree(tree) + if (tree.symbol.isVariable && tree.symbol.owner.isTerm) { + captureVariable(tree.symbol) // Note order dependency: captureVariable needs to come before reifyTree here. + mirrorCall("Select", reifyFree(tree), reifyName(nme.elem)) + } else reifyFree(tree) case tt: TypeTree if (tt.tpe != null) => if (!(boundSyms exists (tt.tpe contains _))) mirrorCall("TypeTree", reifyType(tt.tpe)) else if (tt.original != null) reify(tt.original) diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala index 2bed5bffd4..3536608efd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala @@ -248,7 +248,7 @@ abstract class Duplicators extends Analyzer { case vdef @ ValDef(mods, name, tpt, rhs) => // log("vdef fixing tpe: " + tree.tpe + " with sym: " + tree.tpe.typeSymbol + " and " + invalidSyms) - if (mods.hasFlag(Flags.LAZY)) vdef.symbol.resetFlag(Flags.MUTABLE) + //if (mods.hasFlag(Flags.LAZY)) vdef.symbol.resetFlag(Flags.MUTABLE) // Martin to Iulian: lazy vars can now appear because they are no longer boxed; Please check that deleting this statement is OK. vdef.tpt.tpe = fixType(vdef.tpt.tpe) vdef.tpe = null super.typed(vdef, mode, pt) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 6b6b905e16..9991836344 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -4271,6 +4271,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { else typedIdent(name) + case ReferenceToBoxed(idt @ Ident(_)) => + val id1 = typed1(idt, mode, pt) match { case id: Ident => id } + treeCopy.ReferenceToBoxed(tree, id1) setType AnyRefClass.tpe + case Literal(value) => tree setType ( if (value.tag == UnitTag) UnitClass.tpe diff --git a/src/library/scala/reflect/api/MacroContext.scala b/src/library/scala/reflect/api/MacroContext.scala new file mode 100644 index 0000000000..e23357d26e --- /dev/null +++ b/src/library/scala/reflect/api/MacroContext.scala @@ -0,0 +1,15 @@ +package scala.reflect +package api + +trait MacroContext extends Universe { + + /** Mark a variable as captured; i.e. force boxing in a *Ref type. + */ + def captureVariable(vble: Symbol): Unit + + /** Mark given identifier as a reference to a captured variable itself + * suppressing dereferencing with the `elem` field. + */ + def referenceCapturedVariable(id: Ident): Tree + +} \ No newline at end of file -- cgit v1.2.3 From 5618b77ca8d89b8f44db062334ac2b0663596dee Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 27 Dec 2011 10:36:27 -0800 Subject: Added option -Xlog-reflective-calls. A message is emitted when a reflective call is generated. We can now be eager consumers of this since we purged all the reflective calls at some point -- but without a backstop, they have been slipping back in. --- src/compiler/scala/tools/nsc/settings/ScalaSettings.scala | 1 + src/compiler/scala/tools/nsc/transform/CleanUp.scala | 6 +++++- src/library/scala/collection/parallel/mutable/ParHashMap.scala | 5 ++--- 3 files changed, 8 insertions(+), 4 deletions(-) (limited to 'src/library') diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index a712f4cba2..efd5323ce2 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -68,6 +68,7 @@ trait ScalaSettings extends AbsScalaSettings val genPhaseGraph = StringSetting ("-Xgenerate-phase-graph", "file", "Generate the phase graphs (outputs .dot files) to fileX.dot.", "") val XlogImplicits = BooleanSetting ("-Xlog-implicits", "Show more detail on why some implicits are not applicable.") val logImplicitConv = BooleanSetting ("-Xlog-implicit-conversions", "Print a message whenever an implicit conversion is inserted.") + val logReflectiveCalls = BooleanSetting("-Xlog-reflective-calls", "Print a message when a reflective method call is generated") val maxClassfileName = IntSetting ("-Xmax-classfile-name", "Maximum filename length for generated classes", 255, Some((72, 255)), _ => None) val Xmigration28 = BooleanSetting ("-Xmigration", "Warn about constructs whose behavior may have changed between 2.7 and 2.8.") val nouescape = BooleanSetting ("-Xno-uescape", "Disable handling of \\u unicode escapes.") diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index 98345dd01e..575fe8f295 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -106,6 +106,9 @@ abstract class CleanUp extends Transform with ast.TreeDSL { * refinement, where the refinement defines a parameter based on a * type variable. */ case ad@ApplyDynamic(qual0, params) => + if (settings.logReflectiveCalls.value) + unit.echo(ad.pos, "method invocation uses reflection") + val typedPos = typedWithPos(ad.pos) _ assert(ad.symbol.isPublic) @@ -502,7 +505,8 @@ abstract class CleanUp extends Transform with ast.TreeDSL { * expected to be an AnyRef. */ val t: Tree = ad.symbol.tpe match { case MethodType(mparams, resType) => - assert(params.length == mparams.length) + assert(params.length == mparams.length, mparams) + typedPos { val sym = currentOwner.newValue(ad.pos, mkTerm("qual")) setInfo qual0.tpe qual = safeREF(sym) diff --git a/src/library/scala/collection/parallel/mutable/ParHashMap.scala b/src/library/scala/collection/parallel/mutable/ParHashMap.scala index 37065e32fc..31750b0b0d 100644 --- a/src/library/scala/collection/parallel/mutable/ParHashMap.scala +++ b/src/library/scala/collection/parallel/mutable/ParHashMap.scala @@ -190,7 +190,7 @@ extends collection.parallel.BucketCombiner[(K, V), ParHashMap[K, V], DefaultEntr } else { // construct a normal table and fill it sequentially // TODO parallelize by keeping separate sizemaps and merging them - val table = new HashTable[K, DefaultEntry[K, V]] { + object table extends HashTable[K, DefaultEntry[K, V]] { def insertEntry(e: DefaultEntry[K, V]) = if (super.findEntry(e.key) eq null) super.addEntry(e) sizeMapInit(table.length) } @@ -201,8 +201,7 @@ extends collection.parallel.BucketCombiner[(K, V), ParHashMap[K, V], DefaultEntr } i += 1 } - val c = table.hashTableContents - new ParHashMap(c) + new ParHashMap(table.hashTableContents) } /* classes */ -- cgit v1.2.3 From d188f6fdded6fdd9df3960d6085b9b80046c05ca Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 3 Jan 2012 11:11:45 -0800 Subject: Added forall to Option. Another salvo in the war against option2Iterable. --- src/library/scala/Option.scala | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/library') diff --git a/src/library/scala/Option.scala b/src/library/scala/Option.scala index bd498de847..6db4904b93 100644 --- a/src/library/scala/Option.scala +++ b/src/library/scala/Option.scala @@ -192,6 +192,13 @@ sealed abstract class Option[+A] extends Product with Serializable { @inline final def exists(p: A => Boolean): Boolean = !isEmpty && p(this.get) + /** Returns true if this option is empty '''or''' the predicate + * $p returns true when applied to this $option's value. + * + * @param p the predicate to test + */ + @inline final def forall(p: A => Boolean): Boolean = isEmpty || p(this.get) + /** Apply the given procedure $f to the option's value, * if it is nonempty. Otherwise, do nothing. * -- cgit v1.2.3 From 020053c3215579e8aeb871a4ad0078516994270d Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Thu, 5 Jan 2012 14:26:01 -0800 Subject: More consistent use of Names. Several large helpings of tedium later, fewer strings are being discarded like so much refuse. Some names now cache a String, but only "named Names", so it's not very many and they pay for themselves pretty quickly. Many fewer name-related implicit conversions now taking place. A number of efficiency related measures. --- .../scala/reflect/internal/Constants.scala | 2 +- .../scala/reflect/internal/Definitions.scala | 324 ++++++++------ .../scala/reflect/internal/Importers.scala | 6 +- .../scala/reflect/internal/NameManglers.scala | 37 +- src/compiler/scala/reflect/internal/Names.scala | 204 ++++++--- src/compiler/scala/reflect/internal/StdNames.scala | 488 +++++++++++++++------ src/compiler/scala/reflect/internal/Symbols.scala | 90 ++-- src/compiler/scala/reflect/internal/TreeInfo.scala | 2 +- src/compiler/scala/reflect/internal/Trees.scala | 8 +- src/compiler/scala/reflect/internal/Types.scala | 2 +- .../reflect/internal/pickling/UnPickler.scala | 20 +- .../scala/reflect/runtime/JavaToScala.scala | 40 +- .../scala/reflect/runtime/ScalaToJava.scala | 14 +- src/compiler/scala/reflect/runtime/ToolBoxes.scala | 6 +- .../scala/reflect/runtime/TreeBuildUtil.scala | 10 +- src/compiler/scala/tools/nsc/ast/DocComments.scala | 6 +- .../scala/tools/nsc/ast/TreeBrowsers.scala | 4 +- src/compiler/scala/tools/nsc/ast/TreeGen.scala | 16 +- .../scala/tools/nsc/ast/parser/Parsers.scala | 20 +- .../tools/nsc/ast/parser/SymbolicXMLBuilder.scala | 4 +- .../scala/tools/nsc/backend/JavaPlatform.scala | 6 +- .../nsc/backend/icode/ExceptionHandlers.scala | 12 +- .../scala/tools/nsc/backend/icode/GenICode.scala | 8 +- .../scala/tools/nsc/backend/icode/Members.scala | 1 - .../scala/tools/nsc/backend/jvm/GenAndroid.scala | 11 +- .../scala/tools/nsc/backend/jvm/GenJVM.scala | 12 +- .../scala/tools/nsc/backend/jvm/GenJVMUtil.scala | 23 +- .../scala/tools/nsc/backend/msil/GenMSIL.scala | 4 +- .../scala/tools/nsc/backend/opt/Inliners.scala | 4 +- .../scala/tools/nsc/dependencies/Changes.scala | 4 +- .../scala/tools/nsc/interactive/Global.scala | 2 +- .../scala/tools/nsc/interactive/Picklers.scala | 2 +- .../scala/tools/nsc/interpreter/Dossiers.scala | 3 +- .../scala/tools/nsc/interpreter/ExprTyper.scala | 31 +- .../scala/tools/nsc/interpreter/ILoop.scala | 19 +- .../scala/tools/nsc/interpreter/IMain.scala | 79 ++-- .../scala/tools/nsc/interpreter/Imports.scala | 17 +- .../tools/nsc/interpreter/JLineCompletion.scala | 76 ++-- .../tools/nsc/interpreter/MemberHandlers.scala | 6 +- .../scala/tools/nsc/interpreter/Naming.scala | 2 +- .../scala/tools/nsc/interpreter/Power.scala | 2 +- .../scala/tools/nsc/javac/JavaParsers.scala | 14 +- .../scala/tools/nsc/matching/Patterns.scala | 10 +- .../nsc/symtab/classfile/ClassfileParser.scala | 33 +- .../tools/nsc/symtab/classfile/ICodeReader.scala | 13 +- .../tools/nsc/symtab/classfile/MetaParser.scala | 2 +- .../scala/tools/nsc/symtab/clr/TypeParser.scala | 6 +- .../scala/tools/nsc/transform/CleanUp.scala | 93 ++-- .../scala/tools/nsc/transform/Constructors.scala | 5 +- .../scala/tools/nsc/transform/Erasure.scala | 13 +- .../scala/tools/nsc/transform/ExplicitOuter.scala | 4 +- .../scala/tools/nsc/transform/LiftCode.scala | 37 +- .../scala/tools/nsc/transform/TailCalls.scala | 2 +- .../scala/tools/nsc/transform/UnCurry.scala | 6 +- .../scala/tools/nsc/typechecker/Implicits.scala | 6 +- .../scala/tools/nsc/typechecker/Macros.scala | 15 +- .../tools/nsc/typechecker/MethodSynthesis.scala | 2 +- .../scala/tools/nsc/typechecker/Namers.scala | 2 +- .../tools/nsc/typechecker/PatMatVirtualiser.scala | 33 +- .../tools/nsc/typechecker/SyntheticMethods.scala | 16 +- .../scala/tools/nsc/typechecker/Typers.scala | 2 +- .../scala/tools/nsc/typechecker/Unapplies.scala | 7 +- .../scala/tools/nsc/util/ProxyReport.scala | 14 +- .../plugin/scala/tools/selectivecps/CPSUtils.scala | 45 +- .../tools/selectivecps/SelectiveANFTransform.scala | 2 +- .../tools/selectivecps/SelectiveCPSTransform.scala | 20 +- src/library/scala/io/Codec.scala | 10 +- src/library/scala/reflect/Manifest.scala | 31 +- src/library/scala/reflect/api/Trees.scala | 6 + src/scalap/scala/tools/scalap/JavaWriter.scala | 20 +- src/scalap/scala/tools/scalap/Main.scala | 3 +- src/scalap/scala/tools/scalap/Names.scala | 96 ---- .../scalax/rules/scalasig/ScalaSigPrinter.scala | 3 +- 73 files changed, 1205 insertions(+), 993 deletions(-) delete mode 100644 src/scalap/scala/tools/scalap/Names.scala (limited to 'src/library') diff --git a/src/compiler/scala/reflect/internal/Constants.scala b/src/compiler/scala/reflect/internal/Constants.scala index 2edb0d1fe6..9c4b2b2245 100644 --- a/src/compiler/scala/reflect/internal/Constants.scala +++ b/src/compiler/scala/reflect/internal/Constants.scala @@ -217,7 +217,7 @@ trait Constants extends api.Constants { } def escapedStringValue: String = { - def escape(text: String): String = (text map escapedChar) mkString "" + def escape(text: String): String = text flatMap escapedChar tag match { case NullTag => "null" case StringTag => "\"" + escape(stringValue) + "\"" diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index 900d62476c..aee3938715 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -6,6 +6,7 @@ package scala.reflect package internal +import annotation.{ switch } import scala.collection.{ mutable, immutable } import Flags._ import PartialFunction._ @@ -60,8 +61,8 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val numericWeight = symbolsMapFilt(ScalaValueClasses, nameToWeight.keySet, nameToWeight) lazy val boxedModule = classesMap(x => getModule(boxedName(x))) lazy val boxedClass = classesMap(x => getClass(boxedName(x))) - lazy val refClass = classesMap(x => getClass("scala.runtime." + x + "Ref")) - lazy val volatileRefClass = classesMap(x => getClass("scala.runtime.Volatile" + x + "Ref")) + lazy val refClass = classesMap(x => getRequiredClass("scala.runtime." + x + "Ref")) + lazy val volatileRefClass = classesMap(x => getRequiredClass("scala.runtime.Volatile" + x + "Ref")) lazy val boxMethod = classesMap(x => valueModuleMethod(x, nme.box)) lazy val unboxMethod = classesMap(x => valueModuleMethod(x, nme.unbox)) @@ -85,12 +86,6 @@ trait Definitions extends reflect.api.StandardDefinitions { def isGetClass(sym: Symbol) = (sym.name == nme.getClass_) && (sym.paramss.isEmpty || sym.paramss.head.isEmpty) - private[Definitions] def fullNameStrings: List[String] = nme.ScalaValueNames map ("scala." + _) - private[Definitions] lazy val fullValueName: Set[Name] = { - val values = nme.ScalaValueNames flatMap (x => List(newTypeName("scala." + x), newTermName("scala." + x))) - values.toSet + newTypeName("scala.AnyVal") - } - lazy val AnyValClass = valueCache(tpnme.AnyVal) lazy val UnitClass = valueCache(tpnme.Unit) lazy val ByteClass = valueCache(tpnme.Byte) @@ -151,8 +146,10 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val ScalaPackage = getModule(nme.scala_) lazy val ScalaPackageClass = ScalaPackage.moduleClass - lazy val RuntimePackage = getModule("scala.runtime") + lazy val RuntimePackage = getRequiredModule("scala.runtime") lazy val RuntimePackageClass = RuntimePackage.moduleClass + + lazy val JavaLangEnumClass = getRequiredClass("java.lang.Enum") // convenient one-argument parameter lists lazy val anyparam = List(AnyClass.typeConstructor) @@ -163,17 +160,45 @@ trait Definitions extends reflect.api.StandardDefinitions { private def booltype = BooleanClass.typeConstructor private def inttype = IntClass.typeConstructor private def stringtype = StringClass.typeConstructor + + // Java types + def javaTypeName(jclazz: Class[_]): TypeName = newTypeName(jclazz.getName) + + def javaTypeToValueClass(jtype: Class[_]): Symbol = jtype match { + case java.lang.Void.TYPE => UnitClass + case java.lang.Byte.TYPE => ByteClass + case java.lang.Character.TYPE => CharClass + case java.lang.Short.TYPE => ShortClass + case java.lang.Integer.TYPE => IntClass + case java.lang.Long.TYPE => LongClass + case java.lang.Float.TYPE => FloatClass + case java.lang.Double.TYPE => DoubleClass + case java.lang.Boolean.TYPE => BooleanClass + case _ => NoSymbol + } + def valueClassToJavaType(sym: Symbol): Class[_] = sym match { + case UnitClass => java.lang.Void.TYPE + case ByteClass => java.lang.Byte.TYPE + case CharClass => java.lang.Character.TYPE + case ShortClass => java.lang.Short.TYPE + case IntClass => java.lang.Integer.TYPE + case LongClass => java.lang.Long.TYPE + case FloatClass => java.lang.Float.TYPE + case DoubleClass => java.lang.Double.TYPE + case BooleanClass => java.lang.Boolean.TYPE + case _ => null + } // top types lazy val AnyClass = newClass(ScalaPackageClass, tpnme.Any, Nil) setFlag (ABSTRACT) lazy val AnyRefClass = newAlias(ScalaPackageClass, tpnme.AnyRef, ObjectClass.typeConstructor) lazy val ObjectClass = getClass(sn.Object) - lazy val AnyCompanionClass = getClass("scala.AnyCompanion") setFlag (SEALED | ABSTRACT | TRAIT) - lazy val AnyValCompanionClass = getClass("scala.AnyValCompanion") setFlag (SEALED | ABSTRACT | TRAIT) + lazy val AnyCompanionClass = getRequiredClass("scala.AnyCompanion") setFlag (SEALED | ABSTRACT | TRAIT) + lazy val AnyValCompanionClass = getRequiredClass("scala.AnyValCompanion") setFlag (SEALED | ABSTRACT | TRAIT) // bottom types - lazy val RuntimeNothingClass = getClass(ClassfileConstants.SCALA_NOTHING) - lazy val RuntimeNullClass = getClass(ClassfileConstants.SCALA_NULL) + lazy val RuntimeNothingClass = getClass(fulltpnme.RuntimeNothing) + lazy val RuntimeNullClass = getClass(fulltpnme.RuntimeNull) sealed abstract class BottomClassSymbol(name: TypeName, parent: Symbol) extends ClassSymbol(ScalaPackageClass, NoPosition, name) { locally { @@ -194,25 +219,25 @@ trait Definitions extends reflect.api.StandardDefinitions { } // exceptions and other throwables - lazy val ClassCastExceptionClass = getClass("java.lang.ClassCastException") + lazy val ClassCastExceptionClass = getRequiredClass("java.lang.ClassCastException") lazy val IndexOutOfBoundsExceptionClass = getClass(sn.IOOBException) lazy val InvocationTargetExceptionClass = getClass(sn.InvTargetException) - lazy val MatchErrorClass = getClass("scala.MatchError") - lazy val NonLocalReturnControlClass = getClass("scala.runtime.NonLocalReturnControl") + lazy val MatchErrorClass = getRequiredClass("scala.MatchError") + lazy val NonLocalReturnControlClass = getRequiredClass("scala.runtime.NonLocalReturnControl") lazy val NullPointerExceptionClass = getClass(sn.NPException) lazy val ThrowableClass = getClass(sn.Throwable) - lazy val UninitializedErrorClass = getClass("scala.UninitializedFieldError") + lazy val UninitializedErrorClass = getRequiredClass("scala.UninitializedFieldError") // fundamental reference classes lazy val ScalaObjectClass = getMember(ScalaPackageClass, tpnme.ScalaObject) - lazy val PartialFunctionClass = getClass("scala.PartialFunction") - lazy val AbstractPartialFunctionClass = getClass("scala.runtime.AbstractPartialFunction") - lazy val SymbolClass = getClass("scala.Symbol") + lazy val PartialFunctionClass = getRequiredClass("scala.PartialFunction") + lazy val AbstractPartialFunctionClass = getRequiredClass("scala.runtime.AbstractPartialFunction") + lazy val SymbolClass = getRequiredClass("scala.Symbol") lazy val StringClass = getClass(sn.String) lazy val StringModule = StringClass.linkedClassOfClass lazy val ClassClass = getClass(sn.Class) def Class_getMethod = getMember(ClassClass, nme.getMethod_) - lazy val DynamicClass = getClass("scala.Dynamic") + lazy val DynamicClass = getRequiredClass("scala.Dynamic") // fundamental modules lazy val SysPackage = getPackageObject("scala.sys") @@ -223,7 +248,7 @@ trait Definitions extends reflect.api.StandardDefinitions { // Those modules and their module classes lazy val UnqualifiedOwners = UnqualifiedModules.toSet ++ UnqualifiedModules.map(_.moduleClass) - lazy val PredefModule: Symbol = getModule("scala.Predef") + lazy val PredefModule: Symbol = getRequiredModule("scala.Predef") lazy val PredefModuleClass = PredefModule.moduleClass // Note: this is not the type alias AnyRef, it's a val defined in Predef // used by the @specialize annotation. @@ -242,26 +267,26 @@ trait Definitions extends reflect.api.StandardDefinitions { (sym.name == name) && (sym.owner == PredefModule.moduleClass) ) - lazy val ConsoleModule: Symbol = getModule("scala.Console") - lazy val ScalaRunTimeModule: Symbol = getModule("scala.runtime.ScalaRunTime") - lazy val SymbolModule: Symbol = getModule("scala.Symbol") + lazy val ConsoleModule: Symbol = getRequiredModule("scala.Console") + lazy val ScalaRunTimeModule: Symbol = getRequiredModule("scala.runtime.ScalaRunTime") + lazy val SymbolModule: Symbol = getRequiredModule("scala.Symbol") lazy val Symbol_apply = getMember(SymbolModule, nme.apply) def SeqFactory = getMember(ScalaRunTimeModule, nme.Seq) - def arrayApplyMethod = getMember(ScalaRunTimeModule, "array_apply") - def arrayUpdateMethod = getMember(ScalaRunTimeModule, "array_update") - def arrayLengthMethod = getMember(ScalaRunTimeModule, "array_length") - def arrayCloneMethod = getMember(ScalaRunTimeModule, "array_clone") - def ensureAccessibleMethod = getMember(ScalaRunTimeModule, "ensureAccessible") + def arrayApplyMethod = getMember(ScalaRunTimeModule, nme.array_apply) + def arrayUpdateMethod = getMember(ScalaRunTimeModule, nme.array_update) + def arrayLengthMethod = getMember(ScalaRunTimeModule, nme.array_length) + def arrayCloneMethod = getMember(ScalaRunTimeModule, nme.array_clone) + def ensureAccessibleMethod = getMember(ScalaRunTimeModule, nme.ensureAccessible) def scalaRuntimeSameElements = getMember(ScalaRunTimeModule, nme.sameElements) // classes with special meanings - lazy val StringAddClass = getClass("scala.runtime.StringAdd") - lazy val ArrowAssocClass = getClass("scala.Predef.ArrowAssoc") + lazy val StringAddClass = getRequiredClass("scala.runtime.StringAdd") + lazy val ArrowAssocClass = getRequiredClass("scala.Predef.ArrowAssoc") lazy val StringAdd_+ = getMember(StringAddClass, nme.PLUS) - lazy val NotNullClass = getClass("scala.NotNull") - lazy val ScalaNumberClass = getClass("scala.math.ScalaNumber") - lazy val TraitSetterAnnotationClass = getClass("scala.runtime.TraitSetter") - lazy val DelayedInitClass = getClass("scala.DelayedInit") + lazy val NotNullClass = getRequiredClass("scala.NotNull") + lazy val ScalaNumberClass = getRequiredClass("scala.math.ScalaNumber") + lazy val TraitSetterAnnotationClass = getRequiredClass("scala.runtime.TraitSetter") + lazy val DelayedInitClass = getRequiredClass("scala.DelayedInit") def delayedInitMethod = getMember(DelayedInitClass, nme.delayedInit) // a dummy value that communicates that a delayedInit call is compiler-generated // from phase UnCurry to phase Constructors @@ -269,14 +294,14 @@ trait Definitions extends reflect.api.StandardDefinitions { // def delayedInitArgVal = EmptyPackageClass.newValue(NoPosition, nme.delayedInitArg) // .setInfo(UnitClass.tpe) - lazy val TypeConstraintClass = getClass("scala.annotation.TypeConstraint") + lazy val TypeConstraintClass = getRequiredClass("scala.annotation.TypeConstraint") lazy val SingletonClass = newClass(ScalaPackageClass, tpnme.Singleton, anyparam) setFlag (ABSTRACT | TRAIT | FINAL) - lazy val SerializableClass = getClass("scala.Serializable") + lazy val SerializableClass = getRequiredClass("scala.Serializable") lazy val JavaSerializableClass = getClass(sn.JavaSerializable) - lazy val ComparableClass = getClass("java.lang.Comparable") - lazy val JavaCloneableClass = getClass("java.lang.Cloneable") - lazy val RemoteInterfaceClass = getClass("java.rmi.Remote") - lazy val RemoteExceptionClass = getClass("java.rmi.RemoteException") + lazy val ComparableClass = getRequiredClass("java.lang.Comparable") + lazy val JavaCloneableClass = getRequiredClass("java.lang.Cloneable") + lazy val RemoteInterfaceClass = getRequiredClass("java.rmi.Remote") + lazy val RemoteExceptionClass = getRequiredClass("java.rmi.RemoteException") lazy val RepeatedParamClass = newCovariantPolyClass( ScalaPackageClass, @@ -326,66 +351,68 @@ trait Definitions extends reflect.api.StandardDefinitions { val clazz = newClass(ScalaPackageClass, tpnme.EQUALS_PATTERN_NAME, Nil) clazz setInfo polyType(List(newTypeParam(clazz, 0)), ClassInfoType(anyparam, new Scope, clazz)) } + lazy val MatchingStrategyClass = getRequiredClass("scala.MatchingStrategy") // collections classes - lazy val ConsClass = getClass("scala.collection.immutable.$colon$colon") - lazy val IterableClass = getClass("scala.collection.Iterable") - lazy val IteratorClass = getClass("scala.collection.Iterator") - lazy val ListClass = getClass("scala.collection.immutable.List") - lazy val SeqClass = getClass("scala.collection.Seq") - lazy val StringBuilderClass = getClass("scala.collection.mutable.StringBuilder") - lazy val TraversableClass = getClass("scala.collection.Traversable") - - lazy val ListModule = getModule("scala.collection.immutable.List") + lazy val ConsClass = getRequiredClass("scala.collection.immutable.$colon$colon") + lazy val IterableClass = getRequiredClass("scala.collection.Iterable") + lazy val IteratorClass = getRequiredClass("scala.collection.Iterator") + lazy val ListClass = getRequiredClass("scala.collection.immutable.List") + lazy val SeqClass = getRequiredClass("scala.collection.Seq") + lazy val StringBuilderClass = getRequiredClass("scala.collection.mutable.StringBuilder") + lazy val TraversableClass = getRequiredClass("scala.collection.Traversable") + + lazy val ListModule = getRequiredModule("scala.collection.immutable.List") lazy val List_apply = getMember(ListModule, nme.apply) - lazy val NilModule = getModule("scala.collection.immutable.Nil") - lazy val SeqModule = getModule("scala.collection.Seq") + lazy val NilModule = getRequiredModule("scala.collection.immutable.Nil") + lazy val SeqModule = getRequiredModule("scala.collection.Seq") + lazy val IteratorModule = getRequiredModule("scala.collection.Iterator") + lazy val Iterator_apply = getMember(IteratorModule, nme.apply) // arrays and their members - lazy val ArrayModule = getModule("scala.Array") + lazy val ArrayModule = getRequiredModule("scala.Array") lazy val ArrayModule_overloadedApply = getMember(ArrayModule, nme.apply) - lazy val ArrayClass = getClass("scala.Array") + lazy val ArrayClass = getRequiredClass("scala.Array") lazy val Array_apply = getMember(ArrayClass, nme.apply) lazy val Array_update = getMember(ArrayClass, nme.update) lazy val Array_length = getMember(ArrayClass, nme.length) lazy val Array_clone = getMember(ArrayClass, nme.clone_) // reflection / structural types - lazy val SoftReferenceClass = getClass("java.lang.ref.SoftReference") - lazy val WeakReferenceClass = getClass("java.lang.ref.WeakReference") + lazy val SoftReferenceClass = getRequiredClass("java.lang.ref.SoftReference") + lazy val WeakReferenceClass = getRequiredClass("java.lang.ref.WeakReference") lazy val MethodClass = getClass(sn.MethodAsObject) def methodClass_setAccessible = getMember(MethodClass, nme.setAccessible) - lazy val EmptyMethodCacheClass = getClass("scala.runtime.EmptyMethodCache") - lazy val MethodCacheClass = getClass("scala.runtime.MethodCache") + lazy val EmptyMethodCacheClass = getRequiredClass("scala.runtime.EmptyMethodCache") + lazy val MethodCacheClass = getRequiredClass("scala.runtime.MethodCache") def methodCache_find = getMember(MethodCacheClass, nme.find_) def methodCache_add = getMember(MethodCacheClass, nme.add_) // scala.reflect - lazy val ReflectApiUniverse = getClass("scala.reflect.api.Universe") - lazy val ReflectRuntimeMirror = getModule("scala.reflect.runtime.Mirror") - def freeValueMethod = getMember(ReflectRuntimeMirror, "freeValue") + lazy val ReflectApiUniverse = getRequiredClass("scala.reflect.api.Universe") + lazy val ReflectRuntimeMirror = getRequiredModule("scala.reflect.runtime.Mirror") + def freeValueMethod = getMember(ReflectRuntimeMirror, nme.freeValue) lazy val ReflectPackage = getPackageObject("scala.reflect") - def Reflect_mirror = getMember(ReflectPackage, "mirror") - - - lazy val PartialManifestClass = getClass("scala.reflect.ClassManifest") - lazy val PartialManifestModule = getModule("scala.reflect.ClassManifest") - lazy val FullManifestClass = getClass("scala.reflect.Manifest") - lazy val FullManifestModule = getModule("scala.reflect.Manifest") - lazy val OptManifestClass = getClass("scala.reflect.OptManifest") - lazy val NoManifest = getModule("scala.reflect.NoManifest") + def Reflect_mirror = getMember(ReflectPackage, nme.mirror) + + lazy val PartialManifestClass = getRequiredClass("scala.reflect.ClassManifest") + lazy val PartialManifestModule = getRequiredModule("scala.reflect.ClassManifest") + lazy val FullManifestClass = getRequiredClass("scala.reflect.Manifest") + lazy val FullManifestModule = getRequiredModule("scala.reflect.Manifest") + lazy val OptManifestClass = getRequiredClass("scala.reflect.OptManifest") + lazy val NoManifest = getRequiredModule("scala.reflect.NoManifest") lazy val CodeClass = getClass(sn.Code) lazy val CodeModule = getModule(sn.Code) lazy val Code_lift = getMember(CodeModule, nme.lift_) - lazy val ScalaSignatureAnnotation = getClass("scala.reflect.ScalaSignature") - lazy val ScalaLongSignatureAnnotation = getClass("scala.reflect.ScalaLongSignature") + lazy val ScalaSignatureAnnotation = getRequiredClass("scala.reflect.ScalaSignature") + lazy val ScalaLongSignatureAnnotation = getRequiredClass("scala.reflect.ScalaLongSignature") // Option classes - lazy val OptionClass: Symbol = getClass("scala.Option") - lazy val SomeClass: Symbol = getClass("scala.Some") - lazy val NoneModule: Symbol = getModule("scala.None") - lazy val SomeModule: Symbol = getModule("scala.Some") + lazy val OptionClass: Symbol = getRequiredClass("scala.Option") + lazy val SomeClass: Symbol = getRequiredClass("scala.Some") + lazy val NoneModule: Symbol = getRequiredModule("scala.None") + lazy val SomeModule: Symbol = getRequiredModule("scala.Some") /** Note: don't use this manifest/type function for anything important, * as it is incomplete. Would love to have things like existential types @@ -441,7 +468,7 @@ trait Definitions extends reflect.api.StandardDefinitions { // Product, Tuple, Function private def mkArityArray(name: String, arity: Int, countFrom: Int = 1): Array[Symbol] = { - val list = countFrom to arity map (i => getClass("scala." + name + i)) + val list = countFrom to arity map (i => getRequiredClass("scala." + name + i)) if (countFrom == 0) list.toArray else (NoSymbol +: list).toArray } @@ -457,10 +484,24 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val FunctionClass = mkArityArray("Function", MaxFunctionArity, 0) lazy val AbstractFunctionClass = mkArityArray("runtime.AbstractFunction", MaxFunctionArity, 0) lazy val isProductNClass = ProductClass.toSet + def wrapArrayMethodName(elemtp: Type): TermName = elemtp.typeSymbol match { + case ByteClass => nme.wrapByteArray + case ShortClass => nme.wrapShortArray + case CharClass => nme.wrapCharArray + case IntClass => nme.wrapIntArray + case LongClass => nme.wrapLongArray + case FloatClass => nme.wrapFloatArray + case DoubleClass => nme.wrapDoubleArray + case BooleanClass => nme.wrapBooleanArray + case UnitClass => nme.wrapUnitArray + case _ => + if ((elemtp <:< AnyRefClass.tpe) && !isPhantomClass(elemtp.typeSymbol)) nme.wrapRefArray + else nme.genericWrapArray + } - def tupleField(n: Int, j: Int) = getMember(TupleClass(n), "_" + j) - def isTupleType(tp: Type): Boolean = isTupleType(tp, false) - def isTupleTypeOrSubtype(tp: Type): Boolean = isTupleType(tp, true) + def tupleField(n: Int, j: Int) = getMember(TupleClass(n), nme.productAccessorName(j)) + def isTupleType(tp: Type): Boolean = isTupleType(tp, false) + def isTupleTypeOrSubtype(tp: Type): Boolean = isTupleType(tp, true) private def isTupleType(tp: Type, subtypeOK: Boolean) = tp.normalize match { case TypeRef(_, sym, args) if args.nonEmpty => val len = args.length @@ -479,7 +520,7 @@ trait Definitions extends reflect.api.StandardDefinitions { } else NoType } - lazy val ProductRootClass: Symbol = getClass("scala.Product") + lazy val ProductRootClass: Symbol = getRequiredClass("scala.Product") def Product_productArity = getMember(ProductRootClass, nme.productArity) def Product_productElement = getMember(ProductRootClass, nme.productElement) // def Product_productElementName = getMember(ProductRootClass, nme.productElementName) @@ -548,9 +589,10 @@ trait Definitions extends reflect.api.StandardDefinitions { case _ => NoType } - def seqType(arg: Type) = appliedType(SeqClass.typeConstructor, List(arg)) - def arrayType(arg: Type) = appliedType(ArrayClass.typeConstructor, List(arg)) - def byNameType(arg: Type) = appliedType(ByNameParamClass.typeConstructor, List(arg)) + def seqType(arg: Type) = appliedType(SeqClass.typeConstructor, List(arg)) + def arrayType(arg: Type) = appliedType(ArrayClass.typeConstructor, List(arg)) + def byNameType(arg: Type) = appliedType(ByNameParamClass.typeConstructor, List(arg)) + def iteratorOfType(tp: Type) = appliedType(IteratorClass.typeConstructor, List(tp)) def ClassType(arg: Type) = if (phase.erasedTypes || forMSIL) ClassClass.tpe @@ -560,7 +602,7 @@ trait Definitions extends reflect.api.StandardDefinitions { // .NET backend // - lazy val ComparatorClass = getClass("scala.runtime.Comparator") + lazy val ComparatorClass = getRequiredClass("scala.runtime.Comparator") // System.ValueType lazy val ValueTypeClass: Symbol = getClass(sn.ValueType) // System.MulticastDelegate @@ -605,10 +647,10 @@ trait Definitions extends reflect.api.StandardDefinitions { var Object_## : Symbol = _ var Object_synchronized: Symbol = _ lazy val Object_isInstanceOf = newPolyMethod( - ObjectClass, "$isInstanceOf", + ObjectClass, newTermName("$isInstanceOf"), tparam => MethodType(List(), booltype)) setFlag (FINAL | SYNTHETIC) lazy val Object_asInstanceOf = newPolyMethod( - ObjectClass, "$asInstanceOf", + ObjectClass, newTermName("$asInstanceOf"), tparam => MethodType(List(), tparam.typeConstructor)) setFlag (FINAL | SYNTHETIC) def Object_getClass = getMember(ObjectClass, nme.getClass_) @@ -623,57 +665,57 @@ trait Definitions extends reflect.api.StandardDefinitions { var String_+ : Symbol = _ // boxed classes - lazy val ObjectRefClass = getClass("scala.runtime.ObjectRef") - lazy val VolatileObjectRefClass = getClass("scala.runtime.VolatileObjectRef") - lazy val BoxesRunTimeClass = getModule("scala.runtime.BoxesRunTime") + lazy val ObjectRefClass = getRequiredClass("scala.runtime.ObjectRef") + lazy val VolatileObjectRefClass = getRequiredClass("scala.runtime.VolatileObjectRef") + lazy val BoxesRunTimeClass = getRequiredModule("scala.runtime.BoxesRunTime") lazy val BoxedNumberClass = getClass(sn.BoxedNumber) lazy val BoxedCharacterClass = getClass(sn.BoxedCharacter) lazy val BoxedBooleanClass = getClass(sn.BoxedBoolean) - lazy val BoxedByteClass = getClass("java.lang.Byte") - lazy val BoxedShortClass = getClass("java.lang.Short") - lazy val BoxedIntClass = getClass("java.lang.Integer") - lazy val BoxedLongClass = getClass("java.lang.Long") - lazy val BoxedFloatClass = getClass("java.lang.Float") - lazy val BoxedDoubleClass = getClass("java.lang.Double") - - lazy val BoxedUnitClass = getClass("scala.runtime.BoxedUnit") - lazy val BoxedUnitModule = getModule("scala.runtime.BoxedUnit") - def BoxedUnit_UNIT = getMember(BoxedUnitModule, "UNIT") - def BoxedUnit_TYPE = getMember(BoxedUnitModule, "TYPE") + lazy val BoxedByteClass = getRequiredClass("java.lang.Byte") + lazy val BoxedShortClass = getRequiredClass("java.lang.Short") + lazy val BoxedIntClass = getRequiredClass("java.lang.Integer") + lazy val BoxedLongClass = getRequiredClass("java.lang.Long") + lazy val BoxedFloatClass = getRequiredClass("java.lang.Float") + lazy val BoxedDoubleClass = getRequiredClass("java.lang.Double") + + lazy val BoxedUnitClass = getRequiredClass("scala.runtime.BoxedUnit") + lazy val BoxedUnitModule = getRequiredModule("scala.runtime.BoxedUnit") + def BoxedUnit_UNIT = getMember(BoxedUnitModule, nme.UNIT) + def BoxedUnit_TYPE = getMember(BoxedUnitModule, nme.TYPE_) // Annotation base classes - lazy val AnnotationClass = getClass("scala.annotation.Annotation") - lazy val ClassfileAnnotationClass = getClass("scala.annotation.ClassfileAnnotation") - lazy val StaticAnnotationClass = getClass("scala.annotation.StaticAnnotation") + lazy val AnnotationClass = getRequiredClass("scala.annotation.Annotation") + lazy val ClassfileAnnotationClass = getRequiredClass("scala.annotation.ClassfileAnnotation") + lazy val StaticAnnotationClass = getRequiredClass("scala.annotation.StaticAnnotation") // Annotations - lazy val BridgeClass = getClass("scala.annotation.bridge") - lazy val ElidableMethodClass = getClass("scala.annotation.elidable") - lazy val ImplicitNotFoundClass = getClass("scala.annotation.implicitNotFound") - lazy val MigrationAnnotationClass = getClass("scala.annotation.migration") - lazy val ScalaStrictFPAttr = getClass("scala.annotation.strictfp") - lazy val SerializableAttr = getClass("scala.annotation.serializable") // @serializable is deprecated - lazy val SwitchClass = getClass("scala.annotation.switch") - lazy val TailrecClass = getClass("scala.annotation.tailrec") - lazy val VarargsClass = getClass("scala.annotation.varargs") - lazy val uncheckedStableClass = getClass("scala.annotation.unchecked.uncheckedStable") - lazy val uncheckedVarianceClass = getClass("scala.annotation.unchecked.uncheckedVariance") - - lazy val BeanPropertyAttr = getClass("scala.beans.BeanProperty") - lazy val BooleanBeanPropertyAttr = getClass("scala.beans.BooleanBeanProperty") - lazy val CloneableAttr = getClass("scala.cloneable") - lazy val DeprecatedAttr = getClass("scala.deprecated") - lazy val DeprecatedNameAttr = getClass("scala.deprecatedName") - lazy val NativeAttr = getClass("scala.native") - lazy val RemoteAttr = getClass("scala.remote") - lazy val ScalaInlineClass = getClass("scala.inline") - lazy val ScalaNoInlineClass = getClass("scala.noinline") - lazy val SerialVersionUIDAttr = getClass("scala.SerialVersionUID") - lazy val SpecializedClass = getClass("scala.specialized") - lazy val ThrowsClass = getClass("scala.throws") - lazy val TransientAttr = getClass("scala.transient") - lazy val UncheckedClass = getClass("scala.unchecked") - lazy val VolatileAttr = getClass("scala.volatile") + lazy val BridgeClass = getRequiredClass("scala.annotation.bridge") + lazy val ElidableMethodClass = getRequiredClass("scala.annotation.elidable") + lazy val ImplicitNotFoundClass = getRequiredClass("scala.annotation.implicitNotFound") + lazy val MigrationAnnotationClass = getRequiredClass("scala.annotation.migration") + lazy val ScalaStrictFPAttr = getRequiredClass("scala.annotation.strictfp") + lazy val SerializableAttr = getRequiredClass("scala.annotation.serializable") // @serializable is deprecated + lazy val SwitchClass = getRequiredClass("scala.annotation.switch") + lazy val TailrecClass = getRequiredClass("scala.annotation.tailrec") + lazy val VarargsClass = getRequiredClass("scala.annotation.varargs") + lazy val uncheckedStableClass = getRequiredClass("scala.annotation.unchecked.uncheckedStable") + lazy val uncheckedVarianceClass = getRequiredClass("scala.annotation.unchecked.uncheckedVariance") + + lazy val BeanPropertyAttr = getRequiredClass("scala.beans.BeanProperty") + lazy val BooleanBeanPropertyAttr = getRequiredClass("scala.beans.BooleanBeanProperty") + lazy val CloneableAttr = getRequiredClass("scala.cloneable") + lazy val DeprecatedAttr = getRequiredClass("scala.deprecated") + lazy val DeprecatedNameAttr = getRequiredClass("scala.deprecatedName") + lazy val NativeAttr = getRequiredClass("scala.native") + lazy val RemoteAttr = getRequiredClass("scala.remote") + lazy val ScalaInlineClass = getRequiredClass("scala.inline") + lazy val ScalaNoInlineClass = getRequiredClass("scala.noinline") + lazy val SerialVersionUIDAttr = getRequiredClass("scala.SerialVersionUID") + lazy val SpecializedClass = getRequiredClass("scala.specialized") + lazy val ThrowsClass = getRequiredClass("scala.throws") + lazy val TransientAttr = getRequiredClass("scala.transient") + lazy val UncheckedClass = getRequiredClass("scala.unchecked") + lazy val VolatileAttr = getRequiredClass("scala.volatile") // Meta-annotations lazy val BeanGetterTargetClass = getMetaAnnotation("beanGetter") @@ -684,7 +726,7 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val SetterTargetClass = getMetaAnnotation("setter") // TODO: module, moduleClass? package, packageObject? - private def getMetaAnnotation(name: String) = getClass("scala.annotation.meta." + name) + private def getMetaAnnotation(name: String) = getRequiredClass("scala.annotation.meta." + name) def isMetaAnnotation(sym: Symbol): Boolean = metaAnnotations(sym) || ( // Trying to allow for deprecated locations sym.isAliasType && isMetaAnnotation(sym.info.typeSymbol) @@ -702,11 +744,11 @@ trait Definitions extends reflect.api.StandardDefinitions { attr } - def getPackageObjectClass(fullname: Name): Symbol = + def getPackageObjectClass(fullname: String): Symbol = getPackageObject(fullname).companionClass - def getPackageObject(fullname: Name): Symbol = - getModule(fullname).info member nme.PACKAGE + def getPackageObject(fullname: String): Symbol = + getModule(newTermName(fullname)).info member nme.PACKAGE def getModule(fullname: Name): Symbol = getModuleOrClass(fullname.toTermName) @@ -716,6 +758,11 @@ trait Definitions extends reflect.api.StandardDefinitions { while (result.isAliasType) result = result.info.typeSymbol result } + + def getRequiredModule(fullname: String): Symbol = + getModule(newTermNameCached(fullname)) + def getRequiredClass(fullname: String): Symbol = + getClass(newTypeNameCached(fullname)) def getClassIfDefined(fullname: String): Symbol = getClassIfDefined(newTypeName(fullname)) @@ -953,8 +1000,7 @@ trait Definitions extends reflect.api.StandardDefinitions { ObjectClass, nme.synchronized_, tparam => msym => MethodType(msym.newSyntheticValueParams(List(tparam.typeConstructor)), tparam.typeConstructor)) setFlag FINAL - String_+ = newMethod( - StringClass, "+", anyparam, stringtype) setFlag FINAL + String_+ = newMethod(StringClass, nme.raw.PLUS, anyparam, stringtype) setFlag FINAL val forced = List( // force initialization of every symbol that is entered as a side effect AnnotationDefaultAttr, // #2264 @@ -987,7 +1033,7 @@ trait Definitions extends reflect.api.StandardDefinitions { assert(forMSIL, "scalaCallers can only be created if target is .NET") // object: reference to object on which to call (scala-)method val paramTypes: List[Type] = List(ObjectClass.tpe) - val name: String = "$scalaCaller$$" + nbScalaCallers + val name = newTermName("$scalaCaller$$" + nbScalaCallers) // tparam => resultType, which is the resultType of PolyType, i.e. the result type after applying the // type parameter =-> a MethodType in this case // TODO: set type bounds manually (-> MulticastDelegate), see newTypeParam diff --git a/src/compiler/scala/reflect/internal/Importers.scala b/src/compiler/scala/reflect/internal/Importers.scala index a4af4bf8f3..6683778671 100644 --- a/src/compiler/scala/reflect/internal/Importers.scala +++ b/src/compiler/scala/reflect/internal/Importers.scala @@ -20,8 +20,8 @@ trait Importers { self: SymbolTable => def importSymbol(sym: from.Symbol): Symbol = { def doImport(sym: from.Symbol): Symbol = { val myowner = importSymbol(sym.owner) - val mypos = importPosition(sym.pos) - val myname = importName(sym.name) + val mypos = importPosition(sym.pos) + val myname = importName(sym.name).toTermName def linkReferenced(mysym: TermSymbol, x: from.TermSymbol, op: from.Symbol => Symbol): Symbol = { symMap(x) = mysym mysym.referenced = op(x.referenced) @@ -33,7 +33,7 @@ trait Importers { self: SymbolTable => case x: from.ModuleSymbol => linkReferenced(new ModuleSymbol(myowner, mypos, myname), x, doImport) case x: from.FreeVar => - new FreeVar(importName(x.name), importType(x.tpe), x.value) + new FreeVar(importName(x.name).toTermName, importType(x.tpe), x.value) case x: from.TermSymbol => linkReferenced(new TermSymbol(myowner, mypos, myname), x, importSymbol) case x: from.TypeSkolem => diff --git a/src/compiler/scala/reflect/internal/NameManglers.scala b/src/compiler/scala/reflect/internal/NameManglers.scala index d4aa6339ff..ef092f16bb 100644 --- a/src/compiler/scala/reflect/internal/NameManglers.scala +++ b/src/compiler/scala/reflect/internal/NameManglers.scala @@ -23,8 +23,8 @@ trait NameManglers { val MODULE_SUFFIX_STRING = NameTransformer.MODULE_SUFFIX_STRING val NAME_JOIN_STRING = NameTransformer.NAME_JOIN_STRING - val MODULE_SUFFIX_NAME: TermName = MODULE_SUFFIX_STRING - val NAME_JOIN_NAME: TermName = NAME_JOIN_STRING + val MODULE_SUFFIX_NAME: TermName = newTermName(MODULE_SUFFIX_STRING) + val NAME_JOIN_NAME: TermName = newTermName(NAME_JOIN_STRING) def flattenedName(segments: Name*): NameType = compactedString(segments mkString NAME_JOIN_STRING) @@ -75,12 +75,12 @@ trait NameManglers { val LOCALDUMMY_PREFIX = "") - def productAccessorName(i: Int): TermName = newTermName("_" + i) def superName(name: Name): TermName = newTermName(SUPER_PREFIX_STRING + name) /** The name of an accessor for protected symbols. */ diff --git a/src/compiler/scala/reflect/internal/Names.scala b/src/compiler/scala/reflect/internal/Names.scala index 8453b1e758..b960695f51 100644 --- a/src/compiler/scala/reflect/internal/Names.scala +++ b/src/compiler/scala/reflect/internal/Names.scala @@ -71,25 +71,38 @@ trait Names extends api.Names { } /** Create a term name from the characters in cs[offset..offset+len-1]. */ - def newTermName(cs: Array[Char], offset: Int, len: Int): TermName = { + def newTermName(cs: Array[Char], offset: Int, len: Int): TermName = + newTermName(cs, offset, len, cachedString = null) + + def newTermName(cs: Array[Char]): TermName = newTermName(cs, 0, cs.length) + def newTypeName(cs: Array[Char]): TypeName = newTypeName(cs, 0, cs.length) + + /** Create a term name from the characters in cs[offset..offset+len-1]. */ + protected def newTermName(cs: Array[Char], offset: Int, len: Int, cachedString: String): TermName = { val h = hashValue(cs, offset, len) & HASH_MASK var n = termHashtable(h) while ((n ne null) && (n.length != len || !equals(n.start, cs, offset, len))) n = n.next - if (n eq null) { + + if (n ne null) n + else { // The logic order here is future-proofing against the possibility // that name.toString will become an eager val, in which case the call // to enterChars cannot follow the construction of the TermName. val ncStart = nc enterChars(cs, offset, len) - n = new TermName(ncStart, len, h) + if (cachedString ne null) new TermName_S(ncStart, len, h, cachedString) + else new TermName_R(ncStart, len, h) } - n } + protected def newTypeName(cs: Array[Char], offset: Int, len: Int, cachedString: String): TypeName = + newTermName(cs, offset, len, cachedString).toTypeName /** Create a term name from string. */ - def newTermName(s: String): TermName = - newTermName(s.toCharArray(), 0, s.length()) + def newTermName(s: String): TermName = newTermName(s.toCharArray(), 0, s.length(), null) + + /** Create a type name from string. */ + def newTypeName(s: String): TypeName = newTermName(s).toTypeName /** Create a term name from the UTF8 encoded bytes in bs[offset..offset+len-1]. */ def newTermName(bs: Array[Byte], offset: Int, len: Int): TermName = { @@ -97,13 +110,15 @@ trait Names extends api.Names { newTermName(chars, 0, chars.length) } + def newTermNameCached(s: String): TermName = + newTermName(s.toCharArray(), 0, s.length(), cachedString = s) + + def newTypeNameCached(s: String): TypeName = + newTypeName(s.toCharArray(), 0, s.length(), cachedString = s) + /** Create a type name from the characters in cs[offset..offset+len-1]. */ def newTypeName(cs: Array[Char], offset: Int, len: Int): TypeName = - newTermName(cs, offset, len).toTypeName - - /** Create a type name from string. */ - def newTypeName(s: String): TypeName = - newTermName(s).toTypeName + newTermName(cs, offset, len, cachedString = null).toTypeName /** Create a type name from the UTF8 encoded bytes in bs[offset..offset+len-1]. */ def newTypeName(bs: Array[Byte], offset: Int, len: Int): TypeName = @@ -114,19 +129,27 @@ trait Names extends api.Names { // Classes ---------------------------------------------------------------------- - /** The name class. */ + /** The name class. + * TODO - resolve schizophrenia regarding whether to treat Names as Strings + * or Strings as Names. Give names the key functions the absence of which + * make people want Strings all the time. + */ sealed abstract class Name(protected val index: Int, protected val len: Int) extends AbsName with Function1[Int, Char] { + type ThisNameType <: Name + protected[this] def thisName: ThisNameType + /** Index into name table */ def start: Int = index /** The next name in the same hash bucket. */ - def next: Name + def next: ThisNameType /** The length of this name. */ final def length: Int = len final def isEmpty = length == 0 final def nonEmpty = !isEmpty + def nameKind: String def isTermName: Boolean def isTypeName: Boolean def toTermName: TermName @@ -134,6 +157,15 @@ trait Names extends api.Names { def companionName: Name def bothNames: List[Name] = List(toTermName, toTypeName) + /** Return the subname with characters from from to to-1. */ + def subName(from: Int, to: Int): ThisNameType + + /** Return a new name of the same variety. */ + def newName(str: String): ThisNameType + + /** Return a new name based on string transformation. */ + def mapName(f: String => String): ThisNameType = newName(f(toString)) + /** Copy bytes of this name to buffer cs, starting at position `offset`. */ final def copyChars(cs: Array[Char], offset: Int) = compat.Platform.arraycopy(chrs, index, cs, offset, len) @@ -145,21 +177,13 @@ trait Names extends api.Names { cs } - /** @return the string representation of this name */ - final override def toString(): String = new String(chrs, index, len) - // Should we opt to make toString into a val to avoid the creation - // of 750,000 copies of x$1, here's the line. - // final override val toString = new String(chrs, index, len) - - def debugString() = NameTransformer.decode(toString) + (if (isTypeName) "!" else "") - /** Write to UTF8 representation of this name to given character array. * Start copying to index `to`. Return index of next free byte in array. * Array must have enough remaining space for all bytes * (i.e. maximally 3*length bytes). */ final def copyUTF8(bs: Array[Byte], offset: Int): Int = { - val bytes = Codec toUTF8 chrs.slice(index, index + len) + val bytes = Codec.toUTF8(chrs, index, len) compat.Platform.arraycopy(bytes, 0, bs, offset, bytes.length) offset + bytes.length } @@ -326,17 +350,20 @@ trait Names extends api.Names { final def startsWith(name: String): Boolean = startsWith(newTermName(name)) final def endsWith(char: Char): Boolean = len > 0 && endChar == char final def endsWith(name: String): Boolean = endsWith(newTermName(name)) - final def stripStart(prefix: Name): Name = subName(prefix.length, len) - final def stripStart(prefix: String): Name = subName(prefix.length, len) - final def stripEnd(suffix: Name): Name = subName(0, len - suffix.length) - final def stripEnd(suffix: String): Name = subName(0, len - suffix.length) - - def dropRight(n: Int) = subName(0, len - n) - - def lastIndexOf(ch: Char) = toChars lastIndexOf ch - /** Return the subname with characters from from to to-1. */ - def subName(from: Int, to: Int): Name + def dropRight(n: Int) = subName(0, len - n) + def drop(n: Int) = subName(n, len) + + def indexOf(ch: Char) = { + val idx = pos(ch) + if (idx == length) -1 else idx + } + def indexOf(ch: Char, fromIndex: Int) = { + val idx = pos(ch, fromIndex) + if (idx == length) -1 else idx + } + def lastIndexOf(ch: Char) = lastPos(ch) + def lastIndexOf(ch: Char, fromIndex: Int) = lastPos(ch, fromIndex) /** Replace all occurrences of `from` by `to` in * name; result is always a term name. @@ -351,31 +378,79 @@ trait Names extends api.Names { } newTermName(cs, 0, len) } + + /** TODO - reconcile/fix that encode returns a Name but + * decode returns a String. + */ /** Replace operator symbols by corresponding $op_name. */ - def encode: Name = { + def encode: ThisNameType = { val str = toString val res = NameTransformer.encode(str) - if (res == str) this - else if (isTypeName) newTypeName(res) - else newTermName(res) + if (res == str) thisName else newName(res) } - def append(ch: Char): Name - def append(suffix: String): Name - def append(suffix: Name): Name - /** Replace $op_name by corresponding operator symbol. */ - def decode: String = ( - NameTransformer.decode(toString) + - (if (nameDebug && isTypeName) "!" else ""))//debug + def decode: String = { + if (this containsChar '$') { + val str = toString + val res = NameTransformer.decode(str) + if (res == str) str + else res + } + else toString + } + /** TODO - find some efficiency. */ + def append(ch: Char) = newName("" + this + ch) + def append(suffix: String) = newName("" + this + suffix) + def append(suffix: Name) = newName("" + this + suffix) + def prepend(ch: Char) = newName("" + ch + this) + def prepend(prefix: String) = newName("" + prefix + this) + def prepend(prefix: Name) = newName("" + prefix + this) + + def decodedName: ThisNameType = newName(decode) def isOperatorName: Boolean = decode != toString - def nameKind: String = if (isTypeName) "type" else "term" - def longString: String = nameKind + " " + NameTransformer.decode(toString) + def longString: String = nameKind + " " + decode + def debugString = { val s = decode ; if (isTypeName) s + "!" else s } + } + + /** A name that contains no operator chars nor dollar signs. + * TODO - see if it's any faster to do something along these lines. + */ + trait AlphaNumName extends Name { + final override def encode = thisName + final override def decodedName = thisName + final override def decode = toString + final override def isOperatorName = false + } + + /** TermName_S and TypeName_S have fields containing the string version of the name. + * TermName_R and TypeName_R recreate it each time toString is called. + */ + private class TermName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TermName(index0, len0, hash) { + protected def createCompanionName(h: Int): TypeName = new TypeName_S(index, len, h, toString) + override def newName(str: String): TermName = newTermNameCached(str) + } + private class TypeName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TypeName(index0, len0, hash) { + protected def createCompanionName(h: Int): TermName = new TermName_S(index, len, h, toString) + override def newName(str: String): TypeName = newTypeNameCached(str) + } + + private class TermName_R(index0: Int, len0: Int, hash: Int) extends TermName(index0, len0, hash) { + protected def createCompanionName(h: Int): TypeName = new TypeName_R(index, len, h) + override def toString = new String(chrs, index, len) } - final class TermName(_index: Int, _len: Int, hash: Int) extends Name(_index, _len) { + private class TypeName_R(index0: Int, len0: Int, hash: Int) extends TypeName(index0, len0, hash) { + protected def createCompanionName(h: Int): TermName = new TermName_R(index, len, h) + override def toString = new String(chrs, index, len) + } + + sealed abstract class TermName(index0: Int, len0: Int, hash: Int) extends Name(index0, len0) { + type ThisNameType = TermName + protected[this] def thisName: TermName = this + var next: TermName = termHashtable(hash) termHashtable(hash) = this def isTermName: Boolean = true @@ -385,20 +460,24 @@ trait Names extends api.Names { val h = hashValue(chrs, index, len) & HASH_MASK var n = typeHashtable(h) while ((n ne null) && n.start != index) - n = n.next; - if (n eq null) - n = new TypeName(index, len, h); - n + n = n.next + + if (n ne null) n + else createCompanionName(h) } - def append(ch: Char): TermName = append("" + ch) - def append(suffix: String): TermName = newTermName(this + suffix) - def append(suffix: Name): TermName = append(suffix.toString) + def newName(str: String): TermName = newTermName(str) def companionName: TypeName = toTypeName def subName(from: Int, to: Int): TermName = newTermName(chrs, start + from, to - from) + + def nameKind = "term" + protected def createCompanionName(h: Int): TypeName } - final class TypeName(_index: Int, _len: Int, hash: Int) extends Name(_index, _len) { + sealed abstract class TypeName(index0: Int, len0: Int, hash: Int) extends Name(index0, len0) { + type ThisNameType = TypeName + protected[this] def thisName: TypeName = this + var next: TypeName = typeHashtable(hash) typeHashtable(hash) = this def isTermName: Boolean = false @@ -407,18 +486,19 @@ trait Names extends api.Names { val h = hashValue(chrs, index, len) & HASH_MASK var n = termHashtable(h) while ((n ne null) && n.start != index) - n = n.next; - if (n eq null) - n = new TermName(index, len, h); - n + n = n.next + + if (n ne null) n + else createCompanionName(h) } def toTypeName: TypeName = this - - def append(ch: Char): TypeName = append("" + ch) - def append(suffix: String): TypeName = newTypeName(this + suffix) - def append(suffix: Name): TypeName = append(suffix.toString) + def newName(str: String): TypeName = newTypeName(str) def companionName: TermName = toTermName def subName(from: Int, to: Int): TypeName = newTypeName(chrs, start + from, to - from) + + def nameKind = "type" + override def decode = if (nameDebug) super.decode + "!" else super.decode + protected def createCompanionName(h: Int): TermName } } diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala index 8afe276514..db1cf7f257 100644 --- a/src/compiler/scala/reflect/internal/StdNames.scala +++ b/src/compiler/scala/reflect/internal/StdNames.scala @@ -8,18 +8,21 @@ package internal import scala.collection.immutable import NameTransformer.MODULE_SUFFIX_STRING +import annotation.switch -trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: SymbolTable => +trait StdNames extends NameManglers { self: SymbolTable => - def encode(str: String): TermName = newTermName(NameTransformer.encode(str)) + def encode(str: String): TermName = newTermNameCached(NameTransformer.encode(str)) + + implicit def lowerTermNames(n: TermName): String = "" + n - implicit def stringToTermName(s: String): TermName = newTermName(s) + // implicit def stringToTermName(s: String): TermName = newTermName(s) /** This should be the first trait in the linearization. */ trait Keywords { private var kws: Set[TermName] = Set() private def kw(s: String): TermName = { - val result = newTermName(s) + val result = newTermNameCached(s) kws = kws + result result } @@ -87,7 +90,7 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy trait CommonNames /*extends LibraryCommonNames*/ { type NameType <: Name - implicit def createNameType(name: String): NameType + protected implicit def createNameType(name: String): NameType val EMPTY: NameType = "" val ANON_FUN_NAME: NameType = "$anonfun" @@ -146,6 +149,10 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy final val String: NameType = "String" final val Throwable: NameType = "Throwable" + final val Annotation: NameType = "Annotation" + final val ClassfileAnnotation: NameType = "ClassfileAnnotation" + final val Enum: NameType = "Enum" + // Annotation simple names, used in Namer final val BeanPropertyAnnot: NameType = "BeanProperty" final val BooleanBeanPropertyAnnot: NameType = "BooleanBeanProperty" @@ -172,123 +179,191 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy final val SyntheticATTR: NameType = "Synthetic" } - trait TermNames extends Keywords with CommonNames { // Compiler internal names + val EXPAND_SEPARATOR_STRING = "$$" + val ANYNAME: NameType = "" val CONSTRUCTOR: NameType = "" val FAKE_LOCAL_THIS: NameType = "this$" val INITIALIZER: NameType = CONSTRUCTOR // Is this buying us something? + val LAZY_LOCAL: NameType = "$lzy" + val LOCAL_SUFFIX_STRING = " " + val MACRO: NameType = "macro$" + val MIRROR_PREFIX: NameType = "$mr." + val MIRROR_SHORT: NameType = "$mr" val MIXIN_CONSTRUCTOR: NameType = "$init$" val MODULE_INSTANCE_FIELD: NameType = NameTransformer.MODULE_INSTANCE_NAME // "MODULE$" val OUTER: NameType = "$outer" - val OUTER_LOCAL: NameType = "$outer " // note the space + val OUTER_LOCAL: NameType = OUTER + LOCAL_SUFFIX_STRING // "$outer ", note the space val OUTER_SYNTH: NameType = "" // emitted by virtual pattern matcher, replaced by outer accessor in explicitouter + val SELECTOR_DUMMY: NameType = "" val SELF: NameType = "$this" val SPECIALIZED_INSTANCE: NameType = "specInstance$" val STAR: NameType = "*" val THIS: NameType = "_$this" - val SELECTOR_DUMMY: NameType = "" final val Nil: NameType = "Nil" final val Predef: NameType = "Predef" final val ScalaRunTime: NameType = "ScalaRunTime" final val Some: NameType = "Some" + + val _1 : NameType = "_1" + val _2 : NameType = "_2" + val _3 : NameType = "_3" + val _4 : NameType = "_4" + val _5 : NameType = "_5" + val _6 : NameType = "_6" + val _7 : NameType = "_7" + val _8 : NameType = "_8" + val _9 : NameType = "_9" + val _10 : NameType = "_10" + val _11 : NameType = "_11" + val _12 : NameType = "_12" + val _13 : NameType = "_13" + val _14 : NameType = "_14" + val _15 : NameType = "_15" + val _16 : NameType = "_16" + val _17 : NameType = "_17" + val _18 : NameType = "_18" + val _19 : NameType = "_19" + val _20 : NameType = "_20" + val _21 : NameType = "_21" + val _22 : NameType = "_22" + + val wrapRefArray: NameType = "wrapRefArray" + val wrapByteArray: NameType = "wrapByteArray" + val wrapShortArray: NameType = "wrapShortArray" + val wrapCharArray: NameType = "wrapCharArray" + val wrapIntArray: NameType = "wrapIntArray" + val wrapLongArray: NameType = "wrapLongArray" + val wrapFloatArray: NameType = "wrapFloatArray" + val wrapDoubleArray: NameType = "wrapDoubleArray" + val wrapBooleanArray: NameType = "wrapBooleanArray" + val wrapUnitArray: NameType = "wrapUnitArray" + val genericWrapArray: NameType = "genericWrapArray" // Compiler utilized names // val productElementName: NameType = "productElementName" - val TYPE_ : NameType = "TYPE" - val add_ : NameType = "add" - val anyValClass: NameType = "anyValClass" - val append: NameType = "append" - val apply: NameType = "apply" - val arrayValue: NameType = "arrayValue" - val arraycopy: NameType = "arraycopy" - val asInstanceOf_ : NameType = "asInstanceOf" - val assert_ : NameType = "assert" - val assume_ : NameType = "assume" - val box: NameType = "box" - val bytes: NameType = "bytes" - val canEqual_ : NameType = "canEqual" - val checkInitialized: NameType = "checkInitialized" - val classOf: NameType = "classOf" - val clone_ : NameType = if (forMSIL) "MemberwiseClone" else "clone" // sn.OClone causes checkinit failure - val conforms: NameType = "conforms" - val copy: NameType = "copy" - val delayedInit: NameType = "delayedInit" - val delayedInitArg: NameType = "delayedInit$body" - val drop: NameType = "drop" - val elem: NameType = "elem" - val eq: NameType = "eq" - val equals_ : NameType = if (forMSIL) "Equals" else "equals" - val error: NameType = "error" - val ex: NameType = "ex" - val false_ : NameType = "false" - val filter: NameType = "filter" - val finalize_ : NameType = if (forMSIL) "Finalize" else "finalize" - val find_ : NameType = "find" - val flatMap: NameType = "flatMap" - val foreach: NameType = "foreach" - val formatted: NameType = "formatted" - val genericArrayOps: NameType = "genericArrayOps" - val get: NameType = "get" - val hasNext: NameType = "hasNext" - val hashCode_ : NameType = if (forMSIL) "GetHashCode" else "hashCode" - val hash_ : NameType = "hash" - val head: NameType = "head" - val identity: NameType = "identity" - val inlinedEquals: NameType = "inlinedEquals" - val applyDynamic: NameType = "applyDynamic" - val isArray: NameType = "isArray" - val isDefinedAt: NameType = "isDefinedAt" - val _isDefinedAt: NameType = "_isDefinedAt" - val isEmpty: NameType = "isEmpty" - val isInstanceOf_ : NameType = "isInstanceOf" - val java: NameType = "java" - val lang: NameType = "lang" - val length: NameType = "length" - val lengthCompare: NameType = "lengthCompare" - val lift_ : NameType = "lift" - val macro_ : NameType = "macro" - val main: NameType = "main" - val map: NameType = "map" - val missingCase: NameType = "missingCase" - val ne: NameType = "ne" - val newArray: NameType = "newArray" - val next: NameType = "next" - val notifyAll_ : NameType = "notifyAll" - val notify_ : NameType = "notify" - val null_ : NameType = "null" - val ofDim: NameType = "ofDim" - val productArity: NameType = "productArity" - val productElement: NameType = "productElement" - val productIterator: NameType = "productIterator" - val productPrefix: NameType = "productPrefix" - val readResolve: NameType = "readResolve" - val runOrElse: NameType = "runOrElse" - val sameElements: NameType = "sameElements" - val scala_ : NameType = "scala" - val self: NameType = "self" - val setAccessible: NameType = "setAccessible" - val synchronized_ : NameType = "synchronized" - val tail: NameType = "tail" - val this_ : NameType = "this" - val throw_ : NameType = "throw" - val toArray: NameType = "toArray" - val toList: NameType = "toList" - val toSeq: NameType = "toSeq" - val toString_ : NameType = if (forMSIL) "ToString" else "toString" - val true_ : NameType = "true" - val unapply: NameType = "unapply" - val unapplySeq: NameType = "unapplySeq" - val unbox: NameType = "unbox" - val update: NameType = "update" - val value: NameType = "value" - val view_ : NameType = "view" - val wait_ : NameType = "wait" - val withFilter: NameType = "withFilter" - val wrapRefArray: NameType = "wrapRefArray" - val zip: NameType = "zip" + val Ident: NameType = "Ident" + val TYPE_ : NameType = "TYPE" + val TypeTree: NameType = "TypeTree" + val UNIT : NameType = "UNIT" + val _isDefinedAt: NameType = "_isDefinedAt" + val add_ : NameType = "add" + val annotation: NameType = "annotation" + val anyValClass: NameType = "anyValClass" + val append: NameType = "append" + val apply: NameType = "apply" + val applyDynamic: NameType = "applyDynamic" + val args : NameType = "args" + val argv : NameType = "argv" + val arrayValue: NameType = "arrayValue" + val array_apply : NameType = "array_apply" + val array_clone : NameType = "array_clone" + val array_length : NameType = "array_length" + val array_update : NameType = "array_update" + val arraycopy: NameType = "arraycopy" + val asInstanceOf_ : NameType = "asInstanceOf" + val asTypeConstructor: NameType = "asTypeConstructor" + val assert_ : NameType = "assert" + val assume_ : NameType = "assume" + val box: NameType = "box" + val bytes: NameType = "bytes" + val canEqual_ : NameType = "canEqual" + val checkInitialized: NameType = "checkInitialized" + val classOf: NameType = "classOf" + val clone_ : NameType = if (forMSIL) "MemberwiseClone" else "clone" // sn.OClone causes checkinit failure + val conforms: NameType = "conforms" + val copy: NameType = "copy" + val delayedInit: NameType = "delayedInit" + val delayedInitArg: NameType = "delayedInit$body" + val drop: NameType = "drop" + val elem: NameType = "elem" + val emptyValDef: NameType = "emptyValDef" + val ensureAccessible : NameType = "ensureAccessible" + val eq: NameType = "eq" + val equalsNumChar : NameType = "equalsNumChar" + val equalsNumNum : NameType = "equalsNumNum" + val equalsNumObject : NameType = "equalsNumObject" + val equals_ : NameType = if (forMSIL) "Equals" else "equals" + val error: NameType = "error" + val ex: NameType = "ex" + val false_ : NameType = "false" + val filter: NameType = "filter" + val finalize_ : NameType = if (forMSIL) "Finalize" else "finalize" + val find_ : NameType = "find" + val flatMap: NameType = "flatMap" + val foreach: NameType = "foreach" + val formatted: NameType = "formatted" + val freeValue : NameType = "freeValue" + val genericArrayOps: NameType = "genericArrayOps" + val get: NameType = "get" + val glob : NameType = "glob" + val hasNext: NameType = "hasNext" + val hashCode_ : NameType = if (forMSIL) "GetHashCode" else "hashCode" + val hash_ : NameType = "hash" + val head: NameType = "head" + val identity: NameType = "identity" + val inlinedEquals: NameType = "inlinedEquals" + val isArray: NameType = "isArray" + val isDefinedAt: NameType = "isDefinedAt" + val isEmpty: NameType = "isEmpty" + val isInstanceOf_ : NameType = "isInstanceOf" + val java: NameType = "java" + val lang: NameType = "lang" + val length: NameType = "length" + val lengthCompare: NameType = "lengthCompare" + val lift_ : NameType = "lift" + val macro_ : NameType = "macro" + val main: NameType = "main" + val map: NameType = "map" + val mirror : NameType = "mirror" + val missingCase: NameType = "missingCase" + val ne: NameType = "ne" + val newArray: NameType = "newArray" + val newScopeWith: NameType = "newScopeWith" + val next: NameType = "next" + val notifyAll_ : NameType = "notifyAll" + val notify_ : NameType = "notify" + val null_ : NameType = "null" + val ofDim: NameType = "ofDim" + val productArity: NameType = "productArity" + val productElement: NameType = "productElement" + val productIterator: NameType = "productIterator" + val productPrefix: NameType = "productPrefix" + val readResolve: NameType = "readResolve" + val runOrElse: NameType = "runOrElse" + val runtime: NameType = "runtime" + val sameElements: NameType = "sameElements" + val scala_ : NameType = "scala" + val self: NameType = "self" + val setAccessible: NameType = "setAccessible" + val setAnnotations: NameType = "setAnnotations" + val setTypeSig: NameType = "setTypeSig" + val synchronized_ : NameType = "synchronized" + val tail: NameType = "tail" + val thisModuleType: NameType = "thisModuleType" + val this_ : NameType = "this" + val throw_ : NameType = "throw" + val toArray: NameType = "toArray" + val toList: NameType = "toList" + val toObjectArray : NameType = "toObjectArray" + val toSeq: NameType = "toSeq" + val toString_ : NameType = if (forMSIL) "ToString" else "toString" + val true_ : NameType = "true" + val typedProductIterator: NameType = "typedProductIterator" + val unapply: NameType = "unapply" + val unapplySeq: NameType = "unapplySeq" + val unbox: NameType = "unbox" + val update: NameType = "update" + val value: NameType = "value" + val valueOf : NameType = "valueOf" + val values : NameType = "values" + val view_ : NameType = "view" + val wait_ : NameType = "wait" + val withFilter: NameType = "withFilter" + val zip: NameType = "zip" // unencoded operators object raw { @@ -316,21 +391,53 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy val toLong: NameType = "toLong" val toFloat: NameType = "toFloat" val toDouble: NameType = "toDouble" + + // primitive operation methods for structual types mostly + // overlap with the above, but not for these two. + val toCharacter: NameType = "toCharacter" + val toInteger: NameType = "toInteger" } object tpnme extends TypeNames /*with LibraryTypeNames*/ with TypeNameMangling { type NameType = TypeName - implicit def createNameType(name: String): TypeName = newTypeName(name) + protected implicit def createNameType(name: String): TypeName = newTypeNameCached(name) val REFINE_CLASS_NAME: NameType = "" val ANON_CLASS_NAME: NameType = "$anon" } + + /** For fully qualified type names. + */ + object fulltpnme extends TypeNames { + type NameType = TypeName + protected implicit def createNameType(name: String): TypeName = newTypeNameCached(name) + + val RuntimeNothing: NameType = "scala.runtime.Nothing$" + val RuntimeNull: NameType = "scala.runtime.Null$" + val JavaLangEnum: NameType = "java.lang.Enum" + } + + /** Java binary names, like scala/runtime/Nothing$. + */ + object binarynme { + def toBinary(name: Name) = name mapName (_.replace('.', '/')) + + val RuntimeNothing = toBinary(fulltpnme.RuntimeNothing).toTypeName + val RuntimeNull = toBinary(fulltpnme.RuntimeNull).toTypeName + } + + object fullnme extends TermNames { + type NameType = TermName + protected implicit def createNameType(name: String): TermName = newTermNameCached(name) + + val MirrorPackage: NameType = "scala.reflect.mirror" + } val javanme = nme.javaKeywords object nme extends TermNames /*with LibraryTermNames*/ with TermNameMangling { type NameType = TermName - def createNameType(name: String): TermName = newTermName(name) + protected implicit def createNameType(name: String): TermName = newTermNameCached(name) /** Translate a String into a list of simple TypeNames and TermNames. * In all segments before the last, type/term is determined by whether @@ -363,7 +470,7 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy case -1 => if (name == "") scala.Nil else scala.List(mkName(name, assumeTerm)) // otherwise, we can tell based on whether '#' or '.' is the following char. case idx => - val (simple, div, rest) = (name take idx, name charAt idx, name drop (idx + 1)) + val (simple, div, rest) = (name take idx, name charAt idx, newTermName(name) drop (idx + 1)) mkName(simple, div == '.') :: segments(rest, assumeTerm) } } @@ -380,26 +487,27 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy /** The expanded name of `name` relative to this class `base` with given `separator` */ def expandedName(name: TermName, base: Symbol, separator: String = EXPAND_SEPARATOR_STRING): TermName = - newTermName(base.fullName('$') + separator + name) + newTermNameCached(base.fullName('$') + separator + name) - def moduleVarName(name: TermName): TermName = newTermName("" + name + MODULE_VAR_SUFFIX) - - val EXPAND_SEPARATOR_STRING = "$$" - val LOCAL_SUFFIX_STRING = " " + def moduleVarName(name: TermName): TermName = + newTermNameCached("" + name + MODULE_VAR_SUFFIX) + val ROOTPKG: TermName = "_root_" /** Base strings from which synthetic names are derived. */ - val CHECK_IF_REFUTABLE_STRING = "check$ifrefutable$" - val DEFAULT_GETTER_STRING = "$default$" - val DO_WHILE_PREFIX = "doWhile$" - val EQEQ_LOCAL_VAR = "eqEqTemp$" - val EVIDENCE_PARAM_PREFIX = "evidence$" - val EXCEPTION_RESULT_PREFIX = "exceptionResult" - val INTERPRETER_IMPORT_WRAPPER = "$iw" - val INTERPRETER_LINE_PREFIX = "line" - val INTERPRETER_VAR_PREFIX = "res" - val INTERPRETER_WRAPPER_SUFFIX = "$object" - val WHILE_PREFIX = "while$" + val CHECK_IF_REFUTABLE_STRING = "check$ifrefutable$" + val DEFAULT_GETTER_STRING = "$default$" + val DO_WHILE_PREFIX = "doWhile$" + val EQEQ_LOCAL_VAR_STRING = "eqEqTemp$" + val EVIDENCE_PARAM_PREFIX = "evidence$" + val EXCEPTION_RESULT_PREFIX = "exceptionResult" + val INTERPRETER_IMPORT_WRAPPER = "$iw" + val INTERPRETER_LINE_PREFIX = "line" + val INTERPRETER_VAR_PREFIX = "res" + val INTERPRETER_WRAPPER_SUFFIX = "$object" + val WHILE_PREFIX = "while$" + + val EQEQ_LOCAL_VAR: TermName = newTermName(EQEQ_LOCAL_VAR_STRING) def getCause = sn.GetCause def getClass_ = sn.GetClass @@ -424,8 +532,8 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy val MUL = encode("*") val NE = encode("!=") val OR = encode("|") - val PLUS = encode("+") - val SUB = encode("-") + val PLUS = ADD // technically redundant, but ADD looks funny with MINUS + val SUB = MINUS // ... as does SUB with PLUS val XOR = encode("^") val ZAND = encode("&&") val ZOR = encode("||") @@ -435,10 +543,120 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy val UNARY_+ = encode("unary_+") val UNARY_- = encode("unary_-") val UNARY_! = encode("unary_!") + + // Grouped here so Cleanup knows what tests to perform. + val CommonOpNames = Set[Name](OR, XOR, AND, EQ, NE) + val ConversionNames = Set[Name](toByte, toChar, toDouble, toFloat, toInt, toLong, toShort) + val BooleanOpNames = Set[Name](ZOR, ZAND, UNARY_!) ++ CommonOpNames + val NumberOpNames = ( + Set[Name](ADD, SUB, MUL, DIV, MOD, LSL, LSR, ASR, LT, LE, GE, GT) + ++ Set(UNARY_+, UNARY_-, UNARY_!) + ++ ConversionNames + ++ CommonOpNames + ) + + val add: NameType = "add" + val complement: NameType = "complement" + val divide: NameType = "divide" + val multiply: NameType = "multiply" + val negate: NameType = "negate" + val positive: NameType = "positive" + val shiftLogicalRight: NameType = "shiftLogicalRight" + val shiftSignedLeft: NameType = "shiftSignedLeft" + val shiftSignedRight: NameType = "shiftSignedRight" + val subtract: NameType = "subtract" + val takeAnd: NameType = "takeAnd" + val takeConditionalAnd: NameType = "takeConditionalAnd" + val takeConditionalOr: NameType = "takeConditionalOr" + val takeModulo: NameType = "takeModulo" + val takeNot: NameType = "takeNot" + val takeOr: NameType = "takeOr" + val takeXor: NameType = "takeXor" + val testEqual: NameType = "testEqual" + val testGreaterOrEqualThan: NameType = "testGreaterOrEqualThan" + val testGreaterThan: NameType = "testGreaterThan" + val testLessOrEqualThan: NameType = "testLessOrEqualThan" + val testLessThan: NameType = "testLessThan" + val testNotEqual: NameType = "testNotEqual" + + def toUnaryName(name: TermName): TermName = name match { + case raw.MINUS => UNARY_- + case raw.PLUS => UNARY_+ + case raw.TILDE => UNARY_~ + case raw.BANG => UNARY_! + case _ => name + } + /** The name of a method which stands in for a primitive operation + * during structural type dispatch. + */ + def primitiveInfixMethodName(name: Name): TermName = name match { + case OR => takeOr + case XOR => takeXor + case AND => takeAnd + case EQ => testEqual + case NE => testNotEqual + case ADD => add + case SUB => subtract + case MUL => multiply + case DIV => divide + case MOD => takeModulo + case LSL => shiftSignedLeft + case LSR => shiftLogicalRight + case ASR => shiftSignedRight + case LT => testLessThan + case LE => testLessOrEqualThan + case GE => testGreaterOrEqualThan + case GT => testGreaterThan + case ZOR => takeConditionalOr + case ZAND => takeConditionalAnd + case _ => NO_NAME + } + /** Postfix/prefix, really. + */ + def primitivePostfixMethodName(name: Name): TermName = name match { + case UNARY_! => takeNot + case UNARY_+ => positive + case UNARY_- => negate + case UNARY_~ => complement + case `toByte` => toByte + case `toShort` => toShort + case `toChar` => toCharacter + case `toInt` => toInteger + case `toLong` => toLong + case `toFloat` => toFloat + case `toDouble` => toDouble + case _ => NO_NAME + } + + @switch def productAccessorName(j: Int): TermName = j match { + case 1 => nme._1 + case 2 => nme._2 + case 3 => nme._3 + case 4 => nme._4 + case 5 => nme._5 + case 6 => nme._6 + case 7 => nme._7 + case 8 => nme._8 + case 9 => nme._9 + case 10 => nme._10 + case 11 => nme._11 + case 12 => nme._12 + case 13 => nme._13 + case 14 => nme._14 + case 15 => nme._15 + case 16 => nme._16 + case 17 => nme._17 + case 18 => nme._18 + case 19 => nme._19 + case 20 => nme._20 + case 21 => nme._21 + case 22 => nme._22 + case _ => newTermName("_" + j) + } } abstract class SymbolNames { - protected implicit def stringToTypeName(s: String): TypeName = newTypeName(s) + protected implicit def createNameType(s: String): TypeName = newTypeNameCached(s) val BeanProperty : TypeName val BooleanBeanProperty : TypeName @@ -471,7 +689,7 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy class JavaKeywords { private var kws: Set[TermName] = Set() private def kw(s: String): TermName = { - val result = newTermName(s) + val result = newTermNameCached(s) kws = kws + result result } @@ -555,12 +773,12 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy final val Throwable: TypeName = "java.lang.Throwable" final val ValueType: TypeName = tpnme.NO_NAME - final val ForName: TermName = "forName" - final val GetCause: TermName = "getCause" - final val GetClass: TermName = "getClass" - final val GetMethod: TermName = "getMethod" - final val Invoke: TermName = "invoke" - final val JavaLang: TermName = "java.lang" + final val ForName: TermName = newTermName("forName") + final val GetCause: TermName = newTermName("getCause") + final val GetClass: TermName = newTermName("getClass") + final val GetMethod: TermName = newTermName("getMethod") + final val Invoke: TermName = newTermName("invoke") + final val JavaLang: TermName = newTermName("java.lang") val Boxed = immutable.Map[TypeName, TypeName]( tpnme.Boolean -> BoxedBoolean, @@ -593,12 +811,12 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy final val Throwable: TypeName = "System.Exception" final val ValueType: TypeName = "System.ValueType" - final val ForName: TermName = "GetType" - final val GetCause: TermName = "InnerException" /* System.Reflection.TargetInvocationException.InnerException */ - final val GetClass: TermName = "GetType" - final val GetMethod: TermName = "GetMethod" - final val Invoke: TermName = "Invoke" - final val JavaLang: TermName = "System" + final val ForName: TermName = newTermName("GetType") + final val GetCause: TermName = newTermName("InnerException") /* System.Reflection.TargetInvocationException.InnerException */ + final val GetClass: TermName = newTermName("GetType") + final val GetMethod: TermName = newTermName("GetMethod") + final val Invoke: TermName = newTermName("Invoke") + final val JavaLang: TermName = newTermName("System") val Boxed = immutable.Map[TypeName, TypeName]( tpnme.Boolean -> "System.Boolean", diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index a40f515352..91b63f76e4 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -264,7 +264,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** Create a new getter for current symbol (which must be a field) */ final def newGetter: Symbol = ( - owner.newMethod(focusPos(pos), nme.getterName(name)) + owner.newMethod(focusPos(pos), nme.getterName(name.toTermName)) setFlag getterFlags(flags) setPrivateWithin privateWithin setInfo MethodType(Nil, tpe) @@ -430,7 +430,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def isDefinedInPackage = effectiveOwner.isPackageClass final def isJavaInterface = isJavaDefined && isTrait - final def needsFlatClasses: Boolean = phase.flatClasses && rawowner != NoSymbol && !rawowner.isPackageClass + final def needsFlatClasses = phase.flatClasses && rawowner != NoSymbol && !rawowner.isPackageClass // In java.lang, Predef, or scala package/package object def isInDefaultNamespace = UnqualifiedOwners(effectiveOwner) @@ -699,16 +699,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => rawowner = owner } - private[Symbols] def flattenName(): Name = { - // This assertion caused me no end of trouble in the interpeter in situations - // where everything proceeds smoothly if there's no assert. I don't think calling "name" - // on a symbol is the right place to throw fatal exceptions if things don't look right. - // It really hampers exploration. Finally I gave up and disabled it, and tickets like - // SI-4874 instantly start working. - // assert(rawowner.isClass, "fatal: %s has non-class owner %s after flatten.".format(rawname + idString, rawowner)) - - nme.flattenedName(rawowner.name, rawname) - } def ownerChain: List[Symbol] = this :: owner.ownerChain def originalOwnerChain: List[Symbol] = this :: originalOwner.getOrElse(this, rawowner).originalOwnerChain @@ -793,7 +783,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => * Never adds id. * Drops package objects. */ - final def fullName(separator: Char): String = nme.dropLocalSuffix(fullNameInternal(separator)).toString + final def fullName(separator: Char): String = fullNameAsName(separator).toString /** Doesn't drop package objects, for those situations (e.g. classloading) * where the true path is needed. @@ -801,8 +791,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => private def fullNameInternal(separator: Char): Name = ( if (isRoot || isRootPackage || this == NoSymbol) name else if (owner.isEffectiveRoot) name - else effectiveOwner.enclClass.fullName(separator) append separator append name + else effectiveOwner.enclClass.fullNameAsName(separator) append separator append name ) + + def fullNameAsName(separator: Char): Name = nme.dropLocalSuffix(fullNameInternal(separator)) /** The encoded full path name of this symbol, where outer names and inner names * are separated by periods. @@ -1369,7 +1361,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** The symbol accessed by this accessor function, but with given owner type. */ final def accessed(ownerTp: Type): Symbol = { assert(hasAccessorFlag, this) - ownerTp decl nme.getterToLocal(getterName) + ownerTp decl nme.getterToLocal(getterName.toTermName) } /** The module corresponding to this module class (note that this @@ -1702,17 +1694,17 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ final def getter(base: Symbol): Symbol = base.info.decl(getterName) filter (_.hasAccessorFlag) - def getterName: Name = ( - if (isSetter) nme.setterToGetter(name) - else if (nme.isLocalName(name)) nme.localToGetter(name) - else name + def getterName: TermName = ( + if (isSetter) nme.setterToGetter(name.toTermName) + else if (nme.isLocalName(name)) nme.localToGetter(name.toTermName) + else name.toTermName ) /** The setter of this value or getter definition, or NoSymbol if none exists */ final def setter(base: Symbol): Symbol = setter(base, false) final def setter(base: Symbol, hasExpandedName: Boolean): Symbol = { - var sname = nme.getterToSetter(nme.getterName(name)) + var sname = nme.getterToSetter(nme.getterName(name.toTermName)) if (hasExpandedName) sname = nme.expandedSetterName(sname, base) base.info.decl(sname) filter (_.hasAccessorFlag) } @@ -1767,7 +1759,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => getter(owner).expandName(base) setter(owner).expandName(base) } - name = nme.expandedName(name, base) + name = nme.expandedName(name.toTermName, base) if (isType) name = name } } @@ -2001,7 +1993,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => extends Symbol(initOwner, initPos, initName) { final override def isTerm = true - override def name: TermName = super.name + override def name: TermName = rawname.toTermName privateWithin = NoSymbol var referenced: Symbol = NoSymbol @@ -2088,20 +2080,20 @@ trait Symbols extends api.Symbols { self: SymbolTable => class ModuleSymbol(initOwner: Symbol, initPos: Position, initName: TermName) extends TermSymbol(initOwner, initPos, initName) { private var flatname: TermName = null - // This method could use a better name from someone clearer on what the condition expresses. - private def isFlatAdjusted = !isMethod && needsFlatClasses - override def owner: Symbol = - if (isFlatAdjusted) rawowner.owner + override def owner = ( + if (!isMethod && needsFlatClasses) rawowner.owner else rawowner - - override def name: TermName = - if (isFlatAdjusted) { - if (flatname == null) - flatname = flattenName().toTermName - + ) + override def name: TermName = ( + if (!isMethod && needsFlatClasses) { + if (flatname eq null) + flatname = nme.flattenedName(rawowner.name, rawname) + flatname - } else rawname + } + else rawname.toTermName + ) override def cloneSymbolImpl(owner: Symbol): Symbol = new ModuleSymbol(owner, pos, name).copyAttrsFrom(this) @@ -2300,7 +2292,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** A class for class symbols */ class ClassSymbol(initOwner: Symbol, initPos: Position, initName: TypeName) extends TypeSymbol(initOwner, initPos, initName) { - + private var flatname: TypeName = null private var source: AbstractFileType = null private var thissym: Symbol = this @@ -2319,20 +2311,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => thissym = this } - private var flatname: TypeName = null - - override def owner: Symbol = - if (needsFlatClasses) rawowner.owner - else rawowner - - override def name: TypeName = - if (needsFlatClasses) { - if (flatname == null) - flatname = flattenName().toTypeName - flatname - } - else rawname.asInstanceOf[TypeName] - private var thisTypeCache: Type = _ private var thisTypePeriod = NoPeriod @@ -2348,7 +2326,19 @@ trait Symbols extends api.Symbols { self: SymbolTable => } thisTypeCache } - + + override def owner: Symbol = + if (needsFlatClasses) rawowner.owner else rawowner + override def name: TypeName = ( + if (needsFlatClasses) { + if (flatname eq null) + flatname = nme.flattenedName(rawowner.name, rawname).toTypeName + + flatname + } + else rawname.toTypeName + ) + /** A symbol carrying the self type of the class as its type */ override def thisSym: Symbol = thissym @@ -2419,7 +2409,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def sourceModule_=(module: Symbol) { this.module = module } } - class FreeVar(name: TermName, tpe: Type, val value: Any) extends TermSymbol(definitions.RootClass, NoPosition, name) { + class FreeVar(name0: TermName, tpe: Type, val value: Any) extends TermSymbol(definitions.RootClass, NoPosition, name0) { setInfo(tpe) override def hashCode = value.hashCode diff --git a/src/compiler/scala/reflect/internal/TreeInfo.scala b/src/compiler/scala/reflect/internal/TreeInfo.scala index 14bf36fb47..e3ee39d2a0 100644 --- a/src/compiler/scala/reflect/internal/TreeInfo.scala +++ b/src/compiler/scala/reflect/internal/TreeInfo.scala @@ -192,7 +192,7 @@ abstract class TreeInfo { def isVariableOrGetter(tree: Tree) = { def sym = tree.symbol def isVar = sym.isVariable - def isGetter = mayBeVarGetter(sym) && sym.owner.info.member(nme.getterToSetter(sym.name)) != NoSymbol + def isGetter = mayBeVarGetter(sym) && sym.owner.info.member(nme.getterToSetter(sym.name.toTermName)) != NoSymbol tree match { case Ident(_) => isVar diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala index c6b5297fe4..4ca55f53ea 100644 --- a/src/compiler/scala/reflect/internal/Trees.scala +++ b/src/compiler/scala/reflect/internal/Trees.scala @@ -160,12 +160,12 @@ trait Trees extends api.Trees { self: SymbolTable => */ def ModuleDef(sym: Symbol, impl: Template): ModuleDef = atPos(sym.pos) { - ModuleDef(Modifiers(sym.flags), sym.name, impl) setSymbol sym + ModuleDef(Modifiers(sym.flags), sym.name.toTermName, impl) setSymbol sym } def ValDef(sym: Symbol, rhs: Tree): ValDef = atPos(sym.pos) { - ValDef(Modifiers(sym.flags), sym.name, + ValDef(Modifiers(sym.flags), sym.name.toTermName, TypeTree(sym.tpe) setPos focusPos(sym.pos), rhs) setSymbol sym } @@ -182,7 +182,7 @@ trait Trees extends api.Trees { self: SymbolTable => atPos(sym.pos) { assert(sym != NoSymbol) DefDef(Modifiers(sym.flags), - sym.name, + sym.name.toTermName, sym.typeParams map TypeDef, vparamss, TypeTree(sym.tpe.finalResultType) setPos focusPos(sym.pos), @@ -214,7 +214,7 @@ trait Trees extends api.Trees { self: SymbolTable => def LabelDef(sym: Symbol, params: List[Symbol], rhs: Tree): LabelDef = atPos(sym.pos) { - LabelDef(sym.name, params map Ident, rhs) setSymbol sym + LabelDef(sym.name.toTermName, params map Ident, rhs) setSymbol sym } diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 998eae0cc1..5b4dc4b4c6 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -3205,7 +3205,7 @@ A type's typeSymbol should never be inspected directly. val isType = pnames.head.isTypeName val newParams = for (name <- pnames) yield if (isType) owner.newTypeParameter(NoPosition, name.toTypeName) - else owner.newValueParameter(NoPosition, name) + else owner.newValueParameter(NoPosition, name.toTermName) paramStack = newParams :: paramStack try { (newParams, ptypes).zipped foreach ((p, t) => p setInfo this(t)) diff --git a/src/compiler/scala/reflect/internal/pickling/UnPickler.scala b/src/compiler/scala/reflect/internal/pickling/UnPickler.scala index 9927560c8c..0789f9c774 100644 --- a/src/compiler/scala/reflect/internal/pickling/UnPickler.scala +++ b/src/compiler/scala/reflect/internal/pickling/UnPickler.scala @@ -184,6 +184,8 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { case _ => errorBadSignature("bad name tag: " + tag) } } + protected def readTermName(): TermName = readName().toTermName + protected def readTypeName(): TypeName = readName().toTypeName /** Read a symbol */ protected def readSymbol(): Symbol = { @@ -211,7 +213,7 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { return NoSymbol if (tag == EXTMODCLASSref) { - val moduleVar = owner.info.decl(nme.moduleVarName(name)) + val moduleVar = owner.info.decl(nme.moduleVarName(name.toTermName)) if (moduleVar.isLazyAccessor) return moduleVar.lazyAccessor.lazyAccessor } @@ -223,7 +225,7 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { // (2) Try with expanded name. Can happen if references to private // symbols are read from outside: for instance when checking the children // of a class. See #1722. - fromName(nme.expandedName(name, owner)) orElse { + fromName(nme.expandedName(name.toTermName, owner)) orElse { // (3) Try as a nested object symbol. nestedObjectSymbol orElse { // (4) Otherwise, fail. @@ -296,14 +298,14 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { val clazz = at(inforef, () => readType()).typeSymbol // after the NMT_TRANSITION period, we can leave off the () => ... () if (isModuleRoot) moduleRoot else { - val m = owner.newModule(name, clazz) + val m = owner.newModule(name.toTermName, clazz) clazz.sourceModule = m m } case VALsym => if (isModuleRoot) { assert(false); NoSymbol } - else if (isMethodFlag) owner.newMethod(name) - else owner.newValue(name) + else if (isMethodFlag) owner.newMethod(name.toTermName) + else owner.newValue(name.toTermName) case _ => errorBadSignature("bad symbol tag: " + tag) @@ -549,13 +551,13 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { case MODULEtree => setSymModsName() - ModuleDef(mods, name, readTemplateRef()) + ModuleDef(mods, name.toTermName, readTemplateRef()) case VALDEFtree => setSymModsName() val tpt = readTreeRef() val rhs = readTreeRef() - ValDef(mods, name, tpt, rhs) + ValDef(mods, name.toTermName, tpt, rhs) case DEFDEFtree => setSymModsName() @@ -563,7 +565,7 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { val vparamss = times(readNat(), () => times(readNat(), readValDefRef)) val tpt = readTreeRef() val rhs = readTreeRef() - DefDef(mods, name, tparams, vparamss, tpt, rhs) + DefDef(mods, name.toTermName, tparams, vparamss, tpt, rhs) case TYPEDEFtree => setSymModsName() @@ -575,7 +577,7 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { setSymName() val rhs = readTreeRef() val params = until(end, readIdentRef) - LabelDef(name, params, rhs) + LabelDef(name.toTermName, params, rhs) case IMPORTtree => setSym() diff --git a/src/compiler/scala/reflect/runtime/JavaToScala.scala b/src/compiler/scala/reflect/runtime/JavaToScala.scala index aa0572aceb..9da75bf2b0 100644 --- a/src/compiler/scala/reflect/runtime/JavaToScala.scala +++ b/src/compiler/scala/reflect/runtime/JavaToScala.scala @@ -272,7 +272,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable => */ private def approximateMatch(sym: Symbol, jstr: String): Boolean = (sym.name.toString == jstr) || - sym.isPrivate && nme.expandedName(sym.name, sym.owner).toString == jstr + sym.isPrivate && nme.expandedName(sym.name.toTermName, sym.owner).toString == jstr /** * Find declarations or definition in class `clazz` that maps to a Java @@ -353,32 +353,28 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable => * not available, wrapped from the Java reflection info. */ def classToScala(jclazz: jClass[_]): Symbol = classCache.toScala(jclazz) { - if (jclazz.isMemberClass && !nme.isImplClassName(jclazz.getName)) { - val sym = sOwner(jclazz).info.decl(newTypeName(jclazz.getSimpleName)) + val jname = javaTypeName(jclazz) + def lookup = sOwner(jclazz).info.decl(newTypeName(jclazz.getSimpleName)) + + if (jclazz.isMemberClass && !nme.isImplClassName(jname)) { + val sym = lookup assert(sym.isType, sym+"/"+jclazz+"/"+sOwner(jclazz)+"/"+jclazz.getSimpleName) sym.asInstanceOf[ClassSymbol] - } else if (jclazz.isLocalClass || invalidClassName(jclazz.getName)) { + } + else if (jclazz.isLocalClass || invalidClassName(jname)) { // local classes and implementation classes not preserved by unpickling - treat as Java jclassAsScala(jclazz) - } else if (jclazz.isArray) { + } + else if (jclazz.isArray) { ArrayClass - } else jclazz match { - case java.lang.Void.TYPE => UnitClass - case java.lang.Byte.TYPE => ByteClass - case java.lang.Character.TYPE => CharClass - case java.lang.Short.TYPE => ShortClass - case java.lang.Integer.TYPE => IntClass - case java.lang.Long.TYPE => LongClass - case java.lang.Float.TYPE => FloatClass - case java.lang.Double.TYPE => DoubleClass - case java.lang.Boolean.TYPE => BooleanClass - case _ => - // jclazz is top-level - get signature - sOwner(jclazz).info decl newTypeName(jclazz.getSimpleName) -// val (clazz, module) = createClassModule( -// sOwner(jclazz), newTypeName(jclazz.getSimpleName), new TopClassCompleter(_, _)) -// classCache enter (jclazz, clazz) -// clazz + } + else javaTypeToValueClass(jclazz) orElse { + // jclazz is top-level - get signature + lookup + // val (clazz, module) = createClassModule( + // sOwner(jclazz), newTypeName(jclazz.getSimpleName), new TopClassCompleter(_, _)) + // classCache enter (jclazz, clazz) + // clazz } } diff --git a/src/compiler/scala/reflect/runtime/ScalaToJava.scala b/src/compiler/scala/reflect/runtime/ScalaToJava.scala index b1e4d6224c..405a00de8d 100644 --- a/src/compiler/scala/reflect/runtime/ScalaToJava.scala +++ b/src/compiler/scala/reflect/runtime/ScalaToJava.scala @@ -29,17 +29,7 @@ trait ScalaToJava extends ConversionUtil { self: SymbolTable => def noClass = throw new ClassNotFoundException("no Java class corresponding to "+clazz+" found") //println("classToJava "+clazz+" "+clazz.owner+" "+clazz.owner.isPackageClass)//debug if (clazz.isValueClass) - clazz match { - case UnitClass => java.lang.Void.TYPE - case ByteClass => java.lang.Byte.TYPE - case CharClass => java.lang.Character.TYPE - case ShortClass => java.lang.Short.TYPE - case IntClass => java.lang.Integer.TYPE - case LongClass => java.lang.Long.TYPE - case FloatClass => java.lang.Float.TYPE - case DoubleClass => java.lang.Double.TYPE - case BooleanClass => java.lang.Boolean.TYPE - } + valueClassToJavaType(clazz) else if (clazz == ArrayClass) noClass else if (clazz.owner.isPackageClass) @@ -54,7 +44,7 @@ trait ScalaToJava extends ConversionUtil { self: SymbolTable => } private def expandedName(sym: Symbol): String = - if (sym.isPrivate) nme.expandedName(sym.name, sym.owner).toString + if (sym.isPrivate) nme.expandedName(sym.name.toTermName, sym.owner).toString else sym.name.toString def fieldToJava(fld: Symbol): jField = fieldCache.toJava(fld) { diff --git a/src/compiler/scala/reflect/runtime/ToolBoxes.scala b/src/compiler/scala/reflect/runtime/ToolBoxes.scala index 9f44e2047a..231bcdbc0e 100644 --- a/src/compiler/scala/reflect/runtime/ToolBoxes.scala +++ b/src/compiler/scala/reflect/runtime/ToolBoxes.scala @@ -33,7 +33,7 @@ trait ToolBoxes extends { self: Universe => private def nextWrapperModuleName() = { wrapCount += 1 - "__wrapper$" + wrapCount + newTermName("__wrapper$" + wrapCount) } private def moduleFileName(className: String) = className + "$" @@ -57,8 +57,8 @@ trait ToolBoxes extends { self: Universe => val minfo = ClassInfoType(List(ObjectClass.tpe, ScalaObjectClass.tpe), new Scope, obj.moduleClass) obj.moduleClass setInfo minfo obj setInfo obj.moduleClass.tpe - val meth = obj.moduleClass.newMethod(NoPosition, wrapperMethodName) - def makeParam(fv: Symbol) = meth.newValueParameter(NoPosition, fv.name) setInfo fv.tpe + val meth = obj.moduleClass.newMethod(NoPosition, newTermName(wrapperMethodName)) + def makeParam(fv: Symbol) = meth.newValueParameter(NoPosition, fv.name.toTermName) setInfo fv.tpe meth setInfo MethodType(fvs map makeParam, expr.tpe) minfo.decls enter meth trace("wrapping ")(defOwner(expr) -> meth) diff --git a/src/compiler/scala/reflect/runtime/TreeBuildUtil.scala b/src/compiler/scala/reflect/runtime/TreeBuildUtil.scala index 8c9e6a2565..9d66ca6c6e 100644 --- a/src/compiler/scala/reflect/runtime/TreeBuildUtil.scala +++ b/src/compiler/scala/reflect/runtime/TreeBuildUtil.scala @@ -3,11 +3,9 @@ package runtime trait TreeBuildUtil extends Universe with api.TreeBuildUtil { - def staticClass(fullname: String): Symbol = definitions.getClass(newTypeName(fullname)) - def staticModule(fullname: String): Symbol = definitions.getModule(newTermName(fullname)) - - def thisModuleType(fullname: String) = - definitions.getModule(fullname).moduleClass.thisType + def staticClass(fullname: String): Symbol = definitions.getRequiredClass(fullname) + def staticModule(fullname: String): Symbol = definitions.getRequiredModule(fullname) + def thisModuleType(fullname: String) = staticModule(fullname).moduleClass.thisType /** Selects type symbol with given name from the defined members of prefix type */ @@ -41,7 +39,7 @@ trait TreeBuildUtil extends Universe with api.TreeBuildUtil { selectIn(owner.info, idx) } - def freeVar(name: String, info: Type, value: Any) = new FreeVar(name, info, value) + def freeVar(name: String, info: Type, value: Any) = new FreeVar(newTermName(name), info, value) def modifiersFromInternalFlags(flags: Long, privateWithin: Name, annotations: List[Tree]): Modifiers = Modifiers(flags, privateWithin, annotations) diff --git a/src/compiler/scala/tools/nsc/ast/DocComments.scala b/src/compiler/scala/tools/nsc/ast/DocComments.scala index f9c818daf0..6a6379cca2 100755 --- a/src/compiler/scala/tools/nsc/ast/DocComments.scala +++ b/src/compiler/scala/tools/nsc/ast/DocComments.scala @@ -220,8 +220,8 @@ trait DocComments { self: Global => else site.info.baseClasses searchList collectFirst { case x if defs(x) contains vble => defs(x)(vble) } match { - case Some(str) if str startsWith '$' => lookupVariable(str.tail, site) - case res => res orElse lookupVariable(vble, site.owner) + case Some(str) if str startsWith "$" => lookupVariable(str.tail, site) + case res => res orElse lookupVariable(vble, site.owner) } } @@ -397,7 +397,7 @@ trait DocComments { self: Global => if (tpe != NoType) tpe else { val alias1 = alias.cloneSymbol(definitions.RootClass) - alias1.name = repl.toTypeName + alias1.name = newTypeName(repl) typeRef(NoPrefix, alias1, Nil) } case None => diff --git a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala index 752e3c6699..7b5de1f3dd 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala @@ -360,7 +360,7 @@ abstract class TreeBrowsers { ("Program", EMPTY) case UnitTree(unit) => - ("CompilationUnit", unit.toString) + ("CompilationUnit", newTermName("" + unit)) case DocDef(comment, definition) => ("DocDef", EMPTY) @@ -441,7 +441,7 @@ abstract class TreeBrowsers { ("Apply", EMPTY) case Super(qualif, mix) => - ("Super", "mix: " + mix) + ("Super", newTermName("mix: " + mix)) case This(qualifier) => ("This", qualifier) diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index 0dc3b1fffd..e69c463e71 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -128,7 +128,7 @@ abstract class TreeGen extends reflect.internal.TreeGen { def mkManifestFactoryCall(full: Boolean, constructor: String, tparg: Type, args: List[Tree]): Tree = mkMethodCall( if (full) FullManifestModule else PartialManifestModule, - constructor, + newTermName(constructor), List(tparg), args ) @@ -161,16 +161,10 @@ abstract class TreeGen extends reflect.internal.TreeGen { * apply the element type directly. */ def mkWrapArray(tree: Tree, elemtp: Type) = { - val sym = elemtp.typeSymbol - val meth: Name = - if (isValueClass(sym)) "wrap"+sym.name+"Array" - else if ((elemtp <:< AnyRefClass.tpe) && !isPhantomClass(sym)) "wrapRefArray" - else "genericWrapArray" - mkMethodCall( PredefModule, - meth, - if (isValueClass(sym)) Nil else List(elemtp), + wrapArrayMethodName(elemtp), + if (isScalaValueType(elemtp)) Nil else List(elemtp), List(tree) ) } @@ -179,8 +173,8 @@ abstract class TreeGen extends reflect.internal.TreeGen { * elem type elemtp to expected type pt. */ def mkCastArray(tree: Tree, elemtp: Type, pt: Type) = - if (elemtp.typeSymbol == AnyClass && isValueClass(tree.tpe.typeArgs.head.typeSymbol)) - mkCast(mkRuntimeCall("toObjectArray", List(tree)), pt) + if (elemtp.typeSymbol == AnyClass && isScalaValueType(tree.tpe.typeArgs.head)) + mkCast(mkRuntimeCall(nme.toObjectArray, List(tree)), pt) else mkCast(tree, pt) diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index db97dd3475..5881821ab3 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -314,7 +314,7 @@ self => val stmts = templateStatSeq(false)._2 accept(EOF) - def mainModuleName = settings.script.value + def mainModuleName = newTermName(settings.script.value) /** If there is only a single object template in the file and it has a * suitable main method, we will use it rather than building another object * around it. Since objects are loaded lazily the whole script would have @@ -343,7 +343,7 @@ self => * whole additional parse. So instead, if the actual object's name differs from * what the script is expecting, we transform it to match. */ - if (name.toString == mainModuleName) md + if (name == mainModuleName) md else treeCopy.ModuleDef(md, mods, mainModuleName, template) case _ => /** If we see anything but the above, fail. */ @@ -352,7 +352,7 @@ self => Some(makePackaging(0, emptyPkg, newStmts)) } - if (mainModuleName == ScriptRunner.defaultScriptMain) + if (mainModuleName == newTermName(ScriptRunner.defaultScriptMain)) searchForMain() foreach { return _ } /** Here we are building an AST representing the following source fiction, @@ -384,13 +384,13 @@ self => // def main def mainParamType = AppliedTypeTree(Ident(tpnme.Array), List(Ident(tpnme.String))) - def mainParameter = List(ValDef(Modifiers(Flags.PARAM), "argv", mainParamType, EmptyTree)) - def mainSetArgv = List(ValDef(NoMods, "args", TypeTree(), Ident("argv"))) + def mainParameter = List(ValDef(Modifiers(Flags.PARAM), nme.argv, mainParamType, EmptyTree)) + def mainSetArgv = List(ValDef(NoMods, nme.args, TypeTree(), Ident(nme.argv))) def mainNew = makeNew(Nil, emptyValDef, stmts, List(Nil), NoPosition, NoPosition) def mainDef = DefDef(NoMods, nme.main, Nil, List(mainParameter), scalaDot(tpnme.Unit), Block(mainSetArgv, mainNew)) // object Main - def moduleName = ScriptRunner scriptMain settings + def moduleName = newTermName(ScriptRunner scriptMain settings) def moduleBody = Template(List(scalaScalaObjectConstr), emptyValDef, List(emptyInit, mainDef)) def moduleDef = ModuleDef(NoMods, moduleName, moduleBody) @@ -980,6 +980,7 @@ self => nme.ERROR } def ident(): Name = ident(true) + def rawIdent(): Name = try in.name finally in.nextToken() /** For when it's known already to be a type name. */ def identForType(): TypeName = ident().toTypeName @@ -1117,7 +1118,7 @@ self => case LONGLIT => in.intVal(isNegated) case FLOATLIT => in.floatVal(isNegated).toFloat case DOUBLELIT => in.floatVal(isNegated) - case STRINGLIT => in.strVal + case STRINGLIT => in.strVal.intern() case TRUE => true case FALSE => false case NULL => null @@ -1465,8 +1466,9 @@ self => def prefixExpr(): Tree = { if (isUnaryOp) { atPos(in.offset) { - val name: Name = "unary_" + ident() - if (in.name == raw.MINUS && isNumericLit) simpleExprRest(atPos(in.offset)(literal(true)), true) + val name = nme.toUnaryName(rawIdent()) + // val name = nme.toUnaryName(ident()) // val name: Name = "unary_" + ident() + if (name == nme.UNARY_- && isNumericLit) simpleExprRest(atPos(in.offset)(literal(true)), true) else Select(stripParens(simpleExpr()), name) } } diff --git a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala index b8fa55447a..ffe65aec63 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala @@ -58,11 +58,11 @@ abstract class SymbolicXMLBuilder(p: Parsers#Parser, preserveWS: Boolean) { private object xmltypes extends XMLTypeNames { type NameType = TypeName - implicit def createNameType(name: String): TypeName = newTypeName(name) + implicit def createNameType(name: String): TypeName = newTypeNameCached(name) } private object xmlterms extends XMLTermNames { type NameType = TermName - implicit def createNameType(name: String): TermName = newTermName(name) + implicit def createNameType(name: String): TermName = newTermNameCached(name) } import xmltypes.{_Comment, _Elem, _EntityRef, _Group, _MetaData, _NamespaceBinding, _NodeBuffer, diff --git a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala index d80a1c4f34..27df45b563 100644 --- a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala +++ b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala @@ -39,9 +39,9 @@ trait JavaPlatform extends Platform { ) ++ depAnalysisPhase lazy val externalEquals = getMember(BoxesRunTimeClass, nme.equals_) - lazy val externalEqualsNumNum = getMember(BoxesRunTimeClass, "equalsNumNum") - lazy val externalEqualsNumChar = getMember(BoxesRunTimeClass, "equalsNumChar") - lazy val externalEqualsNumObject = getMember(BoxesRunTimeClass, "equalsNumObject") + lazy val externalEqualsNumNum = getMember(BoxesRunTimeClass, nme.equalsNumNum) + lazy val externalEqualsNumChar = getMember(BoxesRunTimeClass, nme.equalsNumChar) + lazy val externalEqualsNumObject = getMember(BoxesRunTimeClass, nme.equalsNumObject) /** We could get away with excluding BoxedBooleanClass for the * purpose of equality testing since it need not compare equal diff --git a/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala b/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala index 1880bdc52c..ffc6640743 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala @@ -3,13 +3,11 @@ * @author Martin Odersky */ - package scala.tools.nsc package backend package icode -import scala.collection.{ mutable, immutable, generic } -import util.{ Position, NoPosition } +import scala.collection.{ mutable, immutable } /** * Exception handlers are pieces of code that `handle` exceptions on @@ -21,10 +19,10 @@ import util.{ Position, NoPosition } trait ExceptionHandlers { self: ICodes => - import global.{ definitions, Symbol, NoSymbol } + import global._ import definitions.{ ThrowableClass } - class ExceptionHandler(val method: IMethod, val label: String, val cls: Symbol, val pos: Position) { + class ExceptionHandler(val method: IMethod, val label: TermName, val cls: Symbol, val pos: Position) { def loadExceptionClass = if (cls == NoSymbol) ThrowableClass else cls private var _startBlock: BasicBlock = _; var finalizer: Finalizer = _; @@ -69,12 +67,12 @@ trait ExceptionHandlers { def dup: ExceptionHandler = new ExceptionHandler(this) } - class Finalizer(method: IMethod, label: String, pos: Position) extends ExceptionHandler(method, label, NoSymbol, pos) { + class Finalizer(method: IMethod, label: TermName, pos: Position) extends ExceptionHandler(method, label, NoSymbol, pos) { override def toString() = "finalizer_" + label override def dup: Finalizer = new Finalizer(method, label, pos) } - object NoFinalizer extends Finalizer(null, "", NoPosition) { + object NoFinalizer extends Finalizer(null, newTermNameCached(""), NoPosition) { override def startBlock: BasicBlock = sys.error("NoFinalizer cannot have a start block."); override def setStartBlock(b: BasicBlock): Unit = sys.error("NoFinalizer cannot have a start block."); override def dup = this diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 2e34db09eb..803bd05031 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -1293,7 +1293,7 @@ abstract class GenICode extends SubComponent { /** The Object => String overload. */ - private lazy val String_valueOf: Symbol = getMember(StringModule, "valueOf") filter (sym => + private lazy val String_valueOf: Symbol = getMember(StringModule, nme.valueOf) filter (sym => sym.info.paramTypes match { case List(pt) => pt.typeSymbol == ObjectClass case _ => false @@ -1305,7 +1305,7 @@ abstract class GenICode extends SubComponent { // case we want to get more precise. // // private def valueOfForType(tp: Type): Symbol = { - // val xs = getMember(StringModule, "valueOf") filter (sym => + // val xs = getMember(StringModule, nme.valueOf) filter (sym => // // We always exclude the Array[Char] overload because java throws an NPE if // // you pass it a null. It will instead find the Object one, which doesn't. // sym.info.paramTypes match { @@ -1352,7 +1352,7 @@ abstract class GenICode extends SubComponent { def genScalaHash(tree: Tree, ctx: Context): Context = { val hashMethod = { ctx.bb.emit(LOAD_MODULE(ScalaRunTimeModule)) - getMember(ScalaRunTimeModule, "hash") + getMember(ScalaRunTimeModule, nme.hash_) } val ctx1 = genLoad(tree, ctx, ObjectReference) @@ -1959,7 +1959,7 @@ abstract class GenICode extends SubComponent { */ private def newExceptionHandler(cls: Symbol, resultKind: TypeKind, pos: Position): ExceptionHandler = { handlerCount += 1 - val exh = new ExceptionHandler(method, "" + handlerCount, cls, pos) + val exh = new ExceptionHandler(method, newTermNameCached("" + handlerCount), cls, pos) exh.resultKind = resultKind method.addHandler(exh) handlers = exh :: handlers diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala index 4ef6766262..2668e7f29f 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala @@ -169,7 +169,6 @@ trait Members { var exh: List[ExceptionHandler] = Nil var sourceFile: SourceFile = NoSourceFile var returnType: TypeKind = _ - var recursive: Boolean = false /** local variables and method parameters */ diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenAndroid.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenAndroid.scala index 301dbd18d6..e7cf716add 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenAndroid.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenAndroid.scala @@ -23,15 +23,10 @@ trait GenAndroid { * `Parcelable` interface must also have a static field called `CREATOR`, * which is an object implementing the `Parcelable.Creator` interface. */ - private val fieldName = "CREATOR" + private val fieldName = newTermName("CREATOR") - private lazy val AndroidParcelableInterface = - try definitions.getClass("android.os.Parcelable") - catch { case _: FatalError => NoSymbol } - - private lazy val AndroidCreatorClass = - if (AndroidParcelableInterface == NoSymbol) NoSymbol - else definitions.getClass("android.os.Parcelable$Creator") + private lazy val AndroidParcelableInterface = definitions.getClassIfDefined("android.os.Parcelable") + private lazy val AndroidCreatorClass = definitions.getClassIfDefined("android.os.Parcelable$Creator") def isAndroidParcelableClass(sym: Symbol) = (AndroidParcelableInterface != NoSymbol) && diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index e05dd28e00..03d1bc3ad2 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -183,10 +183,10 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with val MethodHandleType = new JObjectType("java.dyn.MethodHandle") // Scala attributes - val BeanInfoAttr = definitions.getClass("scala.beans.BeanInfo") - val BeanInfoSkipAttr = definitions.getClass("scala.beans.BeanInfoSkip") - val BeanDisplayNameAttr = definitions.getClass("scala.beans.BeanDisplayName") - val BeanDescriptionAttr = definitions.getClass("scala.beans.BeanDescription") + val BeanInfoAttr = definitions.getRequiredClass("scala.beans.BeanInfo") + val BeanInfoSkipAttr = definitions.getRequiredClass("scala.beans.BeanInfoSkip") + val BeanDisplayNameAttr = definitions.getRequiredClass("scala.beans.BeanDisplayName") + val BeanDescriptionAttr = definitions.getRequiredClass("scala.beans.BeanDescription") final val ExcludedForwarderFlags = { import Flags._ @@ -296,7 +296,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with */ def scalaSignatureAddingMarker(jclass: JClass, sym: Symbol): Option[AnnotationInfo] = currentRun.symData get sym match { - case Some(pickle) if !nme.isModuleName(jclass.getName()) => + case Some(pickle) if !nme.isModuleName(newTermName(jclass.getName)) => val scalaAttr = fjbgContext.JOtherAttribute(jclass, jclass, tpnme.ScalaSignatureATTR.toString, versionPickle.bytes, versionPickle.writeIndex) @@ -759,7 +759,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with null else { val outerName = javaName(innerSym.rawowner) - if (isTopLevelModule(innerSym.rawowner)) "" + nme.stripModuleSuffix(outerName) + if (isTopLevelModule(innerSym.rawowner)) "" + nme.stripModuleSuffix(newTermName(outerName)) else outerName } } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala index acaf1f6cc2..93d3d19ac8 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala @@ -33,11 +33,11 @@ trait GenJVMUtil { ) // Don't put this in per run caches. - private val javaNameCache = new mutable.WeakHashMap[Symbol, String]() ++= List( - NothingClass -> RuntimeNothingClass.fullName('/'), - RuntimeNothingClass -> RuntimeNothingClass.fullName('/'), - NullClass -> RuntimeNullClass.fullName('/'), - RuntimeNullClass -> RuntimeNullClass.fullName('/') + private val javaNameCache = new mutable.WeakHashMap[Symbol, Name]() ++= List( + NothingClass -> binarynme.RuntimeNothing, + RuntimeNothingClass -> binarynme.RuntimeNothing, + NullClass -> binarynme.RuntimeNull, + RuntimeNullClass -> binarynme.RuntimeNull ) /** This trait may be used by tools who need access to @@ -70,7 +70,6 @@ trait GenJVMUtil { def mkArray(xs: Traversable[JType]): Array[JType] = { val a = new Array[JType](xs.size); xs.copyToArray(a); a } def mkArray(xs: Traversable[String]): Array[String] = { val a = new Array[String](xs.size); xs.copyToArray(a); a } - /** Return the a name of this symbol that can be used on the Java * platform. It removes spaces from names. * @@ -86,11 +85,13 @@ trait GenJVMUtil { */ def javaName(sym: Symbol): String = javaNameCache.getOrElseUpdate(sym, { - if (sym.isClass || (sym.isModule && !sym.isMethod)) - sym.javaBinaryName - else - sym.javaSimpleName - }) + sym.name.newName( + if (sym.isClass || (sym.isModule && !sym.isMethod)) + sym.javaBinaryName + else + sym.javaSimpleName + ) + }).toString def javaType(t: TypeKind): JType = (t: @unchecked) match { case UNIT => JType.VOID diff --git a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala index bf59d80cdd..d2e54ff3f1 100644 --- a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala +++ b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala @@ -124,8 +124,8 @@ abstract class GenMSIL extends SubComponent { // Scala attributes // symtab.Definitions -> object (singleton..) val SerializableAttr = definitions.SerializableAttr.tpe - val CloneableAttr = definitions.getClass("scala.cloneable").tpe - val TransientAtt = definitions.getClass("scala.transient").tpe + val CloneableAttr = definitions.CloneableAttr.tpe + val TransientAtt = definitions.TransientAttr.tpe // remoting: the architectures are too different, no mapping (no portable code // possible) diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index e01c42ad87..e3d21011d1 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -85,9 +85,9 @@ abstract class Inliners extends SubComponent { /* fresh name counter */ val fresh = perRunCaches.newMap[String, Int]() withDefaultValue 0 - def freshName(s: String) = { + def freshName(s: String): TermName = { fresh(s) += 1 - s + fresh(s) + newTermName(s + fresh(s)) } private def hasInline(sym: Symbol) = sym hasAnnotation ScalaInlineClass diff --git a/src/compiler/scala/tools/nsc/dependencies/Changes.scala b/src/compiler/scala/tools/nsc/dependencies/Changes.scala index 4c7263ef69..089ef9cf35 100644 --- a/src/compiler/scala/tools/nsc/dependencies/Changes.scala +++ b/src/compiler/scala/tools/nsc/dependencies/Changes.scala @@ -18,8 +18,8 @@ abstract class Changes { abstract class Change - private lazy val annotationsChecked = - List(definitions.getClass("scala.specialized")) // Any others that should be checked? + private lazy val annotationsChecked = + List(definitions.SpecializedClass) // Any others that should be checked? private val flagsToCheck = IMPLICIT | FINAL | PRIVATE | PROTECTED | SEALED | OVERRIDE | CASE | ABSTRACT | DEFERRED | METHOD | diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index f900859f46..0fea0a2d92 100644 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -818,7 +818,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") def add(sym: Symbol, pre: Type, implicitlyAdded: Boolean)(toMember: (Symbol, Type) => M) { if ((sym.isGetter || sym.isSetter) && sym.accessed != NoSymbol) { add(sym.accessed, pre, implicitlyAdded)(toMember) - } else if (!sym.name.decode.containsName(Dollar) && !sym.isSynthetic && sym.hasRawInfo) { + } else if (!sym.name.decodedName.containsName(Dollar) && !sym.isSynthetic && sym.hasRawInfo) { val symtpe = pre.memberType(sym) onTypeError ErrorType matching(sym, symtpe, this(sym.name)) match { case Some(m) => diff --git a/src/compiler/scala/tools/nsc/interactive/Picklers.scala b/src/compiler/scala/tools/nsc/interactive/Picklers.scala index 2b6e793c5c..b7a9c7329c 100644 --- a/src/compiler/scala/tools/nsc/interactive/Picklers.scala +++ b/src/compiler/scala/tools/nsc/interactive/Picklers.scala @@ -101,7 +101,7 @@ trait Picklers { self: Global => if (sym1.isOverloaded) { val index = sym1.alternatives.indexOf(sym) assert(index >= 0, sym1+" not found in alternatives "+sym1.alternatives) - buf += index.toString + buf += newTermName(index.toString) } } } diff --git a/src/compiler/scala/tools/nsc/interpreter/Dossiers.scala b/src/compiler/scala/tools/nsc/interpreter/Dossiers.scala index 2c556656ca..d889cadf47 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Dossiers.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Dossiers.scala @@ -12,6 +12,7 @@ trait Dossiers { import intp._ import intp.global._ + import definitions._ trait Dossier { def symbol: Symbol @@ -34,7 +35,7 @@ trait Dossiers { class TermDossier(val symbol: TermSymbol, val staticType: Type, val value: AnyRef) extends Dossier { def runtimeClass: JClass = value.getClass - def runtimeSymbol: Symbol = safeClass(runtimeClass.getName) getOrElse NoSymbol + def runtimeSymbol: Symbol = getClassIfDefined(runtimeClass.getName) def runtimeType: Type = runtimeSymbol.tpe def runtimeTypeString = TypeStrings.fromClazz(runtimeClass) diff --git a/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala b/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala index 115cef7f00..9f5fde70d8 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala @@ -15,6 +15,7 @@ trait ExprTyper { import repl._ import replTokens.{ Tokenizer } import global.{ reporter => _, Import => _, _ } + import definitions._ import syntaxAnalyzer.{ UnitParser, UnitScanner, token2name } import naming.freshInternalVarName @@ -70,30 +71,29 @@ trait ExprTyper { // 2) A path loadable via getModule. // 3) Try interpreting it as an expression. private var typeOfExpressionDepth = 0 - def typeOfExpression(expr: String, silent: Boolean = true): Option[Type] = { + def typeOfExpression(expr: String, silent: Boolean = true): Type = { repltrace("typeOfExpression(" + expr + ")") if (typeOfExpressionDepth > 2) { repldbg("Terminating typeOfExpression recursion for expression: " + expr) - return None + return NoType } - def asQualifiedImport = { + def asQualifiedImport: Type = { val name = expr.takeWhile(_ != '.') - importedTermNamed(name) flatMap { sym => - typeOfExpression(sym.fullName + expr.drop(name.length), true) - } + typeOfExpression(importedTermNamed(name).fullName + expr.drop(name.length), true) } - def asModule = safeModule(expr) map (_.tpe) - def asExpr = { + def asModule: Type = getModuleIfDefined(expr).tpe + def asExpr: Type = { val lhs = freshInternalVarName() val line = "lazy val " + lhs + " =\n" + expr interpret(line, true) match { case IR.Success => typeOfExpression(lhs, true) - case _ => None + case _ => NoType } } - def evaluate() = { + + def evaluate(): Type = { typeOfExpressionDepth += 1 try typeOfTerm(expr) orElse asModule orElse asExpr orElse asQualifiedImport finally typeOfExpressionDepth -= 1 @@ -107,26 +107,27 @@ trait ExprTyper { if (!silent) evaluate() - None + NoType } } // Since people will be giving us ":t def foo = 5" even though that is not an // expression, we have a means of typing declarations too. - private def typeOfDeclaration(code: String): Option[Type] = { + private def typeOfDeclaration(code: String): Type = { repltrace("typeOfDeclaration(" + code + ")") val obname = freshInternalVarName() interpret("object " + obname + " {\n" + code + "\n}\n", true) match { case IR.Success => val sym = symbolOfTerm(obname) - if (sym == NoSymbol) None else { + if (sym == NoSymbol) NoType else { // TODO: bitmap$n is not marked synthetic. val decls = sym.tpe.decls.toList filterNot (x => x.isConstructor || x.isPrivate || (x.name.toString contains "$")) repltrace("decls: " + decls) - decls.lastOption map (decl => typeCleanser(sym, decl.name)) + if (decls.isEmpty) NoType + else typeCleanser(sym, decls.last.name) } case _ => - None + NoType } } // def compileAndTypeExpr(expr: String): Option[Typer] = { diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala index 2159ecbb8a..0dc51d5eb0 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala @@ -53,6 +53,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) def isAsync = !settings.Yreplsync.value lazy val power = new Power(intp, new StdReplVals(this)) + lazy val NoType = intp.global.NoType // TODO // object opt extends AestheticSettings @@ -436,9 +437,10 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) // Still todo: modules. private def typeCommand(line: String): Result = { if (line.trim == "") ":type " - else intp.typeOfExpression(line, false) match { - case Some(tp) => intp.afterTyper(tp.toString) - case _ => "" // the error message was already printed + else { + val tp = intp.typeOfExpression(line, false) + if (tp == NoType) "" // the error message was already printed + else intp.afterTyper(tp.toString) } } private def warningsCommand(): Result = { @@ -485,13 +487,14 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) } case wrapper :: Nil => intp.typeOfExpression(wrapper) match { - case Some(PolyType(List(targ), MethodType(List(arg), restpe))) => + case PolyType(List(targ), MethodType(List(arg), restpe)) => intp setExecutionWrapper intp.pathToTerm(wrapper) "Set wrapper to '" + wrapper + "'" - case Some(x) => - failMsg + "\nFound: " + x - case _ => - failMsg + "\nFound: " + case tp => + failMsg + ( + if (tp == g.NoType) "\nFound: " + else "\nFound: " + ) } case _ => failMsg } diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala index 8e4ff8aa37..0f0ab69e6d 100644 --- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala +++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala @@ -188,7 +188,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends import global._ import definitions.{ ScalaPackage, JavaLangPackage, PredefModule, RootClass, - getClassIfDefined, getModuleIfDefined + getClassIfDefined, getModuleIfDefined, getRequiredModule, getRequiredClass } private implicit def privateTreeOps(t: Tree): List[Tree] = { @@ -196,6 +196,12 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends def foreach[U](f: Tree => U): Unit = t foreach { x => f(x) ; () } }).toList } + + implicit def installReplTypeOps(tp: Type): ReplTypeOps = new ReplTypeOps(tp) + class ReplTypeOps(tp: Type) { + def orElse(other: => Type): Type = if (tp ne NoType) tp else other + def andAlso(fn: Type => Type): Type = if (tp eq NoType) tp else fn(tp) + } // TODO: If we try to make naming a lazy val, we run into big time // scalac unhappiness with what look like cycles. It has not been easy to @@ -204,12 +210,13 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends val global: imain.global.type = imain.global } with Naming { // make sure we don't overwrite their unwisely named res3 etc. - override def freshUserVarName(): String = { - val name = super.freshUserVarName() - if (definedNameMap contains name) freshUserVarName() + def freshUserTermName(): TermName = { + val name = newTermName(freshUserVarName()) + if (definedNameMap contains name) freshUserTermName() else name } - def isInternalVarName(name: Name): Boolean = isInternalVarName("" + name) + def isUserTermName(name: Name) = isUserVarName("" + name) + def isInternalTermName(name: Name) = isInternalVarName("" + name) } import naming._ @@ -359,7 +366,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends private def mostRecentlyHandledTree: Option[Tree] = { prevRequests.reverse foreach { req => req.handlers.reverse foreach { - case x: MemberDefHandler if x.definesValue && !isInternalVarName(x.name) => return Some(x.member) + case x: MemberDefHandler if x.definesValue && !isInternalTermName(x.name) => return Some(x.member) case _ => () } } @@ -501,7 +508,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends trees.last match { case _:Assign => // we don't want to include assignments case _:TermTree | _:Ident | _:Select => // ... but do want other unnamed terms. - val varName = if (synthetic) freshInternalVarName() else freshUserVarName() + val varName = if (synthetic) freshInternalVarName() else ("" + freshUserTermName()) val rewrittenLine = ( // In theory this would come out the same without the 1-specific test, but // it's a cushion against any more sneaky parse-tree position vs. code mismatches: @@ -643,7 +650,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends def directBind(name: String, boundType: String, value: Any): IR.Result = { val result = bind(name, boundType, value) if (result == IR.Success) - directlyBoundNames += name + directlyBoundNames += newTermName(name) result } def directBind(p: NamedParam): IR.Result = directBind(p.name, p.tpe, p.value) @@ -651,7 +658,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends def rebind(p: NamedParam): IR.Result = { val name = p.name - val oldType = typeOfTerm(name) getOrElse { return IR.Error } + val oldType = typeOfTerm(name) orElse { return IR.Error } val newType = p.tpe val tempName = freshInternalVarName() @@ -666,7 +673,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends def quietBind(p: NamedParam): IR.Result = beQuietDuring(bind(p)) def bind(p: NamedParam): IR.Result = bind(p.name, p.tpe, p.value) def bind[T: Manifest](name: String, value: T): IR.Result = bind((name, value)) - def bindValue(x: Any): IR.Result = bindValue(freshUserVarName(), x) + def bindValue(x: Any): IR.Result = bindValue("" + freshUserTermName(), x) def bindValue(name: String, x: Any): IR.Result = bind(name, TypeStrings.fromValue(x), x) /** Reset this interpreter, forgetting all user-specified requests. */ @@ -789,7 +796,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends * following accessPath into the outer one. */ def resolvePathToSymbol(accessPath: String): Symbol = { - val readRoot = definitions.getModule(readPath) // the outermost wrapper + val readRoot = getRequiredModule(readPath) // the outermost wrapper (accessPath split '.').foldLeft(readRoot) { (sym, name) => if (name == "") sym else lineAfterTyper(sym.info member newTermName(name)) @@ -1039,16 +1046,6 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends def requestHistoryForName(name: Name): List[Request] = prevRequests.toList.reverse filter (_.definedNames contains name) - def safeClass(name: String): Option[Symbol] = { - try Some(definitions.getClass(newTypeName(name))) - catch { case _: MissingRequirementError => None } - } - - def safeModule(name: String): Option[Symbol] = { - try Some(definitions.getModule(newTermName(name))) - catch { case _: MissingRequirementError => None } - } - def definitionForName(name: Name): Option[MemberHandler] = requestForName(name) flatMap { req => req.handlers find (_.definedNames contains name) @@ -1060,34 +1057,32 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends def classOfTerm(id: String): Option[JClass] = valueOfTerm(id) map (_.getClass) - def typeOfTerm(id: String): Option[Type] = newTermName(id) match { - case nme.ROOTPKG => Some(definitions.RootClass.tpe) - case name => requestForName(name) flatMap (_.compilerTypeOf get name) + def typeOfTerm(id: String): Type = newTermName(id) match { + case nme.ROOTPKG => definitions.RootClass.tpe + case name => requestForName(name) flatMap (_.compilerTypeOf get name) getOrElse NoType } def symbolOfTerm(id: String): Symbol = requestForIdent(id) flatMap (_.definedSymbols get newTermName(id)) getOrElse NoSymbol def runtimeClassAndTypeOfTerm(id: String): Option[(JClass, Type)] = { - for { - clazz <- classOfTerm(id) - tpe <- runtimeTypeOfTerm(id) - nonAnon <- clazz.supers find (!_.isScalaAnonymous) - } yield { - (nonAnon, tpe) + classOfTerm(id) flatMap { clazz => + clazz.supers find (!_.isScalaAnonymous) map { nonAnon => + (nonAnon, runtimeTypeOfTerm(id)) + } } } - def runtimeTypeOfTerm(id: String): Option[Type] = { - for { - tpe <- typeOfTerm(id) - clazz <- classOfTerm(id) - staticSym = tpe.typeSymbol - runtimeSym <- safeClass(clazz.getName) - if runtimeSym != staticSym - if runtimeSym isSubClass staticSym + def runtimeTypeOfTerm(id: String): Type = { + typeOfTerm(id) andAlso { tpe => + val clazz = classOfTerm(id) getOrElse { return NoType } + val staticSym = tpe.typeSymbol + val runtimeSym = getClassIfDefined(clazz.getName) + + if ((runtimeSym != NoSymbol) && (runtimeSym != staticSym) && (runtimeSym isSubClass staticSym)) + runtimeSym.info + else NoType } - yield runtimeSym.info } object replTokens extends { @@ -1099,16 +1094,16 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends } with ExprTyper { } def parse(line: String): Option[List[Tree]] = exprTyper.parse(line) - def typeOfExpression(expr: String, silent: Boolean = true): Option[Type] = { + def typeOfExpression(expr: String, silent: Boolean = true): Type = exprTyper.typeOfExpression(expr, silent) - } + def prettyPrint(code: String) = replTokens.prettyPrint(exprTyper tokens code) protected def onlyTerms(xs: List[Name]) = xs collect { case x: TermName => x } protected def onlyTypes(xs: List[Name]) = xs collect { case x: TypeName => x } - def definedTerms = onlyTerms(allDefinedNames) filterNot isInternalVarName + def definedTerms = onlyTerms(allDefinedNames) filterNot isInternalTermName def definedTypes = onlyTypes(allDefinedNames) def definedSymbols = prevRequests.toSet flatMap ((x: Request) => x.definedSymbols.values) diff --git a/src/compiler/scala/tools/nsc/interpreter/Imports.scala b/src/compiler/scala/tools/nsc/interpreter/Imports.scala index 10e3796404..d34ca8bbca 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Imports.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Imports.scala @@ -34,8 +34,9 @@ trait Imports { def languageWildcards: List[Type] = languageWildcardSyms map (_.tpe) def languageWildcardHandlers = languageWildcardSyms map makeWildcardImportHandler - def importedTerms = onlyTerms(importHandlers flatMap (_.importedNames)) - def importedTypes = onlyTypes(importHandlers flatMap (_.importedNames)) + def allImportedNames = importHandlers flatMap (_.importedNames) + def importedTerms = onlyTerms(allImportedNames) + def importedTypes = onlyTypes(allImportedNames) /** Types which have been wildcard imported, such as: * val x = "abc" ; import x._ // type java.lang.String @@ -49,10 +50,7 @@ trait Imports { * into the compiler scopes. */ def sessionWildcards: List[Type] = { - importHandlers flatMap { - case x if x.importsWildcard => x.targetType - case _ => None - } distinct + importHandlers filter (_.importsWildcard) map (_.targetType) distinct } def wildcardTypes = languageWildcards ++ sessionWildcards @@ -63,14 +61,15 @@ trait Imports { def importedTypeSymbols = importedSymbols collect { case x: TypeSymbol => x } def implicitSymbols = importedSymbols filter (_.isImplicit) - def importedTermNamed(name: String) = importedTermSymbols find (_.name.toString == name) + def importedTermNamed(name: String): Symbol = + importedTermSymbols find (_.name.toString == name) getOrElse NoSymbol /** Tuples of (source, imported symbols) in the order they were imported. */ def importedSymbolsBySource: List[(Symbol, List[Symbol])] = { val lang = languageWildcardSyms map (sym => (sym, membersAtPickler(sym))) - val session = importHandlers filter (_.targetType.isDefined) map { mh => - (mh.targetType.get.typeSymbol, mh.importedSymbols) + val session = importHandlers filter (_.targetType != NoType) map { mh => + (mh.targetType.typeSymbol, mh.importedSymbols) } lang ++ session diff --git a/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala b/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala index 9c5299b633..d96e8b07fc 100644 --- a/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala +++ b/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala @@ -16,7 +16,7 @@ import collection.mutable.ListBuffer class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput { val global: intp.global.type = intp.global import global._ - import definitions.{ PredefModule, RootClass, AnyClass, AnyRefClass, ScalaPackage, JavaLangPackage } + import definitions.{ PredefModule, RootClass, AnyClass, AnyRefClass, ScalaPackage, JavaLangPackage, getModuleIfDefined } type ExecResult = Any import intp.{ debugging, afterTyper } @@ -24,14 +24,13 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput private var verbosity: Int = 0 def resetVerbosity() = verbosity = 0 - def getType(name: String, isModule: Boolean) = { - val f = if (isModule) definitions.getModule(_: Name) else definitions.getClass(_: Name) - try Some(f(name).tpe) - catch { case _: MissingRequirementError => None } - } - - def typeOf(name: String) = getType(name, false) - def moduleOf(name: String) = getType(name, true) + def getSymbol(name: String, isModule: Boolean) = ( + if (isModule) getModuleIfDefined(name) + else getModuleIfDefined(name) + ) + def getType(name: String, isModule: Boolean) = getSymbol(name, isModule).tpe + def typeOf(name: String) = getType(name, false) + def moduleOf(name: String) = getType(name, true) trait CompilerCompletion { def tp: Type @@ -46,9 +45,9 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput private def anyMembers = AnyClass.tpe.nonPrivateMembers def anyRefMethodsToShow = Set("isInstanceOf", "asInstanceOf", "toString") - def tos(sym: Symbol) = sym.name.decode.toString - def memberNamed(s: String) = members find (x => tos(x) == s) - def hasMethod(s: String) = methods exists (x => tos(x) == s) + def tos(sym: Symbol): String = sym.decodedName + def memberNamed(s: String) = afterTyper(effectiveTp member newTermName(s)) + def hasMethod(s: String) = memberNamed(s).isMethod // XXX we'd like to say "filterNot (_.isDeprecated)" but this causes the // compiler to crash for reasons not yet known. @@ -62,6 +61,13 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput def packageNames = packages map tos def aliasNames = aliases map tos } + + object NoTypeCompletion extends TypeMemberCompletion(NoType) { + override def memberNamed(s: String) = NoSymbol + override def members = Nil + override def follow(s: String) = None + override def alternativesFor(id: String) = Nil + } object TypeMemberCompletion { def apply(tp: Type, runtimeType: Type, param: NamedParam): TypeMemberCompletion = { @@ -90,7 +96,8 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput } } def apply(tp: Type): TypeMemberCompletion = { - if (tp.typeSymbol.isPackageClass) new PackageCompletion(tp) + if (tp eq NoType) NoTypeCompletion + else if (tp.typeSymbol.isPackageClass) new PackageCompletion(tp) else new TypeMemberCompletion(tp) } def imported(tp: Type) = new ImportCompletion(tp) @@ -118,7 +125,7 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput debugging(tp + " completions ==> ")(filtered(memberNames)) override def follow(s: String): Option[CompletionAware] = - debugging(tp + " -> '" + s + "' ==> ")(memberNamed(s) map (x => TypeMemberCompletion(x.tpe))) + debugging(tp + " -> '" + s + "' ==> ")(Some(TypeMemberCompletion(memberNamed(s).tpe)) filterNot (_ eq NoTypeCompletion)) override def alternativesFor(id: String): List[String] = debugging(id + " alternatives ==> ") { @@ -155,28 +162,29 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput object ids extends CompletionAware { override def completions(verbosity: Int) = intp.unqualifiedIds ++ List("classOf") //, "_root_") // now we use the compiler for everything. - override def follow(id: String) = { - if (completions(0) contains id) { - intp typeOfExpression id map { tpe => - def default = TypeMemberCompletion(tpe) - - // only rebinding vals in power mode for now. - if (!isReplPower) default - else intp runtimeClassAndTypeOfTerm id match { - case Some((clazz, runtimeType)) => - val sym = intp.symbolOfTerm(id) - if (sym.isStable) { - val param = new NamedParam.Untyped(id, intp valueOfTerm id getOrElse null) - TypeMemberCompletion(tpe, runtimeType, param) - } - else default - case _ => - default + override def follow(id: String): Option[CompletionAware] = { + if (!completions(0).contains(id)) + return None + + val tpe = intp typeOfExpression id + if (tpe == NoType) + return None + + def default = Some(TypeMemberCompletion(tpe)) + + // only rebinding vals in power mode for now. + if (!isReplPower) default + else intp runtimeClassAndTypeOfTerm id match { + case Some((clazz, runtimeType)) => + val sym = intp.symbolOfTerm(id) + if (sym.isStable) { + val param = new NamedParam.Untyped(id, intp valueOfTerm id getOrElse null) + Some(TypeMemberCompletion(tpe, runtimeType, param)) } - } + else default + case _ => + default } - else - None } override def toString = " (%s)".format(completions(0).size) } diff --git a/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala b/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala index b64f14e929..c742ab89c0 100644 --- a/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala +++ b/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala @@ -169,7 +169,7 @@ trait MemberHandlers { class ImportHandler(imp: Import) extends MemberHandler(imp) { val Import(expr, selectors) = imp - def targetType = intp.typeOfExpression("" + expr) + def targetType: Type = intp.typeOfExpression("" + expr) override def isLegalTopLevel = true def createImportForName(name: Name): String = { @@ -199,10 +199,10 @@ trait MemberHandlers { def importedSymbols = individualSymbols ++ wildcardSymbols lazy val individualSymbols: List[Symbol] = - atPickler(targetType.toList flatMap (tp => individualNames map (tp nonPrivateMember _))) + atPickler(individualNames map (targetType nonPrivateMember _)) lazy val wildcardSymbols: List[Symbol] = - if (importsWildcard) atPickler(targetType.toList flatMap (_.nonPrivateMembers)) + if (importsWildcard) atPickler(targetType.nonPrivateMembers) else Nil /** Complete list of names imported by a wildcard */ diff --git a/src/compiler/scala/tools/nsc/interpreter/Naming.scala b/src/compiler/scala/tools/nsc/interpreter/Naming.scala index 7377953263..8e215cf63b 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Naming.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Naming.scala @@ -84,7 +84,7 @@ trait Naming { var x = 0 () => { x += 1 ; x } } - def freshUserVarName() = userVar() + def freshUserVarName() = userVar() def freshInternalVarName() = internalVar() def resetAllCreators() { diff --git a/src/compiler/scala/tools/nsc/interpreter/Power.scala b/src/compiler/scala/tools/nsc/interpreter/Power.scala index 82a466a7e5..b4a9b9b0e3 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Power.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Power.scala @@ -353,7 +353,7 @@ class Power[ReplValsImpl <: ReplVals : Manifest](val intp: IMain, replVals: Repl def source(code: String) = new BatchSourceFile("", code) def unit(code: String) = new CompilationUnit(source(code)) def trees(code: String) = parse(code) getOrElse Nil - def typeOf(id: String): Type = intp.typeOfExpression(id) getOrElse NoType + def typeOf(id: String) = intp.typeOfExpression(id) override def toString = """ |** Power mode status ** diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 742e9e03ca..0d7afdc4ec 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -547,7 +547,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { if (parentToken == AT && in.token == DEFAULT) { val annot = atPos(pos) { - New(Select(scalaDot(newTermName("runtime")), tpnme.AnnotationDefaultATTR), List(List())) + New(Select(scalaDot(nme.runtime), tpnme.AnnotationDefaultATTR), List(List())) } mods1 = mods1 withAnnotations List(annot) skipTo(SEMI) @@ -794,9 +794,9 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { accept(INTERFACE) val pos = in.currentPos val name = identForType() - val parents = List(scalaDot(newTypeName("Annotation")), - Select(javaLangDot(newTermName("annotation")), newTypeName("Annotation")), - scalaDot(newTypeName("ClassfileAnnotation"))) + val parents = List(scalaDot(tpnme.Annotation), + Select(javaLangDot(nme.annotation), tpnme.Annotation), + scalaDot(tpnme.ClassfileAnnotation)) val (statics, body) = typeBody(AT, name) def getValueMethodType(tree: Tree) = tree match { case DefDef(_, nme.value, _, _, tpt, _) => Some(tpt.duplicate) @@ -838,18 +838,18 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { } val predefs = List( DefDef( - Modifiers(Flags.JAVA | Flags.STATIC), newTermName("values"), List(), + Modifiers(Flags.JAVA | Flags.STATIC), nme.values, List(), List(List()), arrayOf(enumType), blankExpr), DefDef( - Modifiers(Flags.JAVA | Flags.STATIC), newTermName("valueOf"), List(), + Modifiers(Flags.JAVA | Flags.STATIC), nme.valueOf, List(), List(List(makeParam("x", TypeTree(StringClass.tpe)))), enumType, blankExpr)) accept(RBRACE) val superclazz = - AppliedTypeTree(javaLangDot(newTypeName("Enum")), List(enumType)) + AppliedTypeTree(javaLangDot(tpnme.Enum), List(enumType)) addCompanionObject(consts ::: statics ::: predefs, atPos(pos) { ClassDef(mods, name, List(), makeTemplate(superclazz :: interfaces, body)) diff --git a/src/compiler/scala/tools/nsc/matching/Patterns.scala b/src/compiler/scala/tools/nsc/matching/Patterns.scala index 420fba911b..e5748b7c23 100644 --- a/src/compiler/scala/tools/nsc/matching/Patterns.scala +++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala @@ -36,6 +36,9 @@ trait Patterns extends ast.TreeDSL { // case _ => NoSymbol // } + private lazy val dummyMethod = + new TermSymbol(NoSymbol, NoPosition, newTermName("matching$dummy")) + // Fresh patterns def emptyPatterns(i: Int): List[Pattern] = List.fill(i)(NoPattern) def emptyTrees(i: Int): List[Tree] = List.fill(i)(EmptyTree) @@ -191,9 +194,9 @@ trait Patterns extends ast.TreeDSL { // As yet I can't testify this is doing any good relative to using // tpt.tpe, but it doesn't seem to hurt either. private lazy val packedType = global.typer.computeType(tpt, tpt.tpe) - private lazy val consRef = typeRef(NoPrefix, ConsClass, List(packedType)) - private lazy val listRef = typeRef(NoPrefix, ListClass, List(packedType)) - private lazy val seqRef = typeRef(NoPrefix, SeqClass, List(packedType)) + private lazy val consRef = appliedType(ConsClass.typeConstructor, List(packedType)) + private lazy val listRef = appliedType(ListClass.typeConstructor, List(packedType)) + private lazy val seqRef = appliedType(SeqClass.typeConstructor, List(packedType)) private def thisSeqRef = { val tc = (tree.tpe baseType SeqClass).typeConstructor @@ -205,7 +208,6 @@ trait Patterns extends ast.TreeDSL { private def listFolder(hd: Tree, tl: Tree): Tree = unbind(hd) match { case t @ Star(_) => moveBindings(hd, WILD(t.tpe)) case _ => - val dummyMethod = new TermSymbol(NoSymbol, NoPosition, "matching$dummy") val consType = MethodType(dummyMethod newSyntheticValueParams List(packedType, listRef), consRef) Apply(TypeTree(consType), List(hd, tl)) setType consRef diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 94eb6d2afd..ac72b4d22c 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -440,18 +440,18 @@ abstract class ClassfileParser { /** Return the class symbol of the given name. */ def classNameToSymbol(name: Name): Symbol = { def loadClassSymbol(name: Name) = { - val s = name.toString - val file = global.classPath findSourceFile s getOrElse { - MissingRequirementError.notFound("class " + s) + val file = global.classPath findSourceFile ("" +name) getOrElse { + MissingRequirementError.notFound("class " + name) } - val completer = new global.loaders.ClassfileLoader(file) + val completer = new global.loaders.ClassfileLoader(file) var owner: Symbol = definitions.RootClass - var sym: Symbol = NoSymbol - var ss: String = null - var start = 0 - var end = s indexOf '.' + var sym: Symbol = NoSymbol + var ss: Name = null + var start = 0 + var end = name indexOf '.' + while (end > 0) { - ss = s.substring(start, end) + ss = name.subName(start, end) sym = owner.info.decls lookup ss if (sym == NoSymbol) { sym = owner.newPackage(NoPosition, ss) setInfo completer @@ -460,17 +460,16 @@ abstract class ClassfileParser { } owner = sym.moduleClass start = end + 1 - end = s.indexOf('.', start) + end = name.indexOf('.', start) } - ss = s substring start - sym = owner.info.decls lookup ss - if (sym == NoSymbol) { - sym = owner.newClass(NoPosition, newTypeName(ss)) setInfo completer - owner.info.decls enter sym - if (settings.debug.value && settings.verbose.value) + ss = name.subName(0, start) + owner.info.decls lookup ss orElse { + sym = owner.newClass(NoPosition, ss.toTypeName) setInfo completer + if (opt.verboseDebug) println("loaded "+sym+" from file "+file) + + owner.info.decls enter sym } - sym } def lookupClass(name: Name) = try { diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala index abc1dd387c..0b64a49a2c 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala @@ -26,9 +26,6 @@ abstract class ICodeReader extends ClassfileParser { var instanceCode: IClass = null // the ICode class for the current symbol var staticCode: IClass = null // the ICode class static members var method: IMethod = NoIMethod // the current IMethod - - val nothingName = newTermName(SCALA_NOTHING) - val nullName = newTermName(SCALA_NULL) var isScalaModule = false /** Read back bytecode for the given class symbol. It returns @@ -182,9 +179,9 @@ abstract class ICodeReader extends ClassfileParser { } override def classNameToSymbol(name: Name) = { - val sym = if (name == nothingName) + val sym = if (name == fulltpnme.RuntimeNothing) definitions.NothingClass - else if (name == nullName) + else if (name == fulltpnme.RuntimeNull) definitions.NullClass else if (nme.isImplClassName(name)) { val iface = definitions.getClass(nme.interfaceName(name)) @@ -194,7 +191,7 @@ abstract class ICodeReader extends ClassfileParser { } else if (nme.isModuleName(name)) { val strippedName = nme.stripModuleSuffix(name) - val sym = forceMangledName(strippedName.decode, true) + val sym = forceMangledName(newTermName(strippedName.decode), true) if (sym == NoSymbol) definitions.getModule(strippedName) else sym @@ -991,7 +988,7 @@ abstract class ICodeReader extends ClassfileParser { /** Return a fresh Local variable for the given index. */ private def freshLocal(idx: Int, kind: TypeKind, isArg: Boolean) = { - val sym = method.symbol.newVariable(NoPosition, "loc" + idx).setInfo(kind.toType); + val sym = method.symbol.newVariable(NoPosition, newTermName("loc" + idx)).setInfo(kind.toType); val l = new Local(sym, kind, isArg) method.addLocal(l) l @@ -1008,7 +1005,7 @@ abstract class ICodeReader extends ClassfileParser { /** add a method param with the given index. */ def enterParam(idx: Int, kind: TypeKind) = { - val sym = method.symbol.newVariable(NoPosition, "par" + idx).setInfo(kind.toType) + val sym = method.symbol.newVariable(NoPosition, newTermName("par" + idx)).setInfo(kind.toType) val l = new Local(sym, kind, true) assert(!locals.isDefinedAt(idx)) locals += (idx -> List((l, kind))) diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala index 728593abe7..676c8f09da 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala @@ -49,7 +49,7 @@ abstract class MetaParser{ val sym = locals.lookup(newTypeName(str)) if (sym != NoSymbol) sym.tpe else { - val tp = definitions.getClass(str).tpe; + val tp = definitions.getRequiredClass(str).tpe; if (token != "[") tp else { val args = new ListBuffer[Type]; diff --git a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala index 95ef799720..e0cb0848be 100644 --- a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala @@ -34,6 +34,8 @@ abstract class TypeParser { protected var busy: Boolean = false // lock to detect recursive reads + private implicit def stringToTermName(s: String): TermName = newTermName(s) + private object unpickler extends UnPickler { val global: TypeParser.this.global.type = TypeParser.this.global } @@ -153,8 +155,8 @@ abstract class TypeParser { val canBeTakenAddressOf = (typ.IsValueType || typ.IsEnum) && (typ.FullName != "System.Enum") if(canBeTakenAddressOf) { - clazzBoxed = clazz.owner.newClass(clazz.name.toTypeName append "Boxed") - clazzMgdPtr = clazz.owner.newClass(clazz.name.toTypeName append "MgdPtr") + clazzBoxed = clazz.owner.newClass(clazz.name.toTypeName append newTypeName("Boxed")) + clazzMgdPtr = clazz.owner.newClass(clazz.name.toTypeName append newTypeName("MgdPtr")) clrTypes.mdgptrcls4clssym(clazz) = clazzMgdPtr /* adding typMgdPtr to clrTypes.sym2type should happen early (before metadata for supertypes is parsed, before metadata for members are parsed) so that clazzMgdPtr can be found by getClRType. */ diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index f04867b889..575e3a9141 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -274,69 +274,25 @@ abstract class CleanUp extends Transform with ast.TreeDSL { /* ### HANDLING METHODS NORMALLY COMPILED TO OPERATORS ### */ - val testForNumber: Tree => Tree = { - // Can't shortcut on BoxedNumber because BoxesRunTime - // is unforgiving of other Numbers showing up. - qual1 => ( - (qual1 IS_OBJ BoxedIntClass.tpe) - OR (qual1 IS_OBJ BoxedLongClass.tpe) - OR (qual1 IS_OBJ BoxedDoubleClass.tpe) - OR (qual1 IS_OBJ BoxedFloatClass.tpe) - OR (qual1 IS_OBJ BoxedByteClass.tpe) - OR (qual1 IS_OBJ BoxedShortClass.tpe) - OR (qual1 IS_OBJ BoxedCharacterClass.tpe) - ) - } - val testForBoolean: Tree => Tree = { - qual1 => (qual1 IS_OBJ BoxedBooleanClass.tpe) - } - val testForNumberOrBoolean: Tree => Tree = { - qual1 => testForNumber(qual1) OR testForBoolean(qual1) - } - - def postfixTest(name: Name): Option[(String, Tree => Tree)] = { - var runtimeTest: Tree => Tree = testForNumber - val newName = name match { - case nme.UNARY_! => runtimeTest = testForBoolean ; "takeNot" - case nme.UNARY_+ => "positive" - case nme.UNARY_- => "negate" - case nme.UNARY_~ => "complement" - case nme.toByte => "toByte" - case nme.toShort => "toShort" - case nme.toChar => "toCharacter" - case nme.toInt => "toInteger" - case nme.toLong => "toLong" - case nme.toFloat => "toFloat" - case nme.toDouble => "toDouble" - case _ => return None - } - Some((newName, runtimeTest)) - } - def infixTest(name: Name): Option[(String, Tree => Tree)] = { - val (newName, runtimeTest) = name match { - case nme.OR => ("takeOr", testForNumberOrBoolean) - case nme.XOR => ("takeXor", testForNumberOrBoolean) - case nme.AND => ("takeAnd", testForNumberOrBoolean) - case nme.EQ => ("testEqual", testForNumberOrBoolean) - case nme.NE => ("testNotEqual", testForNumberOrBoolean) - case nme.ADD => ("add", testForNumber) - case nme.SUB => ("subtract", testForNumber) - case nme.MUL => ("multiply", testForNumber) - case nme.DIV => ("divide", testForNumber) - case nme.MOD => ("takeModulo", testForNumber) - case nme.LSL => ("shiftSignedLeft", testForNumber) - case nme.LSR => ("shiftLogicalRight", testForNumber) - case nme.ASR => ("shiftSignedRight", testForNumber) - case nme.LT => ("testLessThan", testForNumber) - case nme.LE => ("testLessOrEqualThan", testForNumber) - case nme.GE => ("testGreaterOrEqualThan", testForNumber) - case nme.GT => ("testGreaterThan", testForNumber) - case nme.ZOR => ("takeConditionalOr", testForBoolean) - case nme.ZAND => ("takeConditionalAnd", testForBoolean) - case _ => return None - } - Some((newName, runtimeTest)) - } + // Can't shortcut on BoxedNumber because BoxesRunTime + // is unforgiving of other Numbers showing up. + def testForNumber(qual1: Tree): Tree = ( + (qual1 IS_OBJ BoxedIntClass.tpe) + OR (qual1 IS_OBJ BoxedLongClass.tpe) + OR (qual1 IS_OBJ BoxedDoubleClass.tpe) + OR (qual1 IS_OBJ BoxedFloatClass.tpe) + OR (qual1 IS_OBJ BoxedByteClass.tpe) + OR (qual1 IS_OBJ BoxedShortClass.tpe) + OR (qual1 IS_OBJ BoxedCharacterClass.tpe) + ) + def testForBoolean(qual1: Tree): Tree = ( + (qual1 IS_OBJ BoxedBooleanClass.tpe) + ) + def testForName(name: Name): Tree => Tree = ( + if (nme.CommonOpNames(name)) t => testForNumber(t) OR testForBoolean(t) + else if (nme.BooleanOpNames(name)) testForBoolean + else testForNumber + ) /** The Tree => Tree function in the return is necessary to prevent the original qual * from being duplicated in the resulting code. It may be a side-effecting expression, @@ -345,12 +301,13 @@ abstract class CleanUp extends Transform with ast.TreeDSL { * (If the compiler can verify qual is safe to inline, it will not create the block.) */ def getPrimitiveReplacementForStructuralCall(name: Name): Option[(Symbol, Tree => Tree)] = { - val opt = ( - if (params.isEmpty) postfixTest(name) - else if (params.tail.isEmpty) infixTest(name) - else None + val methodName = ( + if (params.isEmpty) nme.primitivePostfixMethodName(name) + else if (params.tail.isEmpty) nme.primitiveInfixMethodName(name) + else nme.NO_NAME ) - opt map { case (name, fn) => (getMember(BoxesRunTimeClass, name), fn) } + if (methodName == nme.NO_NAME) None + else Some((getMember(BoxesRunTimeClass, methodName), testForName(name))) } /* ### BOXING PARAMS & UNBOXING RESULTS ### */ diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index e03f329577..4d4f4f4c27 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -291,11 +291,10 @@ abstract class Constructors extends Transform with ast.TreeDSL { * be an error to pass it to array_update(.., .., Object). */ def rewriteArrayUpdate(tree: Tree): Tree = { - val array_update = definitions.ScalaRunTimeModule.info.member("array_update") val adapter = new Transformer { override def transform(t: Tree): Tree = t match { - case Apply(fun @ Select(receiver, method), List(xs, idx, v)) if fun.symbol == array_update => - localTyper.typed(Apply(gen.mkAttributedSelect(xs, definitions.Array_update), List(idx, v))) + case Apply(fun @ Select(receiver, method), List(xs, idx, v)) if fun.symbol == arrayUpdateMethod => + localTyper.typed(Apply(gen.mkAttributedSelect(xs, arrayUpdateMethod), List(idx, v))) case _ => super.transform(t) } } diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 1a421eb82f..b327579c8b 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -866,7 +866,7 @@ abstract class Erasure extends AddInterfaces unboundedGenericArrayLevel(arg.tpe) > 0) => val level = unboundedGenericArrayLevel(arg.tpe) def isArrayTest(arg: Tree) = - gen.mkRuntimeCall("isArray", List(arg, Literal(Constant(level)))) + gen.mkRuntimeCall(nme.isArray, List(arg, Literal(Constant(level)))) global.typer.typedPos(tree.pos) { if (level == 1) isArrayTest(qual) @@ -891,7 +891,16 @@ abstract class Erasure extends AddInterfaces if (unboundedGenericArrayLevel(qual.tpe.widen) == 1) // convert calls to apply/update/length on generic arrays to // calls of ScalaRunTime.array_xxx method calls - global.typer.typedPos(tree.pos) { gen.mkRuntimeCall("array_"+name, qual :: args) } + global.typer.typedPos(tree.pos)({ + val arrayMethodName = name match { + case nme.apply => nme.array_apply + case nme.length => nme.array_length + case nme.update => nme.array_update + case nme.clone_ => nme.array_clone + case _ => unit.error(tree.pos, "Unexpected array member, no translation exists.") ; nme.NO_NAME + } + gen.mkRuntimeCall(arrayMethodName, qual :: args) + }) else // store exact array erasure in map to be retrieved later when we might // need to do the cast in adaptMember diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index fcc03a82d0..cf7d6c94fe 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -68,6 +68,8 @@ abstract class ExplicitOuter extends InfoTransform result } + + private val innerClassConstructorParamName: TermName = newTermName("arg" + nme.OUTER) class RemoveBindingsTransformer(toRemove: Set[Symbol]) extends Transformer { override def transform(tree: Tree) = tree match { @@ -134,7 +136,7 @@ abstract class ExplicitOuter extends InfoTransform } if (sym.owner.isTrait) sym setNotFlag PROTECTED // 6 if (sym.isClassConstructor && isInner(sym.owner)) { // 1 - val p = sym.newValueParameter(sym.pos, "arg" + nme.OUTER) + val p = sym.newValueParameter(sym.pos, innerClassConstructorParamName) .setInfo(sym.owner.outerClass.thisType) MethodType(p :: params, restpe) } else if (restpe ne restpe1) diff --git a/src/compiler/scala/tools/nsc/transform/LiftCode.scala b/src/compiler/scala/tools/nsc/transform/LiftCode.scala index 171d1df975..bc7d1754d4 100644 --- a/src/compiler/scala/tools/nsc/transform/LiftCode.scala +++ b/src/compiler/scala/tools/nsc/transform/LiftCode.scala @@ -165,9 +165,6 @@ abstract class LiftCode extends Transform with TypingTransformers { */ class Reifier() { - final val mirrorFullName = "scala.reflect.mirror" - final val mirrorShortName = "$mr" - final val mirrorPrefix = mirrorShortName + "." final val scalaPrefix = "scala." final val localPrefix = "$local" final val memoizerName = "$memo" @@ -217,16 +214,20 @@ abstract class LiftCode extends Transform with TypingTransformers { // helper methods - private def localName(sym: Symbol) = localPrefix + symIndex(sym) + private def localName(sym: Symbol): TermName = + newTermName(localPrefix + symIndex(sym)) private def call(fname: String, args: Tree*): Tree = Apply(termPath(fname), args.toList) private def mirrorSelect(name: String): Tree = - termPath(mirrorPrefix + name) + termPath(nme.MIRROR_PREFIX + name) + + private def mirrorCall(name: TermName, args: Tree*): Tree = + call("" + (nme.MIRROR_PREFIX append name), args: _*) private def mirrorCall(name: String, args: Tree*): Tree = - call(mirrorPrefix + name, args: _*) + call(nme.MIRROR_PREFIX + name, args: _*) private def mirrorFactoryCall(value: Product, args: Tree*): Tree = mirrorCall(value.productPrefix, args: _*) @@ -322,15 +323,15 @@ abstract class LiftCode extends Transform with TypingTransformers { * Generate code to add type and annotation info to a reified symbol */ private def fillInSymbol(sym: Symbol): Tree = { - val rset = Apply(Select(reifySymRef(sym), "setTypeSig"), List(reifyType(sym.info))) + val rset = Apply(Select(reifySymRef(sym), nme.setTypeSig), List(reifyType(sym.info))) if (sym.annotations.isEmpty) rset - else Apply(Select(rset, "setAnnotations"), List(reify(sym.annotations))) + else Apply(Select(rset, nme.setAnnotations), List(reify(sym.annotations))) } /** Reify a scope */ private def reifyScope(scope: Scope): Tree = { scope foreach registerReifiableSymbol - mirrorCall("newScopeWith", scope.toList map reifySymRef: _*) + mirrorCall(nme.newScopeWith, scope.toList map reifySymRef: _*) } /** Reify a list of symbols that need to be created */ @@ -348,14 +349,14 @@ abstract class LiftCode extends Transform with TypingTransformers { val tpe = tpe0.normalize val tsym = tpe.typeSymbol if (tsym.isClass && tpe == tsym.typeConstructor && tsym.isStatic) - Select(reifySymRef(tpe.typeSymbol), "asTypeConstructor") + Select(reifySymRef(tpe.typeSymbol), nme.asTypeConstructor) else tpe match { case t @ NoType => reifyMirrorObject(t) case t @ NoPrefix => reifyMirrorObject(t) case tpe @ ThisType(clazz) if clazz.isModuleClass && clazz.isStatic => - mirrorCall("thisModuleType", reify(clazz.fullName)) + mirrorCall(nme.thisModuleType, reify(clazz.fullName)) case t @ RefinedType(parents, decls) => registerReifiableSymbol(tpe.typeSymbol) mirrorFactoryCall(t, reify(parents), reify(decls), reify(t.typeSymbol)) @@ -387,13 +388,13 @@ abstract class LiftCode extends Transform with TypingTransformers { case tt: TypeTree if (tt.tpe != null) => if (!(boundSyms exists (tt.tpe contains _))) mirrorCall("TypeTree", reifyType(tt.tpe)) else if (tt.original != null) reify(tt.original) - else mirrorCall("TypeTree") + else mirrorCall(nme.TypeTree) case ta @ TypeApply(hk, ts) => val thereAreOnlyTTs = ts collect { case t if !t.isInstanceOf[TypeTree] => t } isEmpty; val ttsAreNotEssential = ts collect { case tt: TypeTree => tt } find { tt => tt.original != null } isEmpty; if (thereAreOnlyTTs && ttsAreNotEssential) reifyTree(hk) else reifyProduct(ta) case global.emptyValDef => - mirrorSelect("emptyValDef") + mirrorSelect(nme.emptyValDef) case _ => if (tree.isDef) boundSyms += tree.symbol @@ -403,8 +404,8 @@ abstract class LiftCode extends Transform with TypingTransformers { if (tree.isDef || tree.isInstanceOf[Function]) registerReifiableSymbol(tree.symbol) if (tree.hasSymbol) - rtree = Apply(Select(rtree, "setSymbol"), List(reifySymRef(tree.symbol))) - Apply(Select(rtree, "setType"), List(reifyType(tree.tpe))) + rtree = Apply(Select(rtree, nme.setSymbol), List(reifySymRef(tree.symbol))) + Apply(Select(rtree, nme.setType), List(reifyType(tree.tpe))) */ } @@ -413,7 +414,7 @@ abstract class LiftCode extends Transform with TypingTransformers { * to a global value, or else a mirror Literal. */ private def reifyFree(tree: Tree): Tree = - mirrorCall("Ident", reifySymRef(tree.symbol)) + mirrorCall(nme.Ident, reifySymRef(tree.symbol)) // todo: consider whether we should also reify positions private def reifyPosition(pos: Position): Tree = @@ -443,7 +444,7 @@ abstract class LiftCode extends Transform with TypingTransformers { case sym: Symbol => reifySymRef(sym) case tpe: Type => reifyType(tpe) case xs: List[_] => reifyList(xs) - case xs: Array[_] => scalaFactoryCall("Array", xs map reify: _*) + case xs: Array[_] => scalaFactoryCall(nme.Array, xs map reify: _*) case scope: Scope => reifyScope(scope) case x: Name => reifyName(x) case x: Position => reifyPosition(x) @@ -475,7 +476,7 @@ abstract class LiftCode extends Transform with TypingTransformers { private def typePath(fullname: String): Tree = path(fullname, newTypeName) private def mirrorAlias = - ValDef(NoMods, mirrorShortName, TypeTree(), termPath(mirrorFullName)) + ValDef(NoMods, nme.MIRROR_SHORT, TypeTree(), termPath(fullnme.MirrorPackage)) /** * Generate code that generates a symbol table of all symbols registered in `reifiableSyms` diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala index ca16e491e2..e2cd0a8402 100644 --- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala +++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala @@ -128,7 +128,7 @@ abstract class TailCalls extends Transform { * the label field. */ this.label = { - val label = method.newLabel(method.pos, "_" + method.name) + val label = method.newLabel(method.pos, newTermName("_" + method.name)) val thisParam = method.newSyntheticValueParam(currentClass.typeOfThis) label setInfo MethodType(thisParam :: method.tpe.params, method.tpe.finalResultType) } diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 13516037f5..adb408f7e4 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -357,7 +357,7 @@ abstract class UnCurry extends InfoTransform case Apply(Apply(TypeApply(Select(tgt, nme.runOrElse), targs), args_scrut), args_pm) if opt.virtPatmat => object noOne extends Transformer { override val treeCopy = newStrictTreeCopier // must duplicate everything - val one = tgt.tpe member "one".toTermName + val one = tgt.tpe member newTermName("one") override def transform(tree: Tree): Tree = tree match { case Apply(fun, List(a)) if fun.symbol == one => // blow one's argument away since all we want to know is whether the match succeeds or not @@ -367,7 +367,7 @@ abstract class UnCurry extends InfoTransform super.transform(tree) } } - substTree(Apply(Apply(TypeApply(Select(tgt.duplicate, tgt.tpe.member("isSuccess".toTermName)), targs map (_.duplicate)), args_scrut map (_.duplicate)), args_pm map (noOne.transform))) + substTree(Apply(Apply(TypeApply(Select(tgt.duplicate, tgt.tpe.member(newTermName("isSuccess"))), targs map (_.duplicate)), args_scrut map (_.duplicate)), args_pm map (noOne.transform))) // for the optimized version of virtpatmat case Block((zero: ValDef) :: (x: ValDef) :: (matchRes: ValDef) :: (keepGoing: ValDef) :: stats, _) if opt.virtPatmat => dupVirtMatch(zero, x, matchRes, keepGoing, stats) @@ -452,7 +452,7 @@ abstract class UnCurry extends InfoTransform atPhase(phase.next) { if (isJava && isPrimitiveArray(suffix.tpe) && isArrayOfSymbol(fun.tpe.params.last.tpe, ObjectClass)) { suffix = localTyper.typedPos(pos) { - gen.mkRuntimeCall("toObjectArray", List(suffix)) + gen.mkRuntimeCall(nme.toObjectArray, List(suffix)) } } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 77dde88a80..3b90eaeed7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -214,10 +214,10 @@ trait Implicits { /** An extractor for types of the form ? { name: (? >: argtpe <: Any*)restp } */ object HasMethodMatching { + val dummyMethod = new TermSymbol(NoSymbol, NoPosition, newTermName("typer$dummy")) + def templateArgType(argtpe: Type) = new BoundedWildcardType(TypeBounds.lower(argtpe)) + def apply(name: Name, argtpes: List[Type], restpe: Type): Type = { - def templateArgType(argtpe: Type) = - new BoundedWildcardType(TypeBounds(argtpe, AnyClass.tpe)) - val dummyMethod = new TermSymbol(NoSymbol, NoPosition, "typer$dummy") val mtpe = MethodType(dummyMethod.newSyntheticValueParams(argtpes map templateArgType), restpe) memberWildcardType(name, mtpe) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 99ba0e0971..b9264aae55 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -7,13 +7,10 @@ trait Macros { self: Analyzer => import global._ import definitions._ - def macroMethName(name: Name) = - newTermName((if (name.isTypeName) "type" else "def") + "macro$" + name) - def macroMeth(mac: Symbol): Symbol = { var owner = mac.owner if (!owner.isModuleClass) owner = owner.companionModule.moduleClass - owner.info.decl(macroMethName(mac.name)) + owner.info.decl(nme.macroMethodName(mac.name)) } /** @@ -37,21 +34,21 @@ trait Macros { self: Analyzer => def macroMethDef(mdef: DefDef): Tree = { def paramDef(name: Name, tpt: Tree) = ValDef(Modifiers(PARAM), name, tpt, EmptyTree) val universeType = TypeTree(ReflectApiUniverse.tpe) - val globParamSec = List(paramDef("glob", universeType)) - def globSelect(name: Name) = Select(Ident("glob"), name) + val globParamSec = List(paramDef(nme.glob, universeType)) + def globSelect(name: Name) = Select(Ident(nme.glob), name) def globTree = globSelect(newTypeName("Tree")) def globType = globSelect(newTypeName("Type")) - val thisParamSec = if (mdef.symbol.owner.isModuleClass) List() else List(paramDef("_this", globTree)) + val thisParamSec = if (mdef.symbol.owner.isModuleClass) List() else List(paramDef(newTermName("_this"), globTree)) def tparamInMacro(tdef: TypeDef) = paramDef(tdef.name.toTermName, globType) def vparamInMacro(vdef: ValDef): ValDef = paramDef(vdef.name, globTree) def wrapImplicit(tree: Tree) = atPos(tree.pos) { - Block(List(ValDef(Modifiers(IMPLICIT), "$glob", universeType, Ident("glob"))), tree) + Block(List(ValDef(Modifiers(IMPLICIT), newTermName("$" + nme.glob), universeType, Ident(nme.glob))), tree) } atPos(mdef.pos) { new DefDef( // can't call DefDef here; need to find out why mods = mdef.mods &~ MACRO, - name = macroMethName(mdef.name), + name = nme.macroMethodName(mdef.name), tparams = List(), vparamss = globParamSec :: thisParamSec :: (mdef.tparams map tparamInMacro) :: (mdef.vparamss map (_ map vparamInMacro)), diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala index 7c605fa0a1..62393befd2 100644 --- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala +++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala @@ -248,7 +248,7 @@ trait MethodSynthesis { } sealed abstract class BeanAccessor(bean: String) extends DerivedFromValDef { - def name = bean + tree.name.toString.capitalize + val name = newTermName(bean + tree.name.toString.capitalize) def flagsMask = BeanPropertyFlags def flagsExtra = 0 override def derivedSym = enclClass.info decl name diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index a20461949d..200191fa13 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -579,7 +579,7 @@ trait Namers extends MethodSynthesis { // via "x$lzy" as can be seen in test #3927. val sym = ( if (owner.isClass) createFieldSymbol(tree) - else owner.newValue(tree.pos, tree.name + "$lzy") setFlag tree.mods.flags resetFlag IMPLICIT + else owner.newValue(tree.pos, tree.name append nme.LAZY_LOCAL) setFlag tree.mods.flags resetFlag IMPLICIT ) enterValSymbol(tree, sym setFlag MUTABLE setLazyAccessor lazyAccessor) } diff --git a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala index 75a5ad6f8a..440db4300c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala @@ -46,8 +46,6 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => import global._ import definitions._ - private lazy val matchingStrategyTycon = definitions.getClass("scala.MatchingStrategy").typeConstructor - class MatchTranslator(typer: Typer) extends MatchCodeGen { def typed(tree: Tree, mode: Int, pt: Type): Tree = typer.typed(tree, mode, pt) // for MatchCodeGen -- imports don't provide implementations for abstract members @@ -55,7 +53,7 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => import typeDebug.{ ptTree, ptBlock, ptLine } def solveContextBound(contextBoundTp: Type): (Tree, Type) = { - val solSym = NoSymbol.newTypeParameter(NoPosition, "SolveImplicit$".toTypeName) + val solSym = NoSymbol.newTypeParameter(NoPosition, newTypeName("SolveImplicit$")) val param = solSym.setInfo(contextBoundTp.typeSymbol.typeParams(0).info.cloneInfo(solSym)) // TypeBounds(NothingClass.typeConstructor, baseTp) val pt = appliedType(contextBoundTp, List(param.tpeHK)) val savedUndets = context.undetparams @@ -67,7 +65,7 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => (result.tree, result.subst.to(result.subst.from indexOf param)) } - lazy val (matchingStrategy, matchingMonadType) = solveContextBound(matchingStrategyTycon) + lazy val (matchingStrategy, matchingMonadType) = solveContextBound(MatchingStrategyClass.typeConstructor) /** Implement a pattern match by turning its cases (including the implicit failure case) * into the corresponding (monadic) extractors, and combining them with the `orElse` combinator. @@ -1482,19 +1480,18 @@ defined class Foo */ } object vpmName { - val one = "one".toTermName - val drop = "drop".toTermName - val flatMap = "flatMap".toTermName - val get = "get".toTermName - val guard = "guard".toTermName - val isEmpty = "isEmpty".toTermName - val orElse = "orElse".toTermName - val outer = "".toTermName - val runOrElse = "runOrElse".toTermName - val zero = "zero".toTermName - - def counted(str: String, i: Int) = (str+i).toTermName - def tupleIndex(i: Int) = ("_"+i).toTermName + val one = newTermName("one") + val drop = newTermName("drop") + val flatMap = newTermName("flatMap") + val get = newTermName("get") + val guard = newTermName("guard") + val isEmpty = newTermName("isEmpty") + val orElse = newTermName("orElse") + val outer = newTermName("") + val runOrElse = newTermName("runOrElse") + val zero = newTermName("zero") + + def counted(str: String, i: Int) = newTermName(str+i) } @@ -1503,7 +1500,7 @@ defined class Foo */ trait CommonCodeGen extends AbsCodeGen { self: CommonCodeGen with MatchingStrategyGen with MonadInstGen => def fun(arg: Symbol, body: Tree): Tree = Function(List(ValDef(arg)), body) def genTypeApply(tfun: Tree, args: Type*): Tree = if(args contains NoType) tfun else TypeApply(tfun, args.toList map TypeTree) - def tupleSel(binder: Symbol)(i: Int): Tree = (REF(binder) DOT vpmName.tupleIndex(i)) // make tree that accesses the i'th component of the tuple referenced by binder + def tupleSel(binder: Symbol)(i: Int): Tree = (REF(binder) DOT nme.productAccessorName(i)) // make tree that accesses the i'th component of the tuple referenced by binder def index(tgt: Tree)(i: Int): Tree = tgt APPLY (LIT(i)) def drop(tgt: Tree)(n: Int): Tree = (tgt DOT vpmName.drop) (LIT(n)) def _equals(checker: Tree, binder: Symbol): Tree = checker MEMBER_== REF(binder) // NOTE: checker must be the target of the ==, that's the patmat semantics for ya diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 3d4f5e8724..92e4e257bf 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -39,10 +39,6 @@ trait SyntheticMethods extends ast.TreeDSL { private object util { private type CM[T] = ClassManifest[T] - lazy val IteratorModule = getModule("scala.collection.Iterator") - lazy val Iterator_apply = getMember(IteratorModule, nme.apply) - def iteratorOfType(tp: Type) = appliedType(IteratorClass.typeConstructor, List(tp)) - def ValOrDefDef(sym: Symbol, body: Tree) = if (sym.isLazy) ValDef(sym, body) else DefDef(sym, body) @@ -76,11 +72,11 @@ trait SyntheticMethods extends ast.TreeDSL { } def manifestToSymbol(m: CM[_]): Symbol = m match { - case x: scala.reflect.AnyValManifest[_] => definitions.getClass("scala." + x) + case x: scala.reflect.AnyValManifest[_] => getMember(ScalaPackageClass, newTermName("" + x)) case _ => getClassIfDefined(m.erasure.getName) } def companionType[T](implicit m: CM[T]) = - getModule(m.erasure.getName).tpe + getRequiredModule(m.erasure.getName).tpe // Use these like `applyType[List, Int]` or `applyType[Map, Int, String]` def applyType[M](implicit m1: CM[M]): Type = @@ -202,7 +198,7 @@ trait SyntheticMethods extends ast.TreeDSL { // in the original order. def accessors = clazz.caseFieldAccessors sortBy { acc => originalAccessors indexWhere { orig => - (acc.name == orig.name) || (acc.name startsWith (orig.name + "$").toTermName) + (acc.name == orig.name) || (acc.name startsWith (orig.name append "$")) } } val arity = accessors.size @@ -225,7 +221,7 @@ trait SyntheticMethods extends ast.TreeDSL { ) def forwardToRuntime(method: Symbol): Tree = - forwardMethod(method, getMember(ScalaRunTimeModule, "_" + method.name toTermName))(This(clazz) :: _) + forwardMethod(method, getMember(ScalaRunTimeModule, method.name prepend "_"))(This(clazz) :: _) // Any member, including private def hasConcreteImpl(name: Name) = @@ -238,14 +234,14 @@ trait SyntheticMethods extends ast.TreeDSL { } } def readConstantValue[T](name: String, default: T = null.asInstanceOf[T]): T = { - clazzMember(name.toTermName).info match { + clazzMember(newTermName(name)).info match { case NullaryMethodType(ConstantType(Constant(value))) => value.asInstanceOf[T] case _ => default } } def productIteratorMethod = { createMethod(nme.productIterator, iteratorOfType(accessorLub))(_ => - gen.mkMethodCall(ScalaRunTimeModule, "typedProductIterator", List(accessorLub), List(This(clazz))) + gen.mkMethodCall(ScalaRunTimeModule, nme.typedProductIterator, List(accessorLub), List(This(clazz))) ) } def projectionMethod(accessor: Symbol, num: Int) = { diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index a7ad140fc1..5ccf27ded9 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3478,7 +3478,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case ex: TypeError => fun match { case Select(qual, name) - if !isPatternMode && nme.isOpAssignmentName(name.decode) => + if !isPatternMode && nme.isOpAssignmentName(newTermName(name.decode)) => val qual1 = typedQualifier(qual) if (treeInfo.isVariableOrGetter(qual1)) { stopTimer(failedOpEqNanos, opeqStart) diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index 9b69c847f6..fd6f972ffc 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -21,6 +21,8 @@ trait Unapplies extends ast.TreeDSL import CODE.{ CASE => _, _ } import treeInfo.{ isRepeatedParamType, isByNameParamType } + private val unapplyParamName = newTermName("x$0") + /** returns type list for return type of the extraction */ def unapplyTypeList(ufn: Symbol, ufntpe: Type) = { assert(ufn.isMethod) @@ -173,14 +175,13 @@ trait Unapplies extends ast.TreeDSL */ def caseModuleUnapplyMeth(cdef: ClassDef): DefDef = { val tparams = cdef.tparams map copyUntypedInvariant - val paramName = newTermName("x$0") val method = constrParamss(cdef) match { case xs :: _ if xs.nonEmpty && isRepeatedParamType(xs.last.tpt) => nme.unapplySeq case _ => nme.unapply } - val cparams = List(ValDef(Modifiers(PARAM | SYNTHETIC), paramName, classType(cdef, tparams), EmptyTree)) + val cparams = List(ValDef(Modifiers(PARAM | SYNTHETIC), unapplyParamName, classType(cdef, tparams), EmptyTree)) val ifNull = if (constrParamss(cdef).head.isEmpty) FALSE else REF(NoneModule) - val body = nullSafe({ case Ident(x) => caseClassUnapplyReturnValue(x, cdef.symbol) }, ifNull)(Ident(paramName)) + val body = nullSafe({ case Ident(x) => caseClassUnapplyReturnValue(x, cdef.symbol) }, ifNull)(Ident(unapplyParamName)) atPos(cdef.pos.focus)( DefDef(caseMods, method, tparams, List(cparams), TypeTree(), body) diff --git a/src/compiler/scala/tools/nsc/util/ProxyReport.scala b/src/compiler/scala/tools/nsc/util/ProxyReport.scala index 86cf2006bb..2f4f029308 100644 --- a/src/compiler/scala/tools/nsc/util/ProxyReport.scala +++ b/src/compiler/scala/tools/nsc/util/ProxyReport.scala @@ -13,7 +13,7 @@ import scala.collection.{ mutable, immutable, generic } trait ProxyReport { val global: Global import global._ - import definitions.{ getClass => gc, _ } + import definitions._ private object classes { def isIgnorable(sym: Symbol) = sym :: sym.allOverriddenSymbols exists { s => @@ -26,13 +26,13 @@ trait ProxyReport { methods foreach (m => m.initialize.info.paramss.flatten foreach (_.initialize)) methods } - lazy val GlobalClass = gc(classOf[Global].getName) - lazy val GenericClass = getModule("scala.collection.generic").moduleClass - lazy val CollectionClass = getModule("scala.collection").moduleClass + lazy val GlobalClass = getRequiredClass(classOf[Global].getName) + lazy val GenericClass = getRequiredModule("scala.collection.generic").moduleClass + lazy val CollectionClass = getRequiredModule("scala.collection").moduleClass - def getType(name: String) = getMember(GlobalClass, name.toTypeName) - def getColl(name: String) = getMember(CollectionClass, name.toTypeName) - def getGeneric(name: String) = getMember(GenericClass, name.toTypeName) + def getType(name: String) = getMember(GlobalClass, newTypeName(name)) + def getColl(name: String) = getMember(CollectionClass, newTypeName(name)) + def getGeneric(name: String) = getMember(GenericClass, newTypeName(name)) // the following operations + those in RewrappingTypeProxy are all operations // in class Type that are overridden in some subclass diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala index f4481b800e..8bbda5dd05 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala @@ -12,22 +12,37 @@ trait CPSUtils { var cpsEnabled = true val verbose: Boolean = System.getProperty("cpsVerbose", "false") == "true" def vprintln(x: =>Any): Unit = if (verbose) println(x) + + object cpsNames { + val catches = newTermName("$catches") + val ex = newTermName("$ex") + val flatMapCatch = newTermName("flatMapCatch") + val getTrivialValue = newTermName("getTrivialValue") + val isTrivial = newTermName("isTrivial") + val reify = newTermName("reify") + val reifyR = newTermName("reifyR") + val shift = newTermName("shift") + val shiftR = newTermName("shiftR") + val shiftSuffix = newTermName("$shift") + val shiftUnit = newTermName("shiftUnit") + val shiftUnitR = newTermName("shiftUnitR") + } - lazy val MarkerCPSSym = definitions.getClass("scala.util.continuations.cpsSym") - lazy val MarkerCPSTypes = definitions.getClass("scala.util.continuations.cpsParam") - lazy val MarkerCPSSynth = definitions.getClass("scala.util.continuations.cpsSynth") - lazy val MarkerCPSAdaptPlus = definitions.getClass("scala.util.continuations.cpsPlus") - lazy val MarkerCPSAdaptMinus = definitions.getClass("scala.util.continuations.cpsMinus") - - lazy val Context = definitions.getClass("scala.util.continuations.ControlContext") - lazy val ModCPS = definitions.getModule("scala.util.continuations") - - lazy val MethShiftUnit = definitions.getMember(ModCPS, "shiftUnit") - lazy val MethShiftUnitR = definitions.getMember(ModCPS, "shiftUnitR") - lazy val MethShift = definitions.getMember(ModCPS, "shift") - lazy val MethShiftR = definitions.getMember(ModCPS, "shiftR") - lazy val MethReify = definitions.getMember(ModCPS, "reify") - lazy val MethReifyR = definitions.getMember(ModCPS, "reifyR") + lazy val MarkerCPSSym = definitions.getRequiredClass("scala.util.continuations.cpsSym") + lazy val MarkerCPSTypes = definitions.getRequiredClass("scala.util.continuations.cpsParam") + lazy val MarkerCPSSynth = definitions.getRequiredClass("scala.util.continuations.cpsSynth") + lazy val MarkerCPSAdaptPlus = definitions.getRequiredClass("scala.util.continuations.cpsPlus") + lazy val MarkerCPSAdaptMinus = definitions.getRequiredClass("scala.util.continuations.cpsMinus") + + lazy val Context = definitions.getRequiredClass("scala.util.continuations.ControlContext") + lazy val ModCPS = definitions.getRequiredModule("scala.util.continuations") + + lazy val MethShiftUnit = definitions.getMember(ModCPS, cpsNames.shiftUnit) + lazy val MethShiftUnitR = definitions.getMember(ModCPS, cpsNames.shiftUnitR) + lazy val MethShift = definitions.getMember(ModCPS, cpsNames.shift) + lazy val MethShiftR = definitions.getMember(ModCPS, cpsNames.shiftR) + lazy val MethReify = definitions.getMember(ModCPS, cpsNames.reify) + lazy val MethReifyR = definitions.getMember(ModCPS, cpsNames.reifyR) lazy val allCPSAnnotations = List(MarkerCPSSym, MarkerCPSTypes, MarkerCPSSynth, MarkerCPSAdaptPlus, MarkerCPSAdaptMinus) diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala index b383227243..585dc3fbe8 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala @@ -355,7 +355,7 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with val valueTpe = removeAllCPSAnnotations(expr.tpe) - val sym = currentOwner.newValue(tree.pos, unit.fresh.newName("tmp")) + val sym = currentOwner.newValue(tree.pos, newTermName(unit.fresh.newName("tmp"))) .setInfo(valueTpe) .setFlag(Flags.SYNTHETIC) .setAnnotations(List(AnnotationInfo(MarkerCPSSym.tpe, Nil, Nil))) diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala index f0c389bb11..960b27c52f 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala @@ -192,21 +192,21 @@ abstract class SelectiveCPSTransform extends PluginComponent with // val expr2 = if (catches.nonEmpty) { val pos = catches.head.pos - val argSym = currentOwner.newValueParameter(pos, "$ex").setInfo(ThrowableClass.tpe) + val argSym = currentOwner.newValueParameter(pos, cpsNames.ex).setInfo(ThrowableClass.tpe) val rhs = Match(Ident(argSym), catches1) val fun = Function(List(ValDef(argSym)), rhs) - val funSym = currentOwner.newValueParameter(pos, "$catches").setInfo(appliedType(PartialFunctionClass.tpe, List(ThrowableClass.tpe, targettp))) + val funSym = currentOwner.newValueParameter(pos, cpsNames.catches).setInfo(appliedType(PartialFunctionClass.tpe, List(ThrowableClass.tpe, targettp))) val funDef = localTyper.typed(atPos(pos) { ValDef(funSym, fun) }) - val expr2 = localTyper.typed(atPos(pos) { Apply(Select(expr1, expr1.tpe.member("flatMapCatch")), List(Ident(funSym))) }) + val expr2 = localTyper.typed(atPos(pos) { Apply(Select(expr1, expr1.tpe.member(cpsNames.flatMapCatch)), List(Ident(funSym))) }) argSym.owner = fun.symbol val chown = new ChangeOwnerTraverser(currentOwner, fun.symbol) chown.traverse(rhs) - val exSym = currentOwner.newValueParameter(pos, "$ex").setInfo(ThrowableClass.tpe) + val exSym = currentOwner.newValueParameter(pos, cpsNames.ex).setInfo(ThrowableClass.tpe) val catch2 = { localTyper.typedCases(tree, List( CaseDef(Bind(exSym, Typed(Ident("_"), TypeTree(ThrowableClass.tpe))), - Apply(Select(Ident(funSym), "isDefinedAt"), List(Ident(exSym))), + Apply(Select(Ident(funSym), nme.isDefinedAt), List(Ident(exSym))), Apply(Ident(funSym), List(Ident(exSym)))) ), ThrowableClass.tpe, targettp) } @@ -317,11 +317,11 @@ abstract class SelectiveCPSTransform extends PluginComponent with log("fun.tpe:"+fun.tpe) log("return type of fun:"+body1.tpe) - var methodName = "map" + var methodName = nme.map if (body1.tpe != null) { if (body1.tpe.typeSymbol == Context) - methodName = "flatMap" + methodName = nme.flatMap } else unit.error(rhs.pos, "cannot compute type for CPS-transformed function result") @@ -347,14 +347,14 @@ abstract class SelectiveCPSTransform extends PluginComponent with // val = ctx.getTrivialValue; ... <--- TODO: try/catch ??? don't bother for the moment... // else // ctx.flatMap { => ... } - val ctxSym = currentOwner.newValue(vd.symbol.name + "$shift").setInfo(rhs1.tpe) + val ctxSym = currentOwner.newValue(vd.symbol.name append cpsNames.shiftSuffix).setInfo(rhs1.tpe) val ctxDef = localTyper.typed(ValDef(ctxSym, rhs1)) def ctxRef = localTyper.typed(Ident(ctxSym)) val argSym = currentOwner.newValue(vd.symbol.name).setInfo(tpe) - val argDef = localTyper.typed(ValDef(argSym, Select(ctxRef, ctxRef.tpe.member("getTrivialValue")))) + val argDef = localTyper.typed(ValDef(argSym, Select(ctxRef, ctxRef.tpe.member(cpsNames.getTrivialValue)))) val switchExpr = localTyper.typed(atPos(vd.symbol.pos) { val body2 = mkBlock(bodyStms, bodyExpr).duplicate // dup before typing! - If(Select(ctxRef, ctxSym.tpe.member("isTrivial")), + If(Select(ctxRef, ctxSym.tpe.member(cpsNames.isTrivial)), applyTrivial(argSym, mkBlock(argDef::bodyStms, bodyExpr)), applyCombinatorFun(ctxRef, body2)) }) diff --git a/src/library/scala/io/Codec.scala b/src/library/scala/io/Codec.scala index fa17f3eaeb..1a27df1c10 100644 --- a/src/library/scala/io/Codec.scala +++ b/src/library/scala/io/Codec.scala @@ -110,7 +110,15 @@ object Codec extends LowPriorityCodecImplicits { @migration("This method was previously misnamed `fromUTF8`. Converts from character sequence to Array[Byte].", "2.9.0") def toUTF8(cs: CharSequence): Array[Byte] = { - val cbuffer = java.nio.CharBuffer wrap cs + val cbuffer = java.nio.CharBuffer.wrap(cs, 0, cs.length) + val bbuffer = UTF8.charSet encode cbuffer + val bytes = new Array[Byte](bbuffer.remaining()) + bbuffer get bytes + + bytes + } + def toUTF8(chars: Array[Char], offset: Int, len: Int): Array[Byte] = { + val cbuffer = java.nio.CharBuffer.wrap(chars, offset, len) val bbuffer = UTF8.charSet encode cbuffer val bytes = new Array[Byte](bbuffer.remaining()) bbuffer get bytes diff --git a/src/library/scala/reflect/Manifest.scala b/src/library/scala/reflect/Manifest.scala index df5f64cdf6..4b402f69b1 100644 --- a/src/library/scala/reflect/Manifest.scala +++ b/src/library/scala/reflect/Manifest.scala @@ -77,10 +77,13 @@ trait AnyValManifest[T] extends Manifest[T] with Equals { */ object Manifest { private def ObjectClass = classOf[java.lang.Object] + + def valueManifests: List[AnyValManifest[_ <: scala.AnyVal]] = + List(Byte, Short, Char, Int, Long, Float, Double, Boolean, Unit) val Byte: AnyValManifest[Byte] = new AnyValManifest[scala.Byte] { def erasure = java.lang.Byte.TYPE - override def toString = "Byte" + final override val toString = "Byte" override def newArray(len: Int): Array[Byte] = new Array[Byte](len) override def newWrappedArray(len: Int): WrappedArray[Byte] = new WrappedArray.ofByte(new Array[Byte](len)) override def newArrayBuilder(): ArrayBuilder[Byte] = new ArrayBuilder.ofByte() @@ -89,7 +92,7 @@ object Manifest { val Short: AnyValManifest[Short] = new AnyValManifest[scala.Short] { def erasure = java.lang.Short.TYPE - override def toString = "Short" + final override val toString = "Short" override def newArray(len: Int): Array[Short] = new Array[Short](len) override def newWrappedArray(len: Int): WrappedArray[Short] = new WrappedArray.ofShort(new Array[Short](len)) override def newArrayBuilder(): ArrayBuilder[Short] = new ArrayBuilder.ofShort() @@ -98,7 +101,7 @@ object Manifest { val Char: AnyValManifest[Char] = new AnyValManifest[scala.Char] { def erasure = java.lang.Character.TYPE - override def toString = "Char" + final override val toString = "Char" override def newArray(len: Int): Array[Char] = new Array[Char](len) override def newWrappedArray(len: Int): WrappedArray[Char] = new WrappedArray.ofChar(new Array[Char](len)) override def newArrayBuilder(): ArrayBuilder[Char] = new ArrayBuilder.ofChar() @@ -107,7 +110,7 @@ object Manifest { val Int: AnyValManifest[Int] = new AnyValManifest[scala.Int] { def erasure = java.lang.Integer.TYPE - override def toString = "Int" + final override val toString = "Int" override def newArray(len: Int): Array[Int] = new Array[Int](len) override def newWrappedArray(len: Int): WrappedArray[Int] = new WrappedArray.ofInt(new Array[Int](len)) override def newArrayBuilder(): ArrayBuilder[Int] = new ArrayBuilder.ofInt() @@ -116,7 +119,7 @@ object Manifest { val Long: AnyValManifest[Long] = new AnyValManifest[scala.Long] { def erasure = java.lang.Long.TYPE - override def toString = "Long" + final override val toString = "Long" override def newArray(len: Int): Array[Long] = new Array[Long](len) override def newWrappedArray(len: Int): WrappedArray[Long] = new WrappedArray.ofLong(new Array[Long](len)) override def newArrayBuilder(): ArrayBuilder[Long] = new ArrayBuilder.ofLong() @@ -125,7 +128,7 @@ object Manifest { val Float: AnyValManifest[Float] = new AnyValManifest[scala.Float] { def erasure = java.lang.Float.TYPE - override def toString = "Float" + final override val toString = "Float" override def newArray(len: Int): Array[Float] = new Array[Float](len) override def newWrappedArray(len: Int): WrappedArray[Float] = new WrappedArray.ofFloat(new Array[Float](len)) override def newArrayBuilder(): ArrayBuilder[Float] = new ArrayBuilder.ofFloat() @@ -134,7 +137,7 @@ object Manifest { val Double: AnyValManifest[Double] = new AnyValManifest[scala.Double] { def erasure = java.lang.Double.TYPE - override def toString = "Double" + final override val toString = "Double" override def newArray(len: Int): Array[Double] = new Array[Double](len) override def newWrappedArray(len: Int): WrappedArray[Double] = new WrappedArray.ofDouble(new Array[Double](len)) override def newArrayBuilder(): ArrayBuilder[Double] = new ArrayBuilder.ofDouble() @@ -143,7 +146,7 @@ object Manifest { val Boolean: AnyValManifest[Boolean] = new AnyValManifest[scala.Boolean] { def erasure = java.lang.Boolean.TYPE - override def toString = "Boolean" + final override val toString = "Boolean" override def newArray(len: Int): Array[Boolean] = new Array[Boolean](len) override def newWrappedArray(len: Int): WrappedArray[Boolean] = new WrappedArray.ofBoolean(new Array[Boolean](len)) override def newArrayBuilder(): ArrayBuilder[Boolean] = new ArrayBuilder.ofBoolean() @@ -152,7 +155,7 @@ object Manifest { val Unit: AnyValManifest[Unit] = new AnyValManifest[scala.Unit] { def erasure = java.lang.Void.TYPE - override def toString = "Unit" + final override val toString = "Unit" override def newArray(len: Int): Array[Unit] = new Array[Unit](len) override def newWrappedArray(len: Int): WrappedArray[Unit] = new WrappedArray.ofUnit(new Array[Unit](len)) override def newArrayBuilder(): ArrayBuilder[Unit] = new ArrayBuilder.ofUnit() @@ -160,7 +163,7 @@ object Manifest { } val Any: Manifest[Any] = new ClassTypeManifest[scala.Any](None, ObjectClass, Nil) { - override def toString = "Any" + final override val toString = "Any" override def <:<(that: ClassManifest[_]): Boolean = (that eq this) override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] override def hashCode = System.identityHashCode(this) @@ -168,7 +171,7 @@ object Manifest { } val Object: Manifest[Object] = new ClassTypeManifest[java.lang.Object](None, ObjectClass, Nil) { - override def toString = "Object" + final override val toString = "Object" override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Any) override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] override def hashCode = System.identityHashCode(this) @@ -176,7 +179,7 @@ object Manifest { } val AnyVal: Manifest[AnyVal] = new ClassTypeManifest[scala.AnyVal](None, ObjectClass, Nil) { - override def toString = "AnyVal" + final override val toString = "AnyVal" override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Any) override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] override def hashCode = System.identityHashCode(this) @@ -184,7 +187,7 @@ object Manifest { } val Null: Manifest[Null] = new ClassTypeManifest[scala.Null](None, ObjectClass, Nil) { - override def toString = "Null" + final override val toString = "Null" override def <:<(that: ClassManifest[_]): Boolean = (that ne null) && (that ne Nothing) && !(that <:< AnyVal) override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] @@ -193,7 +196,7 @@ object Manifest { } val Nothing: Manifest[Nothing] = new ClassTypeManifest[scala.Nothing](None, ObjectClass, Nil) { - override def toString = "Nothing" + final override val toString = "Nothing" override def <:<(that: ClassManifest[_]): Boolean = (that ne null) override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] override def hashCode = System.identityHashCode(this) diff --git a/src/library/scala/reflect/api/Trees.scala b/src/library/scala/reflect/api/Trees.scala index e5502acb20..2394925657 100644 --- a/src/library/scala/reflect/api/Trees.scala +++ b/src/library/scala/reflect/api/Trees.scala @@ -542,12 +542,18 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe => case class Select(qualifier: Tree, name: Name) extends RefTree + def Select(qualifier: Tree, name: String): Select = + Select(qualifier, newTermName(name)) + def Select(qualifier: Tree, sym: Symbol): Select = Select(qualifier, sym.name) setSymbol sym /** Identifier */ case class Ident(name: Name) extends RefTree { } + def Ident(name: String): Ident = + Ident(newTermName(name)) + def Ident(sym: Symbol): Ident = Ident(sym.name) setSymbol sym diff --git a/src/scalap/scala/tools/scalap/JavaWriter.scala b/src/scalap/scala/tools/scalap/JavaWriter.scala index db9d6c5ed9..02b940ab16 100644 --- a/src/scalap/scala/tools/scalap/JavaWriter.scala +++ b/src/scalap/scala/tools/scalap/JavaWriter.scala @@ -9,7 +9,7 @@ package scala.tools.scalap import java.io._ - +import scala.reflect.NameTransformer class JavaWriter(classfile: Classfile, writer: Writer) extends CodeWriter(writer) { @@ -32,22 +32,22 @@ class JavaWriter(classfile: Classfile, writer: Writer) extends CodeWriter(writer } def nameToClass(str: String): String = { - val res = Names.decode(str.replace('/', '.')) + val res = NameTransformer.decode(str.replace('/', '.')) if (res == "java.lang.Object") "scala.Any" else res } def nameToClass0(str: String) = { - val res = Names.decode(str.replace('/', '.')) + val res = NameTransformer.decode(str.replace('/', '.')) if (res == "java.lang.Object") "scala.AnyRef" else res } def nameToSimpleClass(str: String) = - Names.decode(str.substring(str.lastIndexOf('/') + 1)) + NameTransformer.decode(str.substring(str.lastIndexOf('/') + 1)) def nameToPackage(str: String) = { val inx = str.lastIndexOf('/') val name = if (inx == -1) str else str.substring(0, inx).replace('/', '.') - Names.decode(name) + NameTransformer.decode(name) } def sigToType(str: String): String = @@ -119,9 +119,9 @@ class JavaWriter(classfile: Classfile, writer: Writer) extends CodeWriter(writer def printField(flags: Int, name: Int, tpe: Int, attribs: List[cf.Attribute]) { print(flagsToStr(false, flags)) if ((flags & 0x0010) != 0) - print("val " + Names.decode(getName(name))) + print("val " + NameTransformer.decode(getName(name))) else - print("final var " + Names.decode(getName(name))) + print("final var " + NameTransformer.decode(getName(name))) print(": " + getType(tpe) + ";").newline } @@ -139,20 +139,20 @@ class JavaWriter(classfile: Classfile, writer: Writer) extends CodeWriter(writer if (getName(name) == "") { print("def this" + getType(tpe) + ";").newline } else { - print("def " + Names.decode(getName(name))) + print("def " + NameTransformer.decode(getName(name))) print(getType(tpe) + ";").newline } case Some(str) => if (getName(name) == "") print("def this" + str + ";").newline else - print("def " + Names.decode(getName(name)) + str + ";").newline + print("def " + NameTransformer.decode(getName(name)) + str + ";").newline } case None => if (getName(name) == "") { print("def this" + getType(tpe) + ";").newline } else { - print("def " + Names.decode(getName(name))) + print("def " + NameTransformer.decode(getName(name))) print(getType(tpe) + ";").newline } } diff --git a/src/scalap/scala/tools/scalap/Main.scala b/src/scalap/scala/tools/scalap/Main.scala index 7254b00480..a8a9c65f63 100644 --- a/src/scalap/scala/tools/scalap/Main.scala +++ b/src/scalap/scala/tools/scalap/Main.scala @@ -8,6 +8,7 @@ package scala.tools.scalap import java.io.{ PrintStream, OutputStreamWriter, ByteArrayOutputStream } +import scala.reflect.NameTransformer import scalax.rules.scalasig._ import tools.nsc.util.{ ClassPath, JavaClassPath } import tools.util.PathResolver @@ -96,7 +97,7 @@ class Main { */ def process(args: Arguments, path: ClassPath[AbstractFile])(classname: String): Unit = { // find the classfile - val encName = Names.encode( + val encName = NameTransformer.encode( if (classname == "scala.AnyRef") "java.lang.Object" else classname) val cls = path.findClass(encName) diff --git a/src/scalap/scala/tools/scalap/Names.scala b/src/scalap/scala/tools/scalap/Names.scala deleted file mode 100644 index 1d66b31ce3..0000000000 --- a/src/scalap/scala/tools/scalap/Names.scala +++ /dev/null @@ -1,96 +0,0 @@ -/* ___ ____ ___ __ ___ ___ -** / _// __// _ | / / / _ | / _ \ Scala classfile decoder -** __\ \/ /__/ __ |/ /__/ __ |/ ___/ (c) 2003-2011, LAMP/EPFL -** /____/\___/_/ |_/____/_/ |_/_/ http://scala-lang.org/ -** -*/ - - -package scala.tools.scalap - - -object Names { - - val operatorName = new Array[String](128) - operatorName('$') = "$" - operatorName('~') = "$tilde" - operatorName('=') = "$eq" - operatorName('<') = "$less" - operatorName('>') = "$greater" - operatorName('!') = "$bang" - operatorName('#') = "$hash" - operatorName('%') = "$percent" - operatorName('^') = "$up" - operatorName('&') = "$amp" - operatorName('|') = "$bar" - operatorName('*') = "$times" - operatorName('/') = "$div" - operatorName('\\') = "$bslash" - operatorName('+') = "$plus" - operatorName('-') = "$minus" - operatorName(':') = "$colon" - - /** Replace operator symbols by corresponding "$op_name" in names. - */ - def encode(name: String): String = { - var i = 0 - val len = name.length() - val res = new StringBuffer() - while (i < len) { - val c = name.charAt(i) - if (c < 128) { - val nop = operatorName(c) - if (nop == null) - res.append(c) - else - res.append(nop) - } else - res.append(c) - i = i + 1 - } - res.toString() - } - - /** Replace "$op_name" by corresponding operator symbols in names. - */ - def decode(name: String): String = { - var i = 0 - val len = name.length() - val res = new StringBuffer() - while (i < len) { - val c = name.charAt(i) - if (c == '$') { - var j = len - while (j > i) { - val prefix = name.substring(i, j) - val c = lookup(prefix) - if (c != null) { - i = j - res.append(c) - } else - j = j - 1 - } - } else { - i = i + 1 - res.append(c) - } - } - res.toString() - } - - /** Looks up the array entry for the operator name. - */ - def lookup(string: String): String = { - var i = 0 - var res: String = null - while (i < 128) { - if (string.equals(operatorName(i))) { - res = String.valueOf(i.asInstanceOf[Char]) - i = 128 - } - i = i + 1 - } - res - } - -} diff --git a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala index df78bad25e..aa454934c1 100644 --- a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala @@ -13,9 +13,8 @@ package scalasig import java.io.{PrintStream, ByteArrayOutputStream} import java.util.regex.Pattern - import scala.tools.scalap.scalax.util.StringUtil -import reflect.NameTransformer +import scala.reflect.NameTransformer import java.lang.String class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) { -- cgit v1.2.3 From 2e92de4cd66532404081eec6b9e82c6f85b51434 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Thu, 5 Jan 2012 22:00:47 -0800 Subject: Init order issue in Manifest toStrings. Making -Xcheckinit happy. Then cleaned up the anyval and phantom type manifests once in the neighborhood. --- src/library/scala/reflect/Manifest.scala | 65 +++++++++++--------------------- 1 file changed, 22 insertions(+), 43 deletions(-) (limited to 'src/library') diff --git a/src/library/scala/reflect/Manifest.scala b/src/library/scala/reflect/Manifest.scala index 4b402f69b1..18fd34ed2e 100644 --- a/src/library/scala/reflect/Manifest.scala +++ b/src/library/scala/reflect/Manifest.scala @@ -60,7 +60,7 @@ trait Manifest[T] extends ClassManifest[T] with Equals { override def hashCode = this.erasure.## } -trait AnyValManifest[T] extends Manifest[T] with Equals { +sealed abstract class AnyValManifest[T <: AnyVal](override val toString: String) extends Manifest[T] with Equals { override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Manifest.Any) || (that eq Manifest.AnyVal) override def canEqual(other: Any) = other match { @@ -68,7 +68,7 @@ trait AnyValManifest[T] extends Manifest[T] with Equals { case _ => false } override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] - override def hashCode = System.identityHashCode(this) + override val hashCode = System.identityHashCode(this) } /** The object `Manifest` defines factory methods for manifests. @@ -76,130 +76,104 @@ trait AnyValManifest[T] extends Manifest[T] with Equals { * in client code. */ object Manifest { - private def ObjectClass = classOf[java.lang.Object] - - def valueManifests: List[AnyValManifest[_ <: scala.AnyVal]] = + def valueManifests: List[AnyValManifest[_]] = List(Byte, Short, Char, Int, Long, Float, Double, Boolean, Unit) - val Byte: AnyValManifest[Byte] = new AnyValManifest[scala.Byte] { + val Byte: AnyValManifest[Byte] = new AnyValManifest[scala.Byte]("Byte") { def erasure = java.lang.Byte.TYPE - final override val toString = "Byte" override def newArray(len: Int): Array[Byte] = new Array[Byte](len) override def newWrappedArray(len: Int): WrappedArray[Byte] = new WrappedArray.ofByte(new Array[Byte](len)) override def newArrayBuilder(): ArrayBuilder[Byte] = new ArrayBuilder.ofByte() private def readResolve(): Any = Manifest.Byte } - val Short: AnyValManifest[Short] = new AnyValManifest[scala.Short] { + val Short: AnyValManifest[Short] = new AnyValManifest[scala.Short]("Short") { def erasure = java.lang.Short.TYPE - final override val toString = "Short" override def newArray(len: Int): Array[Short] = new Array[Short](len) override def newWrappedArray(len: Int): WrappedArray[Short] = new WrappedArray.ofShort(new Array[Short](len)) override def newArrayBuilder(): ArrayBuilder[Short] = new ArrayBuilder.ofShort() private def readResolve(): Any = Manifest.Short } - val Char: AnyValManifest[Char] = new AnyValManifest[scala.Char] { + val Char: AnyValManifest[Char] = new AnyValManifest[scala.Char]("Char") { def erasure = java.lang.Character.TYPE - final override val toString = "Char" override def newArray(len: Int): Array[Char] = new Array[Char](len) override def newWrappedArray(len: Int): WrappedArray[Char] = new WrappedArray.ofChar(new Array[Char](len)) override def newArrayBuilder(): ArrayBuilder[Char] = new ArrayBuilder.ofChar() private def readResolve(): Any = Manifest.Char } - val Int: AnyValManifest[Int] = new AnyValManifest[scala.Int] { + val Int: AnyValManifest[Int] = new AnyValManifest[scala.Int]("Int") { def erasure = java.lang.Integer.TYPE - final override val toString = "Int" override def newArray(len: Int): Array[Int] = new Array[Int](len) override def newWrappedArray(len: Int): WrappedArray[Int] = new WrappedArray.ofInt(new Array[Int](len)) override def newArrayBuilder(): ArrayBuilder[Int] = new ArrayBuilder.ofInt() private def readResolve(): Any = Manifest.Int } - val Long: AnyValManifest[Long] = new AnyValManifest[scala.Long] { + val Long: AnyValManifest[Long] = new AnyValManifest[scala.Long]("Long") { def erasure = java.lang.Long.TYPE - final override val toString = "Long" override def newArray(len: Int): Array[Long] = new Array[Long](len) override def newWrappedArray(len: Int): WrappedArray[Long] = new WrappedArray.ofLong(new Array[Long](len)) override def newArrayBuilder(): ArrayBuilder[Long] = new ArrayBuilder.ofLong() private def readResolve(): Any = Manifest.Long } - val Float: AnyValManifest[Float] = new AnyValManifest[scala.Float] { + val Float: AnyValManifest[Float] = new AnyValManifest[scala.Float]("Float") { def erasure = java.lang.Float.TYPE - final override val toString = "Float" override def newArray(len: Int): Array[Float] = new Array[Float](len) override def newWrappedArray(len: Int): WrappedArray[Float] = new WrappedArray.ofFloat(new Array[Float](len)) override def newArrayBuilder(): ArrayBuilder[Float] = new ArrayBuilder.ofFloat() private def readResolve(): Any = Manifest.Float } - val Double: AnyValManifest[Double] = new AnyValManifest[scala.Double] { + val Double: AnyValManifest[Double] = new AnyValManifest[scala.Double]("Double") { def erasure = java.lang.Double.TYPE - final override val toString = "Double" override def newArray(len: Int): Array[Double] = new Array[Double](len) override def newWrappedArray(len: Int): WrappedArray[Double] = new WrappedArray.ofDouble(new Array[Double](len)) override def newArrayBuilder(): ArrayBuilder[Double] = new ArrayBuilder.ofDouble() private def readResolve(): Any = Manifest.Double } - val Boolean: AnyValManifest[Boolean] = new AnyValManifest[scala.Boolean] { + val Boolean: AnyValManifest[Boolean] = new AnyValManifest[scala.Boolean]("Boolean") { def erasure = java.lang.Boolean.TYPE - final override val toString = "Boolean" override def newArray(len: Int): Array[Boolean] = new Array[Boolean](len) override def newWrappedArray(len: Int): WrappedArray[Boolean] = new WrappedArray.ofBoolean(new Array[Boolean](len)) override def newArrayBuilder(): ArrayBuilder[Boolean] = new ArrayBuilder.ofBoolean() private def readResolve(): Any = Manifest.Boolean } - val Unit: AnyValManifest[Unit] = new AnyValManifest[scala.Unit] { + val Unit: AnyValManifest[Unit] = new AnyValManifest[scala.Unit]("Unit") { def erasure = java.lang.Void.TYPE - final override val toString = "Unit" override def newArray(len: Int): Array[Unit] = new Array[Unit](len) override def newWrappedArray(len: Int): WrappedArray[Unit] = new WrappedArray.ofUnit(new Array[Unit](len)) override def newArrayBuilder(): ArrayBuilder[Unit] = new ArrayBuilder.ofUnit() private def readResolve(): Any = Manifest.Unit } - val Any: Manifest[Any] = new ClassTypeManifest[scala.Any](None, ObjectClass, Nil) { - final override val toString = "Any" + val Any: Manifest[scala.Any] = new PhantomManifest[scala.Any]("Any") { override def <:<(that: ClassManifest[_]): Boolean = (that eq this) - override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] - override def hashCode = System.identityHashCode(this) private def readResolve(): Any = Manifest.Any } - val Object: Manifest[Object] = new ClassTypeManifest[java.lang.Object](None, ObjectClass, Nil) { - final override val toString = "Object" + val Object: Manifest[java.lang.Object] = new PhantomManifest[java.lang.Object]("Object") { override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Any) - override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] - override def hashCode = System.identityHashCode(this) private def readResolve(): Any = Manifest.Object } - val AnyVal: Manifest[AnyVal] = new ClassTypeManifest[scala.AnyVal](None, ObjectClass, Nil) { - final override val toString = "AnyVal" + val AnyVal: Manifest[scala.AnyVal] = new PhantomManifest[scala.AnyVal]("AnyVal") { override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Any) - override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] - override def hashCode = System.identityHashCode(this) private def readResolve(): Any = Manifest.AnyVal } - val Null: Manifest[Null] = new ClassTypeManifest[scala.Null](None, ObjectClass, Nil) { - final override val toString = "Null" + val Null: Manifest[scala.Null] = new PhantomManifest[scala.Null]("Null") { override def <:<(that: ClassManifest[_]): Boolean = (that ne null) && (that ne Nothing) && !(that <:< AnyVal) - override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] - override def hashCode = System.identityHashCode(this) private def readResolve(): Any = Manifest.Null } - val Nothing: Manifest[Nothing] = new ClassTypeManifest[scala.Nothing](None, ObjectClass, Nil) { - final override val toString = "Nothing" + val Nothing: Manifest[scala.Nothing] = new PhantomManifest[scala.Nothing]("Nothing") { override def <:<(that: ClassManifest[_]): Boolean = (that ne null) - override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] - override def hashCode = System.identityHashCode(this) private def readResolve(): Any = Manifest.Nothing } @@ -234,6 +208,11 @@ object Manifest { def classType[T](prefix: Manifest[_], clazz: Predef.Class[_], args: Manifest[_]*): Manifest[T] = new ClassTypeManifest[T](Some(prefix), clazz, args.toList) + private abstract class PhantomManifest[T](override val toString: String) extends ClassTypeManifest[T](None, classOf[java.lang.Object], Nil) { + override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] + override val hashCode = System.identityHashCode(this) + } + /** Manifest for the class type `clazz[args]`, where `clazz` is * a top-level or static class. */ private class ClassTypeManifest[T](prefix: Option[Manifest[_]], -- cgit v1.2.3 From 4787f883604d1344257c0b40c15790c3dde477f2 Mon Sep 17 00:00:00 2001 From: Szabolcs Berecz Date: Sat, 7 Jan 2012 17:40:00 +0100 Subject: Fixed equality and string representation of xml attributes with null value Prior to this patch was not equal to and it's string representation was "" instead of "" This includes changing MetaData.normalize() so that it doesn't reverse the chain. On the downside, the iterate function in MetaData.normalize() is not tail-recursive now. --- src/library/scala/xml/Elem.scala | 4 +++- src/library/scala/xml/MetaData.scala | 4 ++-- src/library/scala/xml/UnprefixedAttribute.scala | 2 +- src/library/scala/xml/Utility.scala | 2 +- test/files/jvm/xml03syntax.check | 2 +- test/files/run/xml-attribute.scala | 14 ++++++++++++++ 6 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 test/files/run/xml-attribute.scala (limited to 'src/library') diff --git a/src/library/scala/xml/Elem.scala b/src/library/scala/xml/Elem.scala index 127e6e0ab7..df52b34f87 100644 --- a/src/library/scala/xml/Elem.scala +++ b/src/library/scala/xml/Elem.scala @@ -41,7 +41,7 @@ object Elem { class Elem( override val prefix: String, val label: String, - override val attributes: MetaData, + attributes1: MetaData, override val scope: NamespaceBinding, val child: Node*) extends Node with Serializable @@ -49,6 +49,8 @@ extends Node with Serializable final override def doCollectNamespaces = true final override def doTransform = true + override val attributes = MetaData.normalize(attributes1, scope) + if (prefix == "") throw new IllegalArgumentException("prefix of zero length, use null instead") diff --git a/src/library/scala/xml/MetaData.scala b/src/library/scala/xml/MetaData.scala index 98e863eb37..c516747bae 100644 --- a/src/library/scala/xml/MetaData.scala +++ b/src/library/scala/xml/MetaData.scala @@ -38,8 +38,8 @@ object MetaData { def iterate(md: MetaData, normalized_attribs: MetaData, set: Set[String]): MetaData = { lazy val key = getUniversalKey(md, scope) if (md eq Null) normalized_attribs - else if (set(key)) iterate(md.next, normalized_attribs, set) - else iterate(md.next, md copy normalized_attribs, set + key) + else if ((md.value eq null) || set(key)) iterate(md.next, normalized_attribs, set) + else md copy iterate(md.next, normalized_attribs, set + key) } iterate(attribs, Null, Set()) } diff --git a/src/library/scala/xml/UnprefixedAttribute.scala b/src/library/scala/xml/UnprefixedAttribute.scala index c56fba1e6c..b6800d5ed1 100644 --- a/src/library/scala/xml/UnprefixedAttribute.scala +++ b/src/library/scala/xml/UnprefixedAttribute.scala @@ -22,7 +22,7 @@ extends Attribute final val pre = null val next = if (value ne null) next1 else next1.remove(key) - /** same as this(key, Text(value), next) */ + /** same as this(key, Text(value), next), or no attribute if value is null */ def this(key: String, value: String, next: MetaData) = this(key, if (value ne null) Text(value) else null: NodeSeq, next) diff --git a/src/library/scala/xml/Utility.scala b/src/library/scala/xml/Utility.scala index 9b48f4e1bb..fc20b892b9 100644 --- a/src/library/scala/xml/Utility.scala +++ b/src/library/scala/xml/Utility.scala @@ -61,7 +61,7 @@ object Utility extends AnyRef with parsing.TokenTests { val key = md.key val smaller = sort(md.filter { m => m.key < key }) val greater = sort(md.filter { m => m.key > key }) - smaller.append( Null ).append(md.copy ( greater )) + smaller.copy(md.copy ( greater )) } /** Return the node with its attribute list sorted alphabetically diff --git a/test/files/jvm/xml03syntax.check b/test/files/jvm/xml03syntax.check index 75dc539137..9fbedc2ae6 100644 --- a/test/files/jvm/xml03syntax.check +++ b/test/files/jvm/xml03syntax.check @@ -23,4 +23,4 @@ true 4 node=, key=Some(hello) -node=, key=None +node=, key=None diff --git a/test/files/run/xml-attribute.scala b/test/files/run/xml-attribute.scala new file mode 100644 index 0000000000..2b83f70b22 --- /dev/null +++ b/test/files/run/xml-attribute.scala @@ -0,0 +1,14 @@ +import xml.Node + +object Test { + def main(args: Array[String]): Unit = { + val noAttr = + val attrNull = + val attrNone = + assert(noAttr == attrNull) + assert(noAttr == attrNone) + assert(noAttr.toString() == "") + assert(attrNull.toString() == "") + assert(attrNone.toString() == "") + } +} -- cgit v1.2.3 From 51089b34a7a535498dee42e6465d4d577d65b7d5 Mon Sep 17 00:00:00 2001 From: Szabolcs Berecz Date: Sat, 7 Jan 2012 18:23:21 +0100 Subject: Accept prefixed xml attributes with null value This changes makes PrefixedAttribute work the same way as UnprefixedAttribute with respect to null values: is accepted and results in --- src/library/scala/xml/PrefixedAttribute.scala | 15 +++++++++------ test/files/run/xml-attribute.scala | 25 ++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 9 deletions(-) (limited to 'src/library') diff --git a/src/library/scala/xml/PrefixedAttribute.scala b/src/library/scala/xml/PrefixedAttribute.scala index 436dfcda43..b80d6a1c73 100644 --- a/src/library/scala/xml/PrefixedAttribute.scala +++ b/src/library/scala/xml/PrefixedAttribute.scala @@ -13,22 +13,25 @@ package scala.xml * * @param pre ... * @param key ... - * @param value the attribute value, which may not be null + * @param value the attribute value * @param next ... */ class PrefixedAttribute( val pre: String, val key: String, val value: Seq[Node], - val next: MetaData) + val next1: MetaData) extends Attribute { - if (value eq null) - throw new UnsupportedOperationException("value is null") + val next = if (value ne null) next1 else next1.remove(key) - /** same as this(key, Utility.parseAttributeValue(value), next) */ + /** same as this(pre, key, Text(value), next), or no attribute if value is null */ def this(pre: String, key: String, value: String, next: MetaData) = - this(pre, key, Text(value), next) + this(pre, key, if (value ne null) Text(value) else null: NodeSeq, next) + + /** same as this(pre, key, value.get, next), or no attribute if value is None */ + def this(pre: String, key: String, value: Option[Seq[Node]], next: MetaData) = + this(pre, key, value.orNull, next) /** Returns a copy of this unprefixed attribute with the given * next field. diff --git a/test/files/run/xml-attribute.scala b/test/files/run/xml-attribute.scala index 2b83f70b22..8b261acc94 100644 --- a/test/files/run/xml-attribute.scala +++ b/test/files/run/xml-attribute.scala @@ -5,10 +5,29 @@ object Test { val noAttr = val attrNull = val attrNone = + val preAttrNull = + val preAttrNone = assert(noAttr == attrNull) assert(noAttr == attrNone) - assert(noAttr.toString() == "") - assert(attrNull.toString() == "") - assert(attrNone.toString() == "") + assert(noAttr == preAttrNull) + assert(noAttr == preAttrNone) + + val noAttrStr = "" + assert(noAttr.toString() == noAttrStr) + assert(attrNull.toString() == noAttrStr) + assert(attrNone.toString() == noAttrStr) + assert(preAttrNull.toString() == noAttrStr) + assert(preAttrNone.toString() == noAttrStr) + + val xml1 = + val xml2 = + val xml3 = + assert(xml1 == xml2) + assert(xml1 == xml3) + + val xml1Str = "" + assert(xml1.toString() == xml1Str) + assert(xml2.toString() == xml1Str) + assert(xml3.toString() == xml1Str) } } -- cgit v1.2.3 From 27d19715af59e2e438808ae668c093ad61c8f728 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 7 Jan 2012 13:31:11 -0800 Subject: Made Array manifests return type arguments. Closes SI-3758. --- src/library/scala/reflect/ClassManifest.scala | 4 ++-- src/library/scala/reflect/Manifest.scala | 2 +- test/files/run/t3758.scala | 10 ++++++++++ 3 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 test/files/run/t3758.scala (limited to 'src/library') diff --git a/src/library/scala/reflect/ClassManifest.scala b/src/library/scala/reflect/ClassManifest.scala index acd28f04f5..466b57dea7 100644 --- a/src/library/scala/reflect/ClassManifest.scala +++ b/src/library/scala/reflect/ClassManifest.scala @@ -127,7 +127,7 @@ trait ClassManifest[T] extends OptManifest[T] with Equals with Serializable { java.lang.reflect.Array.newInstance(tp, 0).getClass.asInstanceOf[jClass[Array[T]]] def arrayManifest: ClassManifest[Array[T]] = - ClassManifest.classType[Array[T]](arrayClass[T](erasure)) + ClassManifest.classType[Array[T]](arrayClass[T](erasure), this) def newArray(len: Int): Array[T] = java.lang.reflect.Array.newInstance(erasure, len).asInstanceOf[Array[T]] @@ -220,7 +220,7 @@ object ClassManifest { new ClassTypeManifest[T](Some(prefix), clazz, args.toList) def arrayType[T](arg: OptManifest[_]): ClassManifest[Array[T]] = arg match { - case NoManifest => Object.asInstanceOf[ClassManifest[Array[T]]] + case NoManifest => Object.asInstanceOf[ClassManifest[Array[T]]] case m: ClassManifest[_] => m.asInstanceOf[ClassManifest[T]].arrayManifest } diff --git a/src/library/scala/reflect/Manifest.scala b/src/library/scala/reflect/Manifest.scala index 18fd34ed2e..be08409636 100644 --- a/src/library/scala/reflect/Manifest.scala +++ b/src/library/scala/reflect/Manifest.scala @@ -44,7 +44,7 @@ trait Manifest[T] extends ClassManifest[T] with Equals { override def typeArguments: List[Manifest[_]] = Nil override def arrayManifest: Manifest[Array[T]] = - Manifest.classType[Array[T]](arrayClass[T](erasure)) + Manifest.classType[Array[T]](arrayClass[T](erasure), this) override def canEqual(that: Any): Boolean = that match { case _: Manifest[_] => true diff --git a/test/files/run/t3758.scala b/test/files/run/t3758.scala new file mode 100644 index 0000000000..18750b0a9c --- /dev/null +++ b/test/files/run/t3758.scala @@ -0,0 +1,10 @@ +object Test { + def main(args: Array[String]): Unit = { + assert(classManifest[Array[String]].typeArguments contains classManifest[String]) + assert(classManifest[Array[Int]].typeArguments contains classManifest[Int]) + assert(classManifest[Array[Float]].typeArguments contains classManifest[Float]) + assert(manifest[Array[String]].typeArguments contains manifest[String]) + assert(manifest[Array[Int]].typeArguments contains manifest[Int]) + assert(manifest[Array[Float]].typeArguments contains manifest[Float]) + } +} -- cgit v1.2.3 From 04af2eb976bf5b3aec9577837ca03db327d09825 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 7 Jan 2012 15:00:26 -0800 Subject: Cleanups in Cleanup. Seeing about getting delayedInit working (not to mention the breakage it is inflicting elsewhere) which led me into Cleanup and some of its buddies. --- .../scala/reflect/internal/Definitions.scala | 7 +- src/compiler/scala/reflect/internal/StdNames.scala | 18 +++ src/compiler/scala/reflect/internal/Trees.scala | 11 +- .../scala/tools/nsc/transform/CleanUp.scala | 147 ++++++++++----------- src/library/scala/Symbol.scala | 4 +- src/library/scala/runtime/BoxesRunTime.java | 18 +++ 6 files changed, 120 insertions(+), 85 deletions(-) (limited to 'src/library') diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index aee3938715..d3af8e2623 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -267,10 +267,11 @@ trait Definitions extends reflect.api.StandardDefinitions { (sym.name == name) && (sym.owner == PredefModule.moduleClass) ) - lazy val ConsoleModule: Symbol = getRequiredModule("scala.Console") + lazy val ConsoleModule: Symbol = getRequiredModule("scala.Console") lazy val ScalaRunTimeModule: Symbol = getRequiredModule("scala.runtime.ScalaRunTime") - lazy val SymbolModule: Symbol = getRequiredModule("scala.Symbol") - lazy val Symbol_apply = getMember(SymbolModule, nme.apply) + lazy val SymbolModule: Symbol = getRequiredModule("scala.Symbol") + lazy val Symbol_apply = SymbolModule.info decl nme.apply + def SeqFactory = getMember(ScalaRunTimeModule, nme.Seq) def arrayApplyMethod = getMember(ScalaRunTimeModule, nme.array_apply) def arrayUpdateMethod = getMember(ScalaRunTimeModule, nme.array_update) diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala index db1cf7f257..ea5565c581 100644 --- a/src/compiler/scala/reflect/internal/StdNames.scala +++ b/src/compiler/scala/reflect/internal/StdNames.scala @@ -578,6 +578,9 @@ trait StdNames extends NameManglers { self: SymbolTable => val testLessOrEqualThan: NameType = "testLessOrEqualThan" val testLessThan: NameType = "testLessThan" val testNotEqual: NameType = "testNotEqual" + + val isBoxedNumberOrBoolean: NameType = "isBoxedNumberOrBoolean" + val isBoxedNumber: NameType = "isBoxedNumber" def toUnaryName(name: TermName): TermName = name match { case raw.MINUS => UNARY_- @@ -628,6 +631,21 @@ trait StdNames extends NameManglers { self: SymbolTable => case _ => NO_NAME } + val reflPolyCacheName: NameType = "reflPoly$Cache" + val reflClassCacheName: NameType = "reflClass$Cache" + val reflParamsCacheName: NameType = "reflParams$Cache" + val reflMethodCacheName: NameType = "reflMethod$Cache" + val reflMethodName: NameType = "reflMethod$Method" + + private val reflectionCacheNames = Set[NameType]( + reflPolyCacheName, + reflClassCacheName, + reflParamsCacheName, + reflMethodCacheName, + reflMethodName + ) + def isReflectionCacheName(name: Name) = reflectionCacheNames exists (name startsWith _) + @switch def productAccessorName(j: Int): TermName = j match { case 1 => nme._1 case 2 => nme._2 diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala index 4ca55f53ea..96f2c5cc45 100644 --- a/src/compiler/scala/reflect/internal/Trees.scala +++ b/src/compiler/scala/reflect/internal/Trees.scala @@ -248,10 +248,13 @@ trait Trees extends api.Trees { self: SymbolTable => /** Block factory that flattens directly nested blocks. */ - def Block(stats: Tree*): Block = stats match { - case Seq(b @ Block(_, _)) => b - case Seq(stat) => Block(stats.toList, Literal(Constant(()))) - case Seq(_, rest @ _*) => Block(stats.init.toList, stats.last) + def Block(stats: Tree*): Block = { + if (stats.isEmpty) Block(Nil, Literal(Constant(()))) + else stats match { + case Seq(b @ Block(_, _)) => b + case Seq(stat) => Block(stats.toList, Literal(Constant(()))) + case Seq(_, rest @ _*) => Block(stats.init.toList, stats.last) + } } // --- specific traversers and transformers diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index 575e3a9141..034628e95f 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -22,9 +22,35 @@ abstract class CleanUp extends Transform with ast.TreeDSL { new CleanUpTransformer(unit) class CleanUpTransformer(unit: CompilationUnit) extends Transformer { - private val newStaticMembers = mutable.Buffer.empty[Tree] - private val newStaticInits = mutable.Buffer.empty[Tree] + private val newStaticMembers = mutable.Buffer.empty[Tree] + private val newStaticInits = mutable.Buffer.empty[Tree] private val symbolsStoredAsStatic = mutable.Map.empty[String, Symbol] + private def clearStatics() { + newStaticMembers.clear() + newStaticInits.clear() + symbolsStoredAsStatic.clear() + } + private def savingStatics[T](body: => T): T = { + val savedNewStaticMembers : mutable.Buffer[Tree] = newStaticMembers.clone() + val savedNewStaticInits : mutable.Buffer[Tree] = newStaticInits.clone() + val savedSymbolsStoredAsStatic : mutable.Map[String, Symbol] = symbolsStoredAsStatic.clone() + val result = body + + clearStatics() + newStaticMembers ++= savedNewStaticMembers + newStaticInits ++= savedNewStaticInits + symbolsStoredAsStatic ++= savedSymbolsStoredAsStatic + + result + } + private def transformTemplate(tree: Tree) = { + val Template(parents, self, body) = tree + clearStatics() + val newBody = transformTrees(body) + val templ = treeCopy.Template(tree, parents, self, transformTrees(newStaticMembers.toList) ::: newBody) + try addStaticInits(templ) // postprocess to include static ctors + finally clearStatics() + } private def mkTerm(prefix: String): TermName = unit.freshTermName(prefix) /** Kludge to provide a safe fix for #4560: @@ -60,7 +86,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { } private def typedWithPos(pos: Position)(tree: Tree) = - localTyper typed { atPos(pos)(tree) } + localTyper.typedPos(pos)(tree) /** A value class is defined to be only Java-compatible values: unit is * not part of it, as opposed to isValueClass in definitions. scala.Int is @@ -71,7 +97,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { /** The boxed type if it's a primitive; identity otherwise. */ def toBoxedType(tp: Type) = if (isJavaValueType(tp)) boxedClass(tp.typeSymbol).tpe else tp - + override def transform(tree: Tree): Tree = tree match { /* Transforms dynamic calls (i.e. calls to methods that are undefined @@ -116,11 +142,11 @@ abstract class CleanUp extends Transform with ast.TreeDSL { /* ### CREATING THE METHOD CACHE ### */ - def addStaticVariableToClass(forName: String, forType: Type, forInit: Tree, isFinal: Boolean): Symbol = { + def addStaticVariableToClass(forName: TermName, forType: Type, forInit: Tree, isFinal: Boolean): Symbol = { val varSym = ( - currentClass.newVariable(ad.pos, mkTerm(forName)) - setFlag (PRIVATE | STATIC | SYNTHETIC) - setInfo (forType) + currentClass.newVariable(ad.pos, mkTerm("" + forName)) + setFlag PRIVATE | STATIC | SYNTHETIC + setInfo forType ) if (isFinal) varSym setFlag FINAL else varSym.addAnnotation(VolatileAttr) @@ -168,9 +194,9 @@ abstract class CleanUp extends Transform with ast.TreeDSL { */ val reflParamsCacheSym: Symbol = - addStaticVariableToClass("reflParams$Cache", theTypeClassArray, fromTypesToClassArrayLiteral(paramTypes), true) + addStaticVariableToClass(nme.reflParamsCacheName, theTypeClassArray, fromTypesToClassArrayLiteral(paramTypes), true) - addStaticMethodToClass("reflMethod$Method", List(ClassClass.tpe), MethodClass.tpe) { + addStaticMethodToClass(nme.reflMethodName, List(ClassClass.tpe), MethodClass.tpe) { case Pair(reflMethodSym, List(forReceiverSym)) => (REF(forReceiverSym) DOT Class_getMethod)(LIT(method), safeREF(reflParamsCacheSym)) } @@ -197,18 +223,18 @@ abstract class CleanUp extends Transform with ast.TreeDSL { */ val reflParamsCacheSym: Symbol = - addStaticVariableToClass("reflParams$Cache", theTypeClassArray, fromTypesToClassArrayLiteral(paramTypes), true) + addStaticVariableToClass(nme.reflParamsCacheName, theTypeClassArray, fromTypesToClassArrayLiteral(paramTypes), true) val reflMethodCacheSym: Symbol = - addStaticVariableToClass("reflMethod$Cache", MethodClass.tpe, NULL, false) + addStaticVariableToClass(nme.reflMethodCacheName, MethodClass.tpe, NULL, false) val reflClassCacheSym: Symbol = - addStaticVariableToClass("reflClass$Cache", SoftReferenceClass.tpe, NULL, false) + addStaticVariableToClass(nme.reflClassCacheName, SoftReferenceClass.tpe, NULL, false) def isCacheEmpty(receiver: Symbol): Tree = reflClassCacheSym.IS_NULL() OR (reflClassCacheSym.GET() OBJ_NE REF(receiver)) - addStaticMethodToClass("reflMethod$Method", List(ClassClass.tpe), MethodClass.tpe) { + addStaticMethodToClass(nme.reflMethodName, List(ClassClass.tpe), MethodClass.tpe) { case Pair(reflMethodSym, List(forReceiverSym)) => BLOCK( IF (isCacheEmpty(forReceiverSym)) THEN BLOCK( @@ -244,13 +270,15 @@ abstract class CleanUp extends Transform with ast.TreeDSL { */ val reflParamsCacheSym: Symbol = - addStaticVariableToClass("reflParams$Cache", theTypeClassArray, fromTypesToClassArrayLiteral(paramTypes), true) + addStaticVariableToClass(nme.reflParamsCacheName, theTypeClassArray, fromTypesToClassArrayLiteral(paramTypes), true) def mkNewPolyCache = gen.mkSoftRef(NEW(TypeTree(EmptyMethodCacheClass.tpe))) - val reflPolyCacheSym: Symbol = addStaticVariableToClass("reflPoly$Cache", SoftReferenceClass.tpe, mkNewPolyCache, false) + val reflPolyCacheSym: Symbol = ( + addStaticVariableToClass(nme.reflPolyCacheName, SoftReferenceClass.tpe, mkNewPolyCache, false) + ) def getPolyCache = gen.mkCast(fn(safeREF(reflPolyCacheSym), nme.get), MethodCacheClass.tpe) - addStaticMethodToClass("reflMethod$Method", List(ClassClass.tpe), MethodClass.tpe) + addStaticMethodToClass(nme.reflMethodName, List(ClassClass.tpe), MethodClass.tpe) { case Pair(reflMethodSym, List(forReceiverSym)) => val methodSym = reflMethodSym.newVariable(ad.pos, mkTerm("method")) setInfo MethodClass.tpe @@ -274,24 +302,13 @@ abstract class CleanUp extends Transform with ast.TreeDSL { /* ### HANDLING METHODS NORMALLY COMPILED TO OPERATORS ### */ - // Can't shortcut on BoxedNumber because BoxesRunTime - // is unforgiving of other Numbers showing up. - def testForNumber(qual1: Tree): Tree = ( - (qual1 IS_OBJ BoxedIntClass.tpe) - OR (qual1 IS_OBJ BoxedLongClass.tpe) - OR (qual1 IS_OBJ BoxedDoubleClass.tpe) - OR (qual1 IS_OBJ BoxedFloatClass.tpe) - OR (qual1 IS_OBJ BoxedByteClass.tpe) - OR (qual1 IS_OBJ BoxedShortClass.tpe) - OR (qual1 IS_OBJ BoxedCharacterClass.tpe) - ) - def testForBoolean(qual1: Tree): Tree = ( - (qual1 IS_OBJ BoxedBooleanClass.tpe) - ) - def testForName(name: Name): Tree => Tree = ( - if (nme.CommonOpNames(name)) t => testForNumber(t) OR testForBoolean(t) - else if (nme.BooleanOpNames(name)) testForBoolean - else testForNumber + def testForName(name: Name): Tree => Tree = t => ( + if (nme.CommonOpNames(name)) + gen.mkMethodCall(getMember(BoxesRunTimeClass, nme.isBoxedNumberOrBoolean), t :: Nil) + else if (nme.BooleanOpNames(name)) + t IS_OBJ BoxedBooleanClass.tpe + else + gen.mkMethodCall(getMember(BoxesRunTimeClass, nme.isBoxedNumber), t :: Nil) ) /** The Tree => Tree function in the return is necessary to prevent the original qual @@ -525,31 +542,8 @@ abstract class CleanUp extends Transform with ast.TreeDSL { * constructor. */ case Template(parents, self, body) => localTyper = typer.atOwner(tree, currentClass) - var savedNewStaticMembers : mutable.Buffer[Tree] = null - var savedNewStaticInits : mutable.Buffer[Tree] = null - var savedSymbolsStoredAsStatic : mutable.Map[String, Symbol] = null - if(forMSIL) { - savedNewStaticMembers = newStaticMembers.clone - savedNewStaticInits = newStaticInits.clone - savedSymbolsStoredAsStatic = symbolsStoredAsStatic.clone - } - newStaticMembers.clear - newStaticInits.clear - symbolsStoredAsStatic.clear - val transformedTemplate: Template = { - var newBody = transformTrees(body) - treeCopy.Template(tree, parents, self, transformTrees(newStaticMembers.toList) ::: newBody) - } - val res = addStaticInits(transformedTemplate) // postprocess to include static ctors - newStaticMembers.clear - newStaticInits.clear - symbolsStoredAsStatic.clear - if(forMSIL) { - newStaticMembers ++= savedNewStaticMembers - newStaticInits ++= savedNewStaticInits - symbolsStoredAsStatic ++= savedSymbolsStoredAsStatic - } - res + if (forMSIL) savingStatics( transformTemplate(tree) ) + else transformTemplate(tree) case Literal(c) if (c.tag == ClassTag) && !forMSIL=> val tpe = c.typeValue @@ -612,15 +606,12 @@ abstract class CleanUp extends Transform with ast.TreeDSL { * And, finally, be advised - scala symbol literal and the Symbol class of the compiler * have little in common. */ - case symapp @ Apply(Select(Select(a @ Ident(nme.scala_), b @ nme.Symbol), nme.apply), - List(Literal(Constant(symname: String)))) => + case Apply(fn, (arg @ Literal(Constant(symname: String))) :: Nil) if fn.symbol == Symbol_apply => // add the symbol name to a map if it's not there already - val rhs = gen.mkCast(Apply(gen.scalaDot(nme.Symbol), List(Literal(Constant(symname)))), symbolType) - val staticFieldSym = getSymbolStaticField(symapp.pos, symname, rhs, symapp) - + val rhs = gen.mkMethodCall(Symbol_apply, arg :: Nil) + val staticFieldSym = getSymbolStaticField(tree.pos, symname, rhs, tree) // create a reference to a static field - val ntree = typedWithPos(symapp.pos)(safeREF(staticFieldSym)) - + val ntree = typedWithPos(tree.pos)(safeREF(staticFieldSym)) super.transform(ntree) // This transform replaces Array(Predef.wrapArray(Array(...)), ) @@ -640,19 +631,21 @@ abstract class CleanUp extends Transform with ast.TreeDSL { * If it doesn't exist, i.e. the symbol is encountered the first time, * it creates a new static field definition and initialization and returns it. */ - private def getSymbolStaticField(pos: Position, symname: String, rhs: Tree, tree: Tree): Symbol = + private def getSymbolStaticField(pos: Position, symname: String, rhs: Tree, tree: Tree): Symbol = { symbolsStoredAsStatic.getOrElseUpdate(symname, { val theTyper = typer.atOwner(tree, currentClass) // create a symbol for the static field - val stfieldSym = currentClass.newVariable(pos, mkTerm("symbol$")) - .setFlag(PRIVATE | STATIC | SYNTHETIC | FINAL) - .setInfo(symbolType) + val stfieldSym = ( + currentClass.newVariable(pos, mkTerm("symbol$")) + setFlag PRIVATE | STATIC | SYNTHETIC | FINAL + setInfo SymbolClass.tpe + ) currentClass.info.decls enter stfieldSym // create field definition and initialization - val stfieldDef = theTyper.typed { atPos(pos)(VAL(stfieldSym) === rhs) } - val stfieldInit = theTyper.typed { atPos(pos)(safeREF(stfieldSym) === rhs) } + val stfieldDef = theTyper.typedPos(pos)(VAL(stfieldSym) === rhs) + val stfieldInit = theTyper.typedPos(pos)(safeREF(stfieldSym) === rhs) // add field definition to new defs newStaticMembers append stfieldDef @@ -660,6 +653,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { stfieldSym }) + } /* finds the static ctor DefDef tree within the template if it exists. */ private def findStaticCtor(template: Template): Option[Tree] = @@ -671,7 +665,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { /* changes the template for the class so that it contains a static constructor with symbol fields inits, * augments an existing static ctor if one already existed. */ - private def addStaticInits(template: Template): Template = + private def addStaticInits(template: Template): Template = { if (newStaticInits.isEmpty) template else { @@ -693,11 +687,12 @@ abstract class CleanUp extends Transform with ast.TreeDSL { // create new static ctor val staticCtorSym = currentClass.newStaticConstructor(template.pos) val rhs = Block(newStaticInits.toList, Literal(Constant())) - val staticCtorTree = DefDef(staticCtorSym, rhs) - localTyper.typed { atPos(template.pos)(staticCtorTree) } + + localTyper.typedPos(template.pos)(DefDef(staticCtorSym, rhs)) } treeCopy.Template(template, template.parents, template.self, newCtor :: template.body) } + } } // CleanUpTransformer diff --git a/src/library/scala/Symbol.scala b/src/library/scala/Symbol.scala index 8a17ae87b0..8851f1ab91 100644 --- a/src/library/scala/Symbol.scala +++ b/src/library/scala/Symbol.scala @@ -31,8 +31,8 @@ final class Symbol private (val name: String) extends Serializable { override def equals(other: Any) = this eq other.asInstanceOf[AnyRef] } -object Symbol extends UniquenessCache[String, Symbol] -{ +object Symbol extends UniquenessCache[String, Symbol] { + override def apply(name: String): Symbol = super.apply(name) protected def valueFromKey(name: String): Symbol = new Symbol(name) protected def keyFromValue(sym: Symbol): Option[String] = Some(sym.name) } diff --git a/src/library/scala/runtime/BoxesRunTime.java b/src/library/scala/runtime/BoxesRunTime.java index c726c56d0e..b19c8d086c 100644 --- a/src/library/scala/runtime/BoxesRunTime.java +++ b/src/library/scala/runtime/BoxesRunTime.java @@ -769,6 +769,24 @@ public final class BoxesRunTime } throw new NoSuchMethodException(); } + + public static boolean isBoxedNumberOrBoolean(Object arg) { + if (arg instanceof java.lang.Boolean) + return true; + else + return isBoxedNumber(arg); + } + public static boolean isBoxedNumber(Object arg) { + return ( + (arg instanceof java.lang.Integer) + || (arg instanceof java.lang.Long) + || (arg instanceof java.lang.Double) + || (arg instanceof java.lang.Float) + || (arg instanceof java.lang.Short) + || (arg instanceof java.lang.Character) + || (arg instanceof java.lang.Byte) + ); + } /** arg.toChar */ public static java.lang.Character toCharacter(Object arg) throws NoSuchMethodException { -- cgit v1.2.3 From af4a5299290090ff433f2ad7bb801bf4226f423f Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sun, 8 Jan 2012 19:36:33 -0800 Subject: Fix for PartialFunction NPE. Was going straight to the field and bypassing the null guard. Closes SI-5300. --- src/library/scala/runtime/AbstractPartialFunction.scala | 4 ++-- test/files/run/t5300.scala | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 test/files/run/t5300.scala (limited to 'src/library') diff --git a/src/library/scala/runtime/AbstractPartialFunction.scala b/src/library/scala/runtime/AbstractPartialFunction.scala index f48d99f5af..cbe778f09b 100644 --- a/src/library/scala/runtime/AbstractPartialFunction.scala +++ b/src/library/scala/runtime/AbstractPartialFunction.scala @@ -26,7 +26,7 @@ abstract class AbstractPartialFunction[-T1, +R] private var fallBackField: PartialFunction[T1 @uncheckedVariance, R @uncheckedVariance] = _ def fallBack: PartialFunction[T1, R] = synchronized { - if (fallBackField == null) fallBackField = PartialFunction.empty + if (fallBackField eq null) fallBackField = PartialFunction.empty fallBackField } @@ -38,7 +38,7 @@ abstract class AbstractPartialFunction[-T1, +R] override def orElse[A1 <: T1, B1 >: R](that: PartialFunction[A1, B1]) : PartialFunction[A1, B1] = { val result = this.clone.asInstanceOf[AbstractPartialFunction[A1, B1]] result.synchronized { - result.fallBackField = this.fallBackField orElse that + result.fallBackField = if (this.fallBackField eq null) that else this.fallBackField orElse that result } } diff --git a/test/files/run/t5300.scala b/test/files/run/t5300.scala new file mode 100644 index 0000000000..073b29604a --- /dev/null +++ b/test/files/run/t5300.scala @@ -0,0 +1,7 @@ +object Test { + val pf: PartialFunction[Any, Unit] = { case _ => () } + + def main(args: Array[String]): Unit = { + pf orElse pf + } +} -- cgit v1.2.3 From b7bd309f0982df73bd2ac41c6cd8d2e399ff3ee4 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 10 Jan 2012 14:39:38 +0100 Subject: Fixing redundant type parameter in toIndexedSeq which causes suboptimal type inference --- src/library/scala/collection/GenTraversableOnce.scala | 2 +- src/library/scala/collection/TraversableOnce.scala | 2 +- src/library/scala/collection/TraversableProxyLike.scala | 2 +- src/library/scala/collection/generic/TraversableForwarder.scala | 2 +- src/library/scala/collection/immutable/IndexedSeq.scala | 2 +- src/library/scala/collection/interfaces/TraversableOnceMethods.scala | 2 +- src/library/scala/collection/parallel/ParIterableLike.scala | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src/library') diff --git a/src/library/scala/collection/GenTraversableOnce.scala b/src/library/scala/collection/GenTraversableOnce.scala index 3e42e7812b..305f8d768d 100644 --- a/src/library/scala/collection/GenTraversableOnce.scala +++ b/src/library/scala/collection/GenTraversableOnce.scala @@ -471,7 +471,7 @@ trait GenTraversableOnce[+A] { * $willNotTerminateInf * @return an indexed sequence containing all elements of this $coll. */ - def toIndexedSeq[A1 >: A]: immutable.IndexedSeq[A1] + def toIndexedSeq: immutable.IndexedSeq[A] /** Converts this $coll to a stream. * $willNotTerminateInf diff --git a/src/library/scala/collection/TraversableOnce.scala b/src/library/scala/collection/TraversableOnce.scala index 908c4c808d..5bb2e563f6 100644 --- a/src/library/scala/collection/TraversableOnce.scala +++ b/src/library/scala/collection/TraversableOnce.scala @@ -245,7 +245,7 @@ trait TraversableOnce[+A] extends GenTraversableOnce[A] { def toSeq: Seq[A] = toStream - def toIndexedSeq[B >: A]: immutable.IndexedSeq[B] = immutable.IndexedSeq() ++ seq + def toIndexedSeq: immutable.IndexedSeq[A] = immutable.IndexedSeq() ++ seq def toBuffer[B >: A]: mutable.Buffer[B] = new ArrayBuffer[B] ++= seq diff --git a/src/library/scala/collection/TraversableProxyLike.scala b/src/library/scala/collection/TraversableProxyLike.scala index 15565e57c6..e7e797391e 100644 --- a/src/library/scala/collection/TraversableProxyLike.scala +++ b/src/library/scala/collection/TraversableProxyLike.scala @@ -77,7 +77,7 @@ trait TraversableProxyLike[+A, +Repr <: TraversableLike[A, Repr] with Traversabl override def toList: List[A] = self.toList override def toIterable: Iterable[A] = self.toIterable override def toSeq: Seq[A] = self.toSeq - override def toIndexedSeq[B >: A] = self.toIndexedSeq + override def toIndexedSeq: immutable.IndexedSeq[A] = self.toIndexedSeq override def toBuffer[B >: A] = self.toBuffer override def toStream: Stream[A] = self.toStream override def toSet[B >: A]: immutable.Set[B] = self.toSet diff --git a/src/library/scala/collection/generic/TraversableForwarder.scala b/src/library/scala/collection/generic/TraversableForwarder.scala index 6529fe4a79..3d723a1feb 100644 --- a/src/library/scala/collection/generic/TraversableForwarder.scala +++ b/src/library/scala/collection/generic/TraversableForwarder.scala @@ -61,7 +61,7 @@ trait TraversableForwarder[+A] extends Traversable[A] { override def toList: List[A] = underlying.toList override def toIterable: Iterable[A] = underlying.toIterable override def toSeq: Seq[A] = underlying.toSeq - override def toIndexedSeq[B >: A] = underlying.toIndexedSeq + override def toIndexedSeq = underlying.toIndexedSeq override def toBuffer[B >: A] = underlying.toBuffer override def toStream: Stream[A] = underlying.toStream override def toSet[B >: A]: immutable.Set[B] = underlying.toSet diff --git a/src/library/scala/collection/immutable/IndexedSeq.scala b/src/library/scala/collection/immutable/IndexedSeq.scala index bbbef158af..e3939001d8 100644 --- a/src/library/scala/collection/immutable/IndexedSeq.scala +++ b/src/library/scala/collection/immutable/IndexedSeq.scala @@ -22,7 +22,7 @@ trait IndexedSeq[+A] extends Seq[A] with GenericTraversableTemplate[A, IndexedSeq] with IndexedSeqLike[A, IndexedSeq[A]] { override def companion: GenericCompanion[IndexedSeq] = IndexedSeq - override def toIndexedSeq[B >: A]: IndexedSeq[B] = this + override def toIndexedSeq: IndexedSeq[A] = this override def seq: IndexedSeq[A] = this } diff --git a/src/library/scala/collection/interfaces/TraversableOnceMethods.scala b/src/library/scala/collection/interfaces/TraversableOnceMethods.scala index 5e1325fef6..471e977134 100644 --- a/src/library/scala/collection/interfaces/TraversableOnceMethods.scala +++ b/src/library/scala/collection/interfaces/TraversableOnceMethods.scala @@ -48,7 +48,7 @@ trait TraversableOnceMethods[+A] { // conversions def toArray[B >: A : ClassManifest]: Array[B] def toBuffer[B >: A]: mutable.Buffer[B] - def toIndexedSeq[B >: A]: immutable.IndexedSeq[B] + def toIndexedSeq: immutable.IndexedSeq[A] def toIterable: Iterable[A] def toIterator: Iterator[A] def toList: List[A] diff --git a/src/library/scala/collection/parallel/ParIterableLike.scala b/src/library/scala/collection/parallel/ParIterableLike.scala index f0d79ada9d..90b64c17f9 100644 --- a/src/library/scala/collection/parallel/ParIterableLike.scala +++ b/src/library/scala/collection/parallel/ParIterableLike.scala @@ -801,7 +801,7 @@ self: ParIterableLike[T, Repr, Sequential] => override def toList: List[T] = seq.toList - override def toIndexedSeq[U >: T]: collection.immutable.IndexedSeq[U] = seq.toIndexedSeq[U] + override def toIndexedSeq: collection.immutable.IndexedSeq[T] = seq.toIndexedSeq override def toStream: Stream[T] = seq.toStream -- cgit v1.2.3 From 5f2568e36b87d183fd4e4442d5c304db628846c4 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 10 Jan 2012 09:49:46 -0800 Subject: Revert "Accept prefixed xml attributes with null value" This reverts commit 51089b34a7a535498dee42e6465d4d577d65b7d5. A scaladoc test is failing and I have no time to look at it. --- src/library/scala/xml/PrefixedAttribute.scala | 15 ++++++--------- test/files/run/xml-attribute.scala | 25 +++---------------------- 2 files changed, 9 insertions(+), 31 deletions(-) (limited to 'src/library') diff --git a/src/library/scala/xml/PrefixedAttribute.scala b/src/library/scala/xml/PrefixedAttribute.scala index b80d6a1c73..436dfcda43 100644 --- a/src/library/scala/xml/PrefixedAttribute.scala +++ b/src/library/scala/xml/PrefixedAttribute.scala @@ -13,25 +13,22 @@ package scala.xml * * @param pre ... * @param key ... - * @param value the attribute value + * @param value the attribute value, which may not be null * @param next ... */ class PrefixedAttribute( val pre: String, val key: String, val value: Seq[Node], - val next1: MetaData) + val next: MetaData) extends Attribute { - val next = if (value ne null) next1 else next1.remove(key) + if (value eq null) + throw new UnsupportedOperationException("value is null") - /** same as this(pre, key, Text(value), next), or no attribute if value is null */ + /** same as this(key, Utility.parseAttributeValue(value), next) */ def this(pre: String, key: String, value: String, next: MetaData) = - this(pre, key, if (value ne null) Text(value) else null: NodeSeq, next) - - /** same as this(pre, key, value.get, next), or no attribute if value is None */ - def this(pre: String, key: String, value: Option[Seq[Node]], next: MetaData) = - this(pre, key, value.orNull, next) + this(pre, key, Text(value), next) /** Returns a copy of this unprefixed attribute with the given * next field. diff --git a/test/files/run/xml-attribute.scala b/test/files/run/xml-attribute.scala index 8b261acc94..2b83f70b22 100644 --- a/test/files/run/xml-attribute.scala +++ b/test/files/run/xml-attribute.scala @@ -5,29 +5,10 @@ object Test { val noAttr = val attrNull = val attrNone = - val preAttrNull = - val preAttrNone = assert(noAttr == attrNull) assert(noAttr == attrNone) - assert(noAttr == preAttrNull) - assert(noAttr == preAttrNone) - - val noAttrStr = "" - assert(noAttr.toString() == noAttrStr) - assert(attrNull.toString() == noAttrStr) - assert(attrNone.toString() == noAttrStr) - assert(preAttrNull.toString() == noAttrStr) - assert(preAttrNone.toString() == noAttrStr) - - val xml1 = - val xml2 = - val xml3 = - assert(xml1 == xml2) - assert(xml1 == xml3) - - val xml1Str = "" - assert(xml1.toString() == xml1Str) - assert(xml2.toString() == xml1Str) - assert(xml3.toString() == xml1Str) + assert(noAttr.toString() == "") + assert(attrNull.toString() == "") + assert(attrNone.toString() == "") } } -- cgit v1.2.3 From 25fcbd7021cad1e3c7b50c2b8f5c586008579bf9 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 10 Jan 2012 11:18:59 -0800 Subject: Traitified JavaConverters. So it can be used as a mixin. --- src/library/scala/collection/JavaConverters.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/library') diff --git a/src/library/scala/collection/JavaConverters.scala b/src/library/scala/collection/JavaConverters.scala index 94f7e9701b..d213e60112 100755 --- a/src/library/scala/collection/JavaConverters.scala +++ b/src/library/scala/collection/JavaConverters.scala @@ -48,7 +48,8 @@ package scala.collection * @author Martin Odersky * @since 2.8.1 */ -object JavaConverters { + +trait JavaConverters { import java.{ lang => jl, util => ju } import java.util.{ concurrent => juc } import JavaConversions._ @@ -536,3 +537,5 @@ object JavaConverters { propertiesAsScalaMapConverter(p) } + +object JavaConverters extends JavaConverters \ No newline at end of file -- cgit v1.2.3