126
82
class UnCurryTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {
128
private var needTryLift = false
129
private var inPattern = false
83
private var needTryLift = false
84
private var inPattern = false
130
85
private var inConstructorFlag = 0L
131
private val byNameArgs = new mutable.HashSet[Tree]
132
private val noApply = new mutable.HashSet[Tree]
133
private val newMembers = mutable.ArrayBuffer[Tree]()
134
private val repeatedParams = mutable.Map[Symbol, List[ValDef]]()
86
private val byNameArgs = mutable.HashSet[Tree]()
87
private val noApply = mutable.HashSet[Tree]()
88
private val newMembers = mutable.Map[Symbol, mutable.Buffer[Tree]]()
89
private val repeatedParams = mutable.Map[Symbol, List[ValDef]]()
91
/** Add a new synthetic member for `currentOwner` */
92
private def addNewMember(t: Tree): Unit =
93
newMembers.getOrElseUpdate(currentOwner, mutable.Buffer()) += t
95
/** Process synthetic members for `owner`. They are removed form the `newMembers` as a side-effect. */
96
@inline private def useNewMembers[T](owner: Symbol)(f: List[Tree] => T): T =
97
f(newMembers.remove(owner).getOrElse(Nil).toList)
99
@inline private def withInPattern[T](value: Boolean)(body: => T): T = {
102
finally inPattern = !value
105
private def newFunction0(body: Tree): Tree = {
106
val result = localTyper.typedPos(body.pos)(Function(Nil, body)).asInstanceOf[Function]
107
log("Change owner from %s to %s in %s".format(currentOwner, result.symbol, result.body))
108
result.body changeOwner (currentOwner -> result.symbol)
109
transformFunction(result)
136
112
private lazy val serialVersionUIDAnnotation =
137
113
AnnotationInfo(SerialVersionUIDAttr.tpe, List(Literal(Constant(0))), List())
139
override def transformUnit(unit: CompilationUnit) {
140
freeMutableVars.clear()
141
freeLocalsTraverser(unit.body)
142
super.transformUnit(unit)
145
115
private var nprinted = 0
147
override def transform(tree: Tree): Tree = try { //debug
148
postTransform(mainTransform(tree))
150
case ex: Throwable =>
152
Console.println("exception when traversing " + tree)
117
// I don't have a clue why I'm catching TypeErrors here, but it's better
118
// than spewing stack traces at end users for internal errors. Examples
119
// which hit at this point should not be hard to come by, but the immediate
120
// motivation can be seen in continuations-neg/t3718.
121
override def transform(tree: Tree): Tree = (
122
try postTransform(mainTransform(tree))
123
catch { case ex: TypeError =>
124
unit.error(ex.pos, ex.msg)
158
/* Is tree a reference `x' to a call by name parameter that needs to be converted to
159
* x.apply()? Note that this is not the case if `x' is used as an argument to another
130
/* Is tree a reference `x` to a call by name parameter that needs to be converted to
131
* x.apply()? Note that this is not the case if `x` is used as an argument to another
160
132
* call by name parameter.
162
def isByNameRef(tree: Tree): Boolean =
163
tree.isTerm && tree.hasSymbol &&
164
isByNameParamType(tree.symbol.tpe) &&
134
def isByNameRef(tree: Tree) = (
137
&& tree.hasSymbolWhich(s => isByNameParamType(s.tpe))
167
140
/** Uncurry a type of a tree node.
168
141
* This function is sensitive to whether or not we are in a pattern -- when in a pattern
270
/* Transform a function node (x_1,...,x_n) => body of type FunctionN[T_1, .., T_N, R] to
224
/** Transform a function node (x_1,...,x_n) => body of type FunctionN[T_1, .., T_N, R] to
272
* class $anon() extends Object() with FunctionN[T_1, .., T_N, R] with ScalaObject {
226
* class $anon() extends AbstractFunctionN[T_1, .., T_N, R] with Serializable {
273
227
* def apply(x_1: T_1, ..., x_N: T_n): R = body
277
* transform a function node (x => body) of type PartialFunction[T, R] where
231
* If `settings.XoldPatmat.value`, also synthesized AbstractPartialFunction subclasses (see synthPartialFunction).
234
def transformFunction(fun: Function): Tree = {
236
// can happen when analyzer plugins assign refined types to functions, e.g.
237
// (() => Int) { def apply(): Int @typeConstraint }
238
case RefinedType(List(funTp), decls) =>
239
debuglog(s"eliminate refinement from function type ${fun.tpe}")
246
// nullary or parameterless
247
case fun1 if fun1 ne fun => fun1
248
case _ if fun.tpe.typeSymbol == PartialFunctionClass =>
249
// only get here when running under -Xoldpatmat
250
synthPartialFunction(fun)
252
val parents = addSerializable(abstractFunctionForFunctionType(fun.tpe))
253
val anonClass = fun.symbol.owner newAnonymousFunctionClass(fun.pos, inConstructorFlag) addAnnotation serialVersionUIDAnnotation
254
anonClass setInfo ClassInfoType(parents, newScope, anonClass)
256
val targs = fun.tpe.typeArgs
257
val (formals, restpe) = (targs.init, targs.last)
259
val applyMethodDef = {
260
val methSym = anonClass.newMethod(nme.apply, fun.pos, FINAL)
261
val paramSyms = map2(formals, fun.vparams) {
262
(tp, param) => methSym.newSyntheticValueParam(tp, param.name)
264
methSym setInfoAndEnter MethodType(paramSyms, restpe)
266
fun.vparams foreach (_.symbol.owner = methSym)
267
fun.body changeOwner (fun.symbol -> methSym)
269
val body = localTyper.typedPos(fun.pos)(fun.body)
270
val methDef = DefDef(methSym, List(fun.vparams), body)
272
// Have to repack the type to avoid mismatches when existentials
273
// appear in the result - see SI-4869.
274
methDef.tpt setType localTyper.packedType(body, methSym)
278
localTyper.typedPos(fun.pos) {
280
List(ClassDef(anonClass, NoMods, ListOfNil, ListOfNil, List(applyMethodDef), fun.pos)),
281
Typed(New(anonClass.tpe), TypeTree(fun.tpe)))
287
/** Transform a function node (x => body) of type PartialFunction[T, R] where
278
288
* body = expr match { case P_i if G_i => E_i }_i=1..n
289
* to (assuming none of the cases is a default case):
281
* class $anon() extends Object() with PartialFunction[T, R] with ScalaObject {
282
* def apply(x: T): R = (expr: @unchecked) match {
283
* { case P_i if G_i => E_i }_i=1..n
291
* class $anon() extends AbstractPartialFunction[T, R] with Serializable {
292
* def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = (expr: @unchecked) match {
293
* case P_1 if G_1 => E_1
295
* case P_n if G_n => E_n
296
* case _ => default(expr)
284
298
* def isDefinedAt(x: T): boolean = (x: @unchecked) match {
285
299
* case P_1 if G_1 => true
293
* However, if one of the patterns P_i if G_i is a default pattern, generate instead
295
* def isDefinedAt(x: T): boolean = true
307
* If there's a default case, the original match is used for applyOrElse, and isDefinedAt returns `true`
297
def transformFunction(fun: Function): Tree = {
298
val fun1 = deEta(fun)
299
def owner = fun.symbol.owner
300
def targs = fun.tpe.typeArgs
301
def isPartial = fun.tpe.typeSymbol == PartialFunctionClass
303
if (fun1 ne fun) fun1
305
val (formals, restpe) = (targs.init, targs.last)
306
val anonClass = owner newAnonymousFunctionClass fun.pos setFlag (FINAL | SYNTHETIC | inConstructorFlag)
308
if (isFunctionType(fun.tpe)) List(abstractFunctionForFunctionType(fun.tpe), SerializableClass.tpe)
309
else List(ObjectClass.tpe, fun.tpe, SerializableClass.tpe)
311
anonClass setInfo ClassInfoType(parents, new Scope, anonClass)
312
val applyMethod = anonClass.newMethod(fun.pos, nme.apply) setFlag FINAL
313
applyMethod setInfo MethodType(applyMethod newSyntheticValueParams formals, restpe)
314
anonClass.info.decls enter applyMethod
315
anonClass.addAnnotation(serialVersionUIDAnnotation)
317
fun.vparams foreach (_.symbol.owner = applyMethod)
318
new ChangeOwnerTraverser(fun.symbol, applyMethod) traverse fun.body
320
def mkUnchecked(tree: Tree) = {
321
def newUnchecked(expr: Tree) = Annotated(New(gen.scalaDot(UncheckedClass.name), List(Nil)), expr)
323
case Match(selector, cases) => atPos(tree.pos) { Match(newUnchecked(selector), cases) }
309
def synthPartialFunction(fun: Function) = {
310
if (!settings.XoldPatmat.value) debugwarn("Under the new pattern matching scheme, PartialFunction should have been synthesized during typers.")
312
val targs = fun.tpe.typeArgs
313
val (formals, restpe) = (targs.init, targs.last)
315
val anonClass = fun.symbol.owner newAnonymousFunctionClass(fun.pos, inConstructorFlag) addAnnotation serialVersionUIDAnnotation
316
val parents = addSerializable(appliedType(AbstractPartialFunctionClass, targs: _*))
317
anonClass setInfo ClassInfoType(parents, newScope, anonClass)
319
// duplicate before applyOrElseMethodDef is run so that it does not mess up our trees and label symbols (we have a fresh set)
320
// otherwise `TreeSymSubstituter(fun.vparams map (_.symbol), params)` won't work as the subst has been run already
322
val duped = fun.body.duplicate
323
val oldParams = new mutable.ListBuffer[Symbol]()
324
val newParams = new mutable.ListBuffer[Symbol]()
328
case l@LabelDef(_, params, _) =>
330
val oldSym = p.symbol
331
p.symbol = oldSym.cloneSymbol
333
newParams += p.symbol
338
val oldSyms = oldParams.toList ++ oldSyms0
339
val newSyms = newParams.toList ++ (oldSyms0 map (_.cloneSymbol))
340
// println("duping "+ oldSyms +" --> "+ (newSyms map (_.ownerChain)))
342
val substLabels = new TreeSymSubstituter(oldSyms, newSyms)
347
// def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 =
348
val applyOrElseMethodDef = {
349
val methSym = anonClass.newMethod(fun.pos, nme.applyOrElse) setFlag (FINAL | OVERRIDE)
351
val List(argtpe) = formals
352
val A1 = methSym newTypeParameter(newTypeName("A1")) setInfo TypeBounds.upper(argtpe)
353
val B1 = methSym newTypeParameter(newTypeName("B1")) setInfo TypeBounds.lower(restpe)
354
val methFormals = List(A1.tpe, functionType(List(A1.tpe), B1.tpe))
355
val params@List(x, default) = methSym newSyntheticValueParams methFormals
356
methSym setInfoAndEnter polyType(List(A1, B1), MethodType(params, B1.tpe))
358
val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), List(x))
359
val body = localTyper.typedPos(fun.pos) { import CODE._
360
def defaultAction(scrut: Tree) = REF(default) APPLY (REF(x))
362
substParam(fun.body) match {
363
case orig@Match(selector, cases) =>
364
if (cases exists treeInfo.isDefaultCase) orig
366
val defaultCase = CaseDef(Ident(nme.WILDCARD), EmptyTree, defaultAction(selector.duplicate))
367
Match(/*gen.mkUnchecked*/(selector), cases :+ defaultCase)
328
def applyMethodDef() = {
329
val body = if (isPartial) mkUnchecked(fun.body) else fun.body
330
DefDef(Modifiers(FINAL), nme.apply, Nil, List(fun.vparams), TypeTree(restpe), body) setSymbol applyMethod
332
def isDefinedAtMethodDef() = {
333
val m = anonClass.newMethod(fun.pos, nme.isDefinedAt) setFlag FINAL
334
m setInfo MethodType(m newSyntheticValueParams formals, BooleanClass.tpe)
335
anonClass.info.decls enter m
337
val Match(selector, cases) = fun.body
338
val vparam = fun.vparams.head.symbol
339
val idparam = m.paramss.head.head
340
val substParam = new TreeSymSubstituter(List(vparam), List(idparam))
341
def substTree[T <: Tree](t: T): T = substParam(resetLocalAttrs(t))
343
def transformCase(cdef: CaseDef): CaseDef =
344
substTree(CaseDef(cdef.pat.duplicate, cdef.guard.duplicate, Literal(true)))
345
def defaultCase = CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(false))
347
DefDef(m, mkUnchecked(
348
if (cases exists treeInfo.isDefaultCase) Literal(true)
349
else Match(substTree(selector.duplicate), (cases map transformCase) :+ defaultCase)
354
if (isPartial) List(applyMethodDef, isDefinedAtMethodDef)
355
else List(applyMethodDef)
357
localTyper.typedPos(fun.pos) {
359
List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, fun.pos)),
361
New(TypeTree(anonClass.tpe), List(List())),
372
body.changeOwner(fun.symbol -> methSym)
374
val methDef = DefDef(methSym, body)
376
// Have to repack the type to avoid mismatches when existentials
377
// appear in the result - see SI-4869.
378
methDef.tpt setType localTyper.packedType(body, methSym)
382
val isDefinedAtMethodDef = {
383
val methSym = anonClass.newMethod(nme.isDefinedAt, fun.pos, FINAL | SYNTHETIC)
384
val params = methSym newSyntheticValueParams formals
385
methSym setInfoAndEnter MethodType(params, BooleanClass.tpe)
387
val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), params)
388
def doSubst(x: Tree) = substParam(resetLocalAttrsKeepLabels(x)) // see pos/t1761 for why `resetLocalAttrs`, but must keep label symbols around
390
val body = bodyForIDA match {
391
case Match(selector, cases) =>
392
if (cases exists treeInfo.isDefaultCase) TRUE_typed
394
doSubst(Match(/*gen.mkUnchecked*/(selector),
395
(cases map (c => deriveCaseDef(c)(x => TRUE_typed))) :+ (
396
DEFAULT ==> FALSE_typed)))
399
body.changeOwner(fun.symbol -> methSym)
401
DefDef(methSym, body)
404
localTyper.typedPos(fun.pos) {
406
List(ClassDef(anonClass, NoMods, ListOfNil, ListOfNil, List(applyOrElseMethodDef, isDefinedAtMethodDef), fun.pos)),
407
Typed(New(anonClass.tpe), TypeTree(fun.tpe)))
432
484
val args1 = if (isVarArgTypes(formals)) transformVarargs(formals.last.typeArgs.head) else args
434
(formals, args1).zipped map { (formal, arg) =>
435
if (!isByNameParamType(formal)) {
486
map2(formals, args1) { (formal, arg) =>
487
if (!isByNameParamType(formal))
437
} else if (isByNameRef(arg)) {
489
else if (isByNameRef(arg)) {
438
490
byNameArgs += arg
439
arg setType functionType(List(), arg.tpe)
441
if (opt.verboseDebug) {
442
val posstr = arg.pos.source.path + ":" + arg.pos.line
443
val permstr = if (fun.isPrivate) "private" else "notprivate"
444
log("byname | %s | %s | %s".format(posstr, fun.fullName, permstr))
491
arg setType functionType(Nil, arg.tpe)
494
log(s"Argument '$arg' at line ${arg.pos.safeLine} is $formal from ${fun.fullName}")
495
def canUseDirectly(recv: Tree) = (
496
recv.tpe.typeSymbol.isSubClass(FunctionClass(0))
497
&& treeInfo.isExprSafeToInline(recv)
500
// don't add a thunk for by-name argument if argument already is an application of
501
// a Function0. We can then remove the application and use the existing Function0.
502
case Apply(Select(recv, nme.apply), Nil) if canUseDirectly(recv) =>
447
val result = localTyper.typed(
448
Function(Nil, arg) setPos arg.pos).asInstanceOf[Function]
449
new ChangeOwnerTraverser(currentOwner, result.symbol).traverse(arg)
450
transformFunction(result)
455
/** For removing calls to specially designated methods.
511
/** Called if a tree's symbol is elidable. If it's a DefDef,
512
* replace only the body/rhs with 0/false/()/null; otherwise replace
513
* the whole tree with it.
457
def elideIntoUnit(tree: Tree): Tree = Literal(()) setPos tree.pos setType UnitClass.tpe
458
def isElidable(tree: Tree) = {
459
val sym = treeInfo.methPart(tree).symbol
460
// XXX settings.noassertions.value temporarily retained to avoid
461
// breakage until a reasonable interface is settled upon.
462
sym != null && sym.elisionLevel.exists(x => x < settings.elidebelow.value || settings.noassertions.value) && {
463
log("Eliding call from " + tree.symbol.owner + " to " + sym + " based on its elision threshold of " + sym.elisionLevel.get)
515
private def replaceElidableTree(tree: Tree): Tree = {
517
case DefDef(_,_,_,_,_,_) =>
518
deriveDefDef(tree)(rhs => Block(Nil, gen.mkZero(rhs.tpe)) setType rhs.tpe) setSymbol tree.symbol setType tree.tpe
520
gen.mkZero(tree.tpe) setType tree.tpe
524
private def isSelfSynchronized(ddef: DefDef) = ddef.rhs match {
525
case Apply(fn @ TypeApply(Select(sel, _), _), _) =>
526
fn.symbol == Object_synchronized && sel.symbol == ddef.symbol.enclClass && !ddef.symbol.enclClass.isTrait
530
/** If an eligible method is entirely wrapped in a call to synchronized
531
* locked on the same instance, remove the synchronized scaffolding and
532
* mark the method symbol SYNCHRONIZED for bytecode generation.
534
private def translateSynchronized(tree: Tree) = tree match {
535
case dd @ DefDef(_, _, _, _, _, Apply(fn, body :: Nil)) if isSelfSynchronized(dd) =>
536
log("Translating " + dd.symbol.defString + " into synchronized method")
537
dd.symbol setFlag SYNCHRONIZED
538
deriveDefDef(dd)(_ => body)
468
541
def isNonLocalReturn(ret: Return) = ret.symbol != currentOwner.enclMethod || currentOwner.isLazy
470
543
// ------ The tree transformers --------------------------------------------------------
505
577
finally this.inConstructorFlag = saved
508
if (isElidable(tree)) elideIntoUnit(tree)
510
case dd @ DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
511
if (dd.symbol hasAnnotation VarargsClass) saveRepeatedParams(dd)
512
withNeedLift(false) {
513
if (tree.symbol.isClassConstructor) {
514
atOwner(tree.symbol) {
515
val rhs1 = (rhs: @unchecked) match {
516
case Block(stats, expr) =>
517
def transformInConstructor(stat: Tree) =
518
withInConstructorFlag(INCONSTRUCTOR) { transform(stat) }
519
val presupers = treeInfo.preSuperFields(stats) map transformInConstructor
520
val rest = stats drop presupers.length
521
val supercalls = rest take 1 map transformInConstructor
522
val others = rest drop 1 map transform
523
treeCopy.Block(rhs, presupers ::: supercalls ::: others, transform(expr))
580
val sym = tree.symbol
582
// TODO - settings.noassertions.value temporarily retained to avoid
583
// breakage until a reasonable interface is settled upon.
584
if ((sym ne null) && (sym.elisionLevel.exists (_ < settings.elidebelow.value || settings.noassertions.value)))
585
replaceElidableTree(tree)
586
else translateSynchronized(tree) match {
587
case dd @ DefDef(mods, name, tparams, _, tpt, rhs) =>
588
// Remove default argument trees from parameter ValDefs, SI-4812
589
val vparamssNoRhs = dd.vparamss mapConserve (_ mapConserve {p =>
590
treeCopy.ValDef(p, p.mods, p.name, p.tpt, EmptyTree)
593
if (dd.symbol hasAnnotation VarargsClass) saveRepeatedParams(dd)
595
withNeedLift(false) {
596
if (dd.symbol.isClassConstructor) {
598
val rhs1 = (rhs: @unchecked) match {
599
case Block(stats, expr) =>
600
def transformInConstructor(stat: Tree) =
601
withInConstructorFlag(INCONSTRUCTOR) { transform(stat) }
602
val presupers = treeInfo.preSuperFields(stats) map transformInConstructor
603
val rest = stats drop presupers.length
604
val supercalls = rest take 1 map transformInConstructor
605
val others = rest drop 1 map transform
606
treeCopy.Block(rhs, presupers ::: supercalls ::: others, transform(expr))
609
dd, mods, name, transformTypeDefs(tparams),
610
transformValDefss(vparamssNoRhs), transform(tpt), rhs1)
526
tree, mods, name, transformTypeDefs(tparams),
527
transformValDefss(vparamss), transform(tpt), rhs1)
613
super.transform(treeCopy.DefDef(dd, mods, name, tparams, vparamssNoRhs, tpt, rhs))
616
case ValDef(_, _, _, rhs) =>
617
if (sym eq NoSymbol) throw new IllegalStateException("Encountered Valdef without symbol: "+ tree + " in "+ unit)
618
if (!sym.owner.isSourceMethod)
619
withNeedLift(true) { super.transform(tree) }
530
621
super.transform(tree)
622
case UnApply(fn, args) =>
623
val fn1 = withInPattern(false)(transform(fn))
624
val args1 = transformTrees(fn.symbol.name match {
625
case nme.unapply => args
626
case nme.unapplySeq => transformArgs(tree.pos, fn.symbol, args, analyzer.unapplyTypeList(fn.pos, fn.symbol, fn.tpe, args))
627
case _ => sys.error("internal error: UnApply node has wrong symbol")
629
treeCopy.UnApply(tree, fn1, args1)
631
case Apply(fn, args) =>
632
if (fn.symbol == Object_synchronized && shouldBeLiftedAnyway(args.head))
633
transform(treeCopy.Apply(tree, fn, List(liftTree(args.head))))
635
val needLift = needTryLift || !fn.symbol.isLabel // SI-6749, no need to lift in args to label jumps.
636
withNeedLift(needLift) {
637
val formals = fn.tpe.paramTypes
638
treeCopy.Apply(tree, transform(fn), transformTrees(transformArgs(tree.pos, fn.symbol, args, formals)))
534
case ValDef(_, _, _, rhs) =>
535
val sym = tree.symbol
536
// a local variable that is mutable and free somewhere later should be lifted
537
// as lambda lifting (coming later) will wrap 'rhs' in an Ref object.
538
if (!sym.owner.isSourceMethod || (sym.isVariable && freeMutableVars(sym)))
539
withNeedLift(true) { super.transform(tree) }
642
case Assign(_: RefTree, _) =>
643
withNeedLift(true) { super.transform(tree) }
645
case Assign(lhs, _) if lhs.symbol.owner != currentMethod || lhs.symbol.hasFlag(LAZY | ACCESSOR) =>
646
withNeedLift(true) { super.transform(tree) }
648
case ret @ Return(_) if (isNonLocalReturn(ret)) =>
649
withNeedLift(true) { super.transform(ret) }
651
case Try(_, Nil, _) =>
652
// try-finally does not need lifting: lifting is needed only for try-catch
653
// expressions that are evaluated in a context where the stack might not be empty.
654
// `finally` does not attempt to continue evaluation after an exception, so the fact
655
// that values on the stack are 'lost' does not matter
541
656
super.transform(tree)
543
case Apply(Select(Block(List(), Function(vparams, body)), nme.apply), args) =>
544
// perform beta-reduction; this helps keep view applications small
545
println("beta-reduce1: "+tree)
547
mainTransform(new TreeSubstituter(vparams map (_.symbol), args).transform(body))
550
case Apply(Select(Function(vparams, body), nme.apply), args) =>
551
// if (List.forall2(vparams, args)((vparam, arg) => treeInfo.isAffineIn(body) ||
552
// treeInfo.isPureExpr(arg))) =>
553
// perform beta-reduction; this helps keep view applications small
554
println("beta-reduce2: "+tree)
556
mainTransform(new TreeSubstituter(vparams map (_.symbol), args).transform(body))
559
case UnApply(fn, args) =>
561
val fn1 = transform(fn)
563
val args1 = transformTrees(fn.symbol.name match {
564
case nme.unapply => args
565
case nme.unapplySeq => transformArgs(tree.pos, fn.symbol, args, analyzer.unapplyTypeListFromReturnTypeSeq(fn.tpe))
566
case _ => sys.error("internal error: UnApply node has wrong symbol")
568
treeCopy.UnApply(tree, fn1, args1)
570
case Apply(fn, args) =>
571
if (fn.symbol == Object_synchronized && shouldBeLiftedAnyway(args.head))
572
transform(treeCopy.Apply(tree, fn, List(liftTree(args.head))))
575
val formals = fn.tpe.paramTypes
576
treeCopy.Apply(tree, transform(fn), transformTrees(transformArgs(tree.pos, fn.symbol, args, formals)))
579
case Assign(Select(_, _), _) =>
580
withNeedLift(true) { super.transform(tree) }
582
case Assign(lhs, _) if lhs.symbol.owner != currentMethod || lhs.symbol.hasFlag(LAZY | ACCESSOR) =>
583
withNeedLift(true) { super.transform(tree) }
585
case ret @ Return(_) if (isNonLocalReturn(ret)) =>
586
withNeedLift(true) { super.transform(ret) }
588
case Try(block, catches, finalizer) =>
589
if (needTryLift || shouldBeLiftedAnyway(tree)) transform(liftTree(tree))
590
else super.transform(tree)
592
case CaseDef(pat, guard, body) =>
594
val pat1 = transform(pat)
596
treeCopy.CaseDef(tree, pat1, transform(guard), transform(body))
598
case fun @ Function(_, _) =>
599
mainTransform(transformFunction(fun))
601
case Template(_, _, _) =>
602
withInConstructorFlag(0) { super.transform(tree) }
605
val tree1 = super.transform(tree)
606
if (isByNameRef(tree1)) {
607
val tree2 = tree1 setType functionType(Nil, tree1.tpe)
609
if (noApply contains tree2) tree2
610
else localTyper.typedPos(tree1.pos)(Apply(Select(tree2, nme.apply), Nil))
616
assert(tree.tpe != null, tree + " tpe is null")
617
uncurryTreeType(tree.tpe)
658
case Try(block, catches, finalizer) =>
659
if (needTryLift || shouldBeLiftedAnyway(tree)) transform(liftTree(tree))
660
else super.transform(tree)
662
case CaseDef(pat, guard, body) =>
663
val pat1 = withInPattern(true)(transform(pat))
664
treeCopy.CaseDef(tree, pat1, transform(guard), transform(body))
666
case fun @ Function(_, _) =>
667
mainTransform(transformFunction(fun))
669
case Template(_, _, _) =>
670
withInConstructorFlag(0) { super.transform(tree) }
673
val tree1 = super.transform(tree)
674
if (isByNameRef(tree1)) {
675
val tree2 = tree1 setType functionType(Nil, tree1.tpe)
677
if (noApply contains tree2) tree2
678
else localTyper.typedPos(tree1.pos)(Apply(Select(tree2, nme.apply), Nil))
684
assert(result.tpe != null, result + " tpe is null")
685
result setType uncurryTreeType(result.tpe)
620
def postTransform(tree: Tree): Tree = atPhase(phase.next) {
688
def postTransform(tree: Tree): Tree = afterUncurry {
621
689
def applyUnary(): Tree = {
622
def needsParens = tree.symbol.isMethod && !tree.tpe.isInstanceOf[PolyType] // TODO_NMT: verify that the inner tree of a type-apply also gets parens if the whole tree is a polymorphic nullary method application
624
if (!tree.tpe.isInstanceOf[MethodType]) // i.e., it's a NullaryMethodType
625
tree.tpe = MethodType(Nil, tree.tpe.resultType) // TODO_NMT: I think the original `tree.tpe` was wrong, since that would set the method's resulttype to PolyType(Nil, restp) instead of restp
627
atPos(tree.pos)(Apply(tree, Nil) setType tree.tpe.resultType)
630
if (needsParens) repair
631
else if (tree.isType) TypeTree(tree.tpe) setPos tree.pos
690
// TODO_NMT: verify that the inner tree of a type-apply also gets parens if the
691
// whole tree is a polymorphic nullary method application
692
def removeNullary() = tree.tpe match {
693
case MethodType(_, _) => tree
694
case tp => tree setType MethodType(Nil, tp.resultType)
696
if (tree.symbol.isMethod && !tree.tpe.isInstanceOf[PolyType])
697
gen.mkApplyIfNeeded(removeNullary())
698
else if (tree.isType)
699
TypeTree(tree.tpe) setPos tree.pos
704
def isThrowable(pat: Tree): Boolean = pat match {
705
case Typed(Ident(nme.WILDCARD), tpt) =>
706
tpt.tpe =:= ThrowableClass.tpe
713
def isDefaultCatch(cdef: CaseDef) = isThrowable(cdef.pat) && cdef.guard.isEmpty
715
def postTransformTry(tree: Try) = {
716
val body = tree.block
717
val catches = tree.catches
718
val finalizer = tree.finalizer
719
if (opt.virtPatmat) {
720
if (catches exists (cd => !treeInfo.isCatchCase(cd)))
721
debugwarn("VPM BUG! illegal try/catch " + catches)
723
} else if (catches forall treeInfo.isCatchCase) {
726
val exname = unit.freshTermName("ex$")
728
if ((catches exists treeInfo.isDefaultCase) || isDefaultCatch(catches.last)) catches
729
else catches :+ CaseDef(Ident(nme.WILDCARD), EmptyTree, Throw(Ident(exname)))
733
Bind(exname, Ident(nme.WILDCARD)),
735
Match(Ident(exname), cases))
737
debuglog("rewrote try: " + catches + " ==> " + catchall);
738
val catches1 = localTyper.typedCases(
739
List(catchall), ThrowableClass.tpe, WildcardType)
740
treeCopy.Try(tree, body, catches1, finalizer)
636
745
/* Some uncurry post transformations add members to templates.
637
* When inside a template, the following sequence is available:
639
* Any entry in this sequence will be added into the template
747
* Members registered by `addMembers` for the current template are added
640
748
* once the template transformation has finished.
642
750
* In particular, this case will add:
643
751
* - synthetic Java varargs forwarders for repeated parameters
645
case Template(parents, self, body) =>
753
case Template(_, _, _) =>
646
754
localTyper = typer.atOwner(tree, currentClass)
647
val tmpl = if (!forMSIL || forMSIL) {
648
treeCopy.Template(tree, parents, self, transformTrees(newMembers.toList) ::: body)
649
} else super.transform(tree).asInstanceOf[Template]
652
case dd @ DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
653
val rhs1 = nonLocalReturnKeys.get(tree.symbol) match {
655
case Some(k) => atPos(rhs.pos)(nonLocalReturnTry(rhs, k, tree.symbol))
755
useNewMembers(currentClass) {
757
deriveTemplate(tree)(transformTrees(newMembers) ::: _)
657
val flatdd = treeCopy.DefDef(tree, mods, name, tparams, List(vparamss.flatten), tpt, rhs1)
658
if (dd.symbol hasAnnotation VarargsClass) addJavaVarargsForwarders(dd, flatdd, tree)
660
case Try(body, catches, finalizer) =>
661
if (catches forall treeInfo.isCatchCase) tree
663
val exname = unit.freshTermName("ex$")
665
if ((catches exists treeInfo.isDefaultCase) || (catches.last match { // bq: handle try { } catch { ... case ex:Throwable => ...}
666
case CaseDef(Typed(Ident(nme.WILDCARD), tpt), EmptyTree, _) if (tpt.tpe =:= ThrowableClass.tpe) =>
668
case CaseDef(Bind(_, Typed(Ident(nme.WILDCARD), tpt)), EmptyTree, _) if (tpt.tpe =:= ThrowableClass.tpe) =>
673
else catches :+ CaseDef(Ident(nme.WILDCARD), EmptyTree, Throw(Ident(exname)))
677
Bind(exname, Ident(nme.WILDCARD)),
679
Match(Ident(exname), cases))
760
case dd @ DefDef(_, _, _, vparamss0, _, rhs0) =>
761
val (newParamss, newRhs): (List[List[ValDef]], Tree) =
762
if (dependentParamTypeErasure isDependent dd)
763
dependentParamTypeErasure erase dd
765
val vparamss1 = vparamss0 match {
766
case _ :: Nil => vparamss0
767
case _ => vparamss0.flatten :: Nil
681
if (settings.debug.value) log("rewrote try: " + catches + " ==> " + catchall);
682
val catches1 = localTyper.typedCases(
683
tree, List(catchall), ThrowableClass.tpe, WildcardType)
684
treeCopy.Try(tree, body, catches1, finalizer)
772
val flatdd = copyDefDef(dd)(
773
vparamss = newParamss,
774
rhs = nonLocalReturnKeys get dd.symbol match {
775
case Some(k) => atPos(newRhs.pos)(nonLocalReturnTry(newRhs, k, dd.symbol))
779
addJavaVarargsForwarders(dd, flatdd)
782
postTransformTry(tree)
686
784
case Apply(Apply(fn, args), args1) =>
687
785
treeCopy.Apply(tree, fn, args ::: args1)
688
787
case Ident(name) =>
689
assert(name != tpnme.WILDCARD_STAR)
788
assert(name != tpnme.WILDCARD_STAR, tree)
691
790
case Select(_, _) | TypeApply(_, _) =>
693
case ret @ Return(expr) if (isNonLocalReturn(ret)) =>
694
if (settings.debug.value) log("non local return in "+ret.symbol+" from "+currentOwner.enclMethod)
792
case ret @ Return(expr) if isNonLocalReturn(ret) =>
793
log("non-local return from %s to %s".format(currentOwner.enclMethod, ret.symbol))
695
794
atPos(ret.pos)(nonLocalReturnThrow(expr, ret.symbol))
696
795
case TypeTree() =>
803
* When we concatenate parameter lists, formal parameter types that were dependent
804
* on prior parameter values will no longer be correctly scoped.
809
* def foo(a: A)(b: a.B): a.type = {b; b}
811
* def foo(a: A, b: a/* NOT IN SCOPE! */.B): a.B = {b; b}
814
* This violates the principle that each compiler phase should produce trees that
815
* can be retyped (see [[scala.tools.nsc.typechecker.TreeCheckers]]), and causes
816
* a practical problem in `erasure`: it is not able to correctly determine if
817
* such a signature overrides a corresponding signature in a parent. (SI-6443).
819
* This transformation erases the dependent method types by:
820
* - Widening the formal parameter type to existentially abstract
821
* over the prior parameters (using `packSymbols`). This transformation
822
* is performed in the the `InfoTransform`er [[scala.reflect.internal.transform.UnCurry]].
823
* - Inserting casts in the method body to cast to the original,
826
* For the example above, this results in:
829
* def foo(a: A, b: a.B forSome { val a: A }): a.B = { val b$1 = b.asInstanceOf[a.B]; b$1; b$1 }
832
private object dependentParamTypeErasure {
833
sealed abstract class ParamTransform {
836
final case class Identity(param: ValDef) extends ParamTransform
837
final case class Packed(param: ValDef, tempVal: ValDef) extends ParamTransform
839
def isDependent(dd: DefDef): Boolean =
841
val methType = dd.symbol.info
842
methType.isDependentMethodType && mexists(methType.paramss)(_.info exists (_.isImmediatelyDependent))
846
* @return (newVparamss, newRhs)
848
def erase(dd: DefDef): (List[List[ValDef]], Tree) = {
849
import dd.{ vparamss, rhs }
850
val paramTransforms: List[ParamTransform] =
851
map2(vparamss.flatten, dd.symbol.info.paramss.flatten) { (p, infoParam) =>
852
val packedType = infoParam.info
853
if (packedType =:= p.symbol.info) Identity(p)
855
// The Uncurry info transformer existentially abstracted over value parameters
856
// from the previous parameter lists.
858
// Change the type of the param symbol
859
p.symbol updateInfo packedType
861
// Create a new param tree
862
val newParam: ValDef = copyValDef(p)(tpt = TypeTree(packedType))
864
// Within the method body, we'll cast the parameter to the originally
865
// declared type and assign this to a synthetic val. Later, we'll patch
866
// the method body to refer to this, rather than the parameter.
867
val tempVal: ValDef = {
868
val tempValName = unit freshTermName (p.name + "$")
869
val newSym = dd.symbol.newTermSymbol(tempValName, p.pos, SYNTHETIC).setInfo(p.symbol.info)
870
atPos(p.pos)(ValDef(newSym, gen.mkAttributedCast(Ident(p.symbol), p.symbol.info)))
872
Packed(newParam, tempVal)
876
val allParams = paramTransforms map (_.param)
877
val (packedParams, tempVals) = paramTransforms.collect {
878
case Packed(param, tempVal) => (param, tempVal)
881
val rhs1 = if (tempVals.isEmpty) rhs else {
882
localTyper.typedPos(rhs.pos) {
883
// Patch the method body to refer to the temp vals
884
val rhsSubstituted = rhs.substituteSymbols(packedParams map (_.symbol), tempVals map (_.symbol))
885
// The new method body: { val p$1 = p.asInstanceOf[<dependent type>]; ...; <rhsSubstituted> }
886
Block(tempVals, rhsSubstituted)
890
(allParams :: Nil, rhs1)
703
895
/* Analyzes repeated params if method is annotated as `varargs`.
704
896
* If the repeated params exist, it saves them into the `repeatedParams` map,
705
897
* which is used later.