~ubuntu-branches/debian/sid/scala/sid

« back to all changes in this revision

Viewing changes to src/compiler/scala/tools/nsc/transform/UnCurry.scala

  • Committer: Package Import Robot
  • Author(s): Emmanuel Bourg, Mehdi Dogguy, Lucas Satabin, Frank S. Thomas, Emmanuel Bourg
  • Date: 2015-06-05 23:52:59 UTC
  • mfrom: (1.2.11)
  • Revision ID: package-import@ubuntu.com-20150605235259-wk00vgk83dh8o19g
Tags: 2.10.5-1
* Team upload.

[ Mehdi Dogguy ]
* New upstream release (Closes: #744278).

[ Lucas Satabin ]
* Update patches
* Update the clean target
* Update paths of elements to install
* Update watch file

[ Frank S. Thomas ]
* Remove myself from Uploaders.

[ Emmanuel Bourg ]
* The package has been adopted by the Java Team (Closes: #754935)
* Patched the build to avoid downloading libraries from the Internet
* Replaced the minified JavaScript files with unobfuscated ones
* No longer build scala-partest.jar until diffutils is packaged or replaced
* debian/watch: Fixed the versions matched (x.y.z instead of x.y.z..z)
* debian/rules:
  - Added the missing get-orig-source target (Closes: #724704)
  - Improved the clean target
* debian/control:
  - Build depend on scala (>= 2.10) and bnd
  - Use canonical URLs for the Vcs-* fields
  - Standards-Version updated to 3.9.6 (no changes)
* Switch to debhelper level 9

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* NSC -- new Scala compiler
2
 
 * Copyright 2005-2011 LAMP/EPFL
 
2
 * Copyright 2005-2013 LAMP/EPFL
3
3
 * @author
4
4
 */
5
5
 
8
8
 
9
9
import symtab.Flags._
10
10
import scala.collection.{ mutable, immutable }
 
11
import scala.language.postfixOps
11
12
 
12
13
/*<export> */
13
14
/** - uncurry all symbol and tree types (@see UnCurryPhase) -- this includes normalizing all proper types.
19
20
 *  - for every use of a def-parameter: x ==> x.apply()
20
21
 *  - for every argument to a def parameter `x: => T':
21
22
 *      if argument is not a reference to a def parameter:
22
 
 *        convert argument `e' to (expansion of) `() => e'
 
23
 *        convert argument `e` to (expansion of) `() => e'
23
24
 *  - for every repeated Scala parameter `x: T*' --> x: Seq[T].
24
25
 *  - for every repeated Java parameter `x: T...' --> x: Array[T], except:
25
26
 *    if T is an unbounded abstract type, replace --> x: Array[Object]
32
33
 *  - convert implicit method types to method types
33
34
 *  - convert non-trivial catches in try statements to matches
34
35
 *  - convert non-local returns to throws with enclosing try statements.
 
36
 *  - convert try-catch expressions in contexts where there might be values on the stack to
 
37
 *      a local method and a call to it (since an exception empties the evaluation stack):
 
38
 *
 
39
 *      meth(x_1,..., try { x_i } catch { ..}, .. x_b0) ==>
 
40
 *        {
 
41
 *          def liftedTry$1 = try { x_i } catch { .. }
 
42
 *          meth(x_1, .., liftedTry$1(), .. )
 
43
 *        }
35
44
 */
36
45
/*</export> */
37
 
abstract class UnCurry extends InfoTransform with TypingTransformers with ast.TreeDSL {
 
46
abstract class UnCurry extends InfoTransform
 
47
                          with scala.reflect.internal.transform.UnCurry
 
48
                          with TypingTransformers with ast.TreeDSL {
 
49
  val global: Global               // need to repeat here because otherwise last mixin defines global as
 
50
                                   // SymbolTable. If we had DOT this would not be an issue
38
51
  import global._                  // the global environment
39
52
  import definitions._             // standard classes and methods
40
53
  import CODE._
47
60
// ------ Type transformation --------------------------------------------------------
48
61
 
49
62
// uncurry and uncurryType expand type aliases
50
 
  private def expandAlias(tp: Type): Type = if (!tp.isHigherKinded) tp.normalize else tp
51
 
 
52
 
  private def isUnboundedGeneric(tp: Type) = tp match {
53
 
    case t @ TypeRef(_, sym, _) => sym.isAbstractType && !(t <:< AnyRefClass.tpe)
54
 
    case _ => false
55
 
  }
56
 
 
57
 
  private val uncurry: TypeMap = new TypeMap {
58
 
    def apply(tp0: Type): Type = {
59
 
      // tp0.typeSymbolDirect.initialize
60
 
      val tp = expandAlias(tp0)
61
 
      tp match {
62
 
        case MethodType(params, MethodType(params1, restpe)) =>
63
 
          apply(MethodType(params ::: params1, restpe))
64
 
        case MethodType(params, ExistentialType(tparams, restpe @ MethodType(_, _))) =>
65
 
          assert(false, "unexpected curried method types with intervening existential")
66
 
          tp0
67
 
        case MethodType(h :: t, restpe) if h.isImplicit =>
68
 
          apply(MethodType(h.cloneSymbol.resetFlag(IMPLICIT) :: t, restpe))
69
 
        case NullaryMethodType(restpe) =>
70
 
          apply(MethodType(List(), restpe))
71
 
        case TypeRef(pre, ByNameParamClass, List(arg)) =>
72
 
          apply(functionType(List(), arg))
73
 
        case TypeRef(pre, RepeatedParamClass, args) =>
74
 
          apply(appliedType(SeqClass.typeConstructor, args))
75
 
        case TypeRef(pre, JavaRepeatedParamClass, args) =>
76
 
          apply(arrayType(
77
 
            if (isUnboundedGeneric(args.head)) ObjectClass.tpe else args.head))
78
 
        case _ =>
79
 
          expandAlias(mapOver(tp))
80
 
      }
81
 
    }
82
 
  }
83
 
 
84
 
  private val uncurryType = new TypeMap {
85
 
    def apply(tp0: Type): Type = {
86
 
      val tp = expandAlias(tp0)
87
 
      tp match {
88
 
        case ClassInfoType(parents, decls, clazz) =>
89
 
          val parents1 = parents mapConserve uncurry
90
 
          if (parents1 eq parents) tp
91
 
          else ClassInfoType(parents1, decls, clazz) // @MAT normalize in decls??
92
 
        case PolyType(_, _) =>
93
 
          mapOver(tp)
94
 
        case _ =>
95
 
          tp
96
 
      }
97
 
    }
98
 
  }
99
 
 
100
 
  /** - return symbol's transformed type,
101
 
   *  - if symbol is a def parameter with transformed type T, return () => T
102
 
   *
103
 
   * @MAT: starting with this phase, the info of every symbol will be normalized
104
 
   */
105
 
  def transformInfo(sym: Symbol, tp: Type): Type =
106
 
    if (sym.isType) uncurryType(tp) else uncurry(tp)
107
63
 
108
64
  /** Traverse tree omitting local method definitions.
109
 
   *  If a `return' is encountered, set `returnFound' to true.
 
65
   *  If a `return` is encountered, set `returnFound` to true.
110
66
   *  Used for MSIL only.
111
67
   */
112
68
  private object lookForReturns extends Traverser {
124
80
  }
125
81
 
126
82
  class UnCurryTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {
127
 
 
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]]()
 
90
 
 
91
    /** Add a new synthetic member for `currentOwner` */
 
92
    private def addNewMember(t: Tree): Unit =
 
93
      newMembers.getOrElseUpdate(currentOwner, mutable.Buffer()) += t
 
94
 
 
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)
 
98
 
 
99
    @inline private def withInPattern[T](value: Boolean)(body: => T): T = {
 
100
      inPattern = value
 
101
      try body
 
102
      finally inPattern = !value
 
103
    }
 
104
 
 
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)
 
110
    }
135
111
 
136
112
    private lazy val serialVersionUIDAnnotation =
137
113
      AnnotationInfo(SerialVersionUIDAttr.tpe, List(Literal(Constant(0))), List())
138
114
 
139
 
    override def transformUnit(unit: CompilationUnit) {
140
 
      freeMutableVars.clear()
141
 
      freeLocalsTraverser(unit.body)
142
 
      super.transformUnit(unit)
143
 
    }
144
 
 
145
115
    private var nprinted = 0
146
116
 
147
 
    override def transform(tree: Tree): Tree = try { //debug
148
 
      postTransform(mainTransform(tree))
149
 
    } catch {
150
 
      case ex: Throwable =>
151
 
        if (nprinted < 10) {
152
 
          Console.println("exception when traversing " + tree)
153
 
          nprinted += 1
154
 
        }
155
 
        throw ex
156
 
    }
 
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)
 
125
        debugStack(ex)
 
126
        EmptyTree
 
127
      }
 
128
    )
157
129
 
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.
161
133
     */
162
 
    def isByNameRef(tree: Tree): Boolean =
163
 
      tree.isTerm && tree.hasSymbol &&
164
 
      isByNameParamType(tree.symbol.tpe) &&
165
 
      !byNameArgs(tree)
 
134
    def isByNameRef(tree: Tree) = (
 
135
         tree.isTerm
 
136
      && !byNameArgs(tree)
 
137
      && tree.hasSymbolWhich(s => isByNameParamType(s.tpe))
 
138
    )
166
139
 
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
179
152
 
180
153
    /** The type of a non-local return expression with given argument type */
181
154
    private def nonLocalReturnExceptionType(argtype: Type) =
182
 
      appliedType(NonLocalReturnControlClass.typeConstructor, List(argtype))
 
155
      appliedType(NonLocalReturnControlClass, argtype)
183
156
 
184
157
    /** A hashmap from method symbols to non-local return keys */
185
158
    private val nonLocalReturnKeys = perRunCaches.newMap[Symbol, Symbol]()
186
159
 
187
160
    /** Return non-local return key for given method */
188
161
    private def nonLocalReturnKey(meth: Symbol) =
189
 
      nonLocalReturnKeys.getOrElseUpdate(meth, {
190
 
        meth.newValue(meth.pos, unit.freshTermName("nonLocalReturnKey"))
191
 
          .setFlag (SYNTHETIC)
192
 
          .setInfo (ObjectClass.tpe)
193
 
      })
 
162
      nonLocalReturnKeys.getOrElseUpdate(meth,
 
163
        meth.newValue(unit.freshTermName("nonLocalReturnKey"), meth.pos, SYNTHETIC) setInfo ObjectClass.tpe
 
164
      )
194
165
 
195
166
    /** Generate a non-local return throw with given return expression from given method.
196
167
     *  I.e. for the method's non-local return key, generate:
199
170
     *  todo: maybe clone a pre-existing exception instead?
200
171
     *  (but what to do about exceptions that miss their targets?)
201
172
     */
202
 
    private def nonLocalReturnThrow(expr: Tree, meth: Symbol) =
203
 
      localTyper.typed {
204
 
        Throw(
205
 
          New(
206
 
            TypeTree(nonLocalReturnExceptionType(expr.tpe)),
207
 
            List(List(Ident(nonLocalReturnKey(meth)), expr))))
208
 
      }
 
173
    private def nonLocalReturnThrow(expr: Tree, meth: Symbol) = localTyper typed {
 
174
      Throw(
 
175
        nonLocalReturnExceptionType(expr.tpe.widen),
 
176
        Ident(nonLocalReturnKey(meth)),
 
177
        expr
 
178
      )
 
179
    }
209
180
 
210
181
    /** Transform (body, key) to:
211
182
     *
214
185
     *    try {
215
186
     *      body
216
187
     *    } catch {
217
 
     *      case ex: NonLocalReturnControl[_] =>
 
188
     *      case ex: NonLocalReturnControl[T @unchecked] =>
218
189
     *        if (ex.key().eq(key)) ex.value()
219
190
     *        else throw ex
220
191
     *    }
221
192
     *  }
222
193
     */
223
194
    private def nonLocalReturnTry(body: Tree, key: Symbol, meth: Symbol) = {
224
 
      localTyper.typed {
225
 
        val extpe = nonLocalReturnExceptionType(meth.tpe.finalResultType)
226
 
        val ex = meth.newValue(body.pos, nme.ex) setInfo extpe
227
 
        val pat = Bind(ex,
228
 
                       Typed(Ident(nme.WILDCARD),
229
 
                             AppliedTypeTree(Ident(NonLocalReturnControlClass),
230
 
                                             List(Bind(tpnme.WILDCARD,
231
 
                                                       EmptyTree)))))
232
 
        val rhs =
233
 
          If(
234
 
            Apply(
235
 
              Select(
236
 
                Apply(Select(Ident(ex), "key"), List()),
237
 
                Object_eq),
238
 
              List(Ident(key))),
239
 
            Apply(
240
 
              TypeApply(
241
 
                Select(
242
 
                  Apply(Select(Ident(ex), "value"), List()),
243
 
                  Any_asInstanceOf),
244
 
                List(TypeTree(meth.tpe.finalResultType))),
245
 
              List()),
246
 
            Throw(Ident(ex)))
247
 
        val keyDef = ValDef(key, New(TypeTree(ObjectClass.tpe), List(List())))
248
 
        val tryCatch = Try(body, List(CaseDef(pat, EmptyTree, rhs)), EmptyTree)
 
195
      localTyper typed {
 
196
        val extpe   = nonLocalReturnExceptionType(meth.tpe.finalResultType)
 
197
        val ex      = meth.newValue(nme.ex, body.pos) setInfo extpe
 
198
        val argType = meth.tpe.finalResultType withAnnotation (AnnotationInfo marker UncheckedClass.tpe)
 
199
        val pat     = gen.mkBindForCase(ex, NonLocalReturnControlClass, List(argType))
 
200
        val rhs = (
 
201
          IF   ((ex DOT nme.key)() OBJ_EQ Ident(key))
 
202
          THEN ((ex DOT nme.value)())
 
203
          ELSE (Throw(Ident(ex)))
 
204
        )
 
205
        val keyDef   = ValDef(key, New(ObjectClass.tpe))
 
206
        val tryCatch = Try(body, pat -> rhs)
 
207
 
249
208
        Block(List(keyDef), tryCatch)
250
209
      }
251
210
    }
254
213
 
255
214
    /** Undo eta expansion for parameterless and nullary methods */
256
215
    def deEta(fun: Function): Tree = fun match {
257
 
      case Function(List(), Apply(expr, List())) if treeInfo.isPureExpr(expr) =>
258
 
        if (expr hasSymbolWhich (_.isLazy))
259
 
          fun
260
 
        else
261
 
          expr
262
216
      case Function(List(), expr) if isByNameRef(expr) =>
263
217
        noApply += expr
264
218
        expr
267
221
    }
268
222
 
269
223
 
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
271
225
     *
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
274
228
     *    }
275
229
     *    new $anon()
276
230
     *
277
 
     *  transform a function node (x => body) of type PartialFunction[T, R] where
 
231
     * If `settings.XoldPatmat.value`, also synthesized AbstractPartialFunction subclasses (see synthPartialFunction).
 
232
     *
 
233
     */
 
234
    def transformFunction(fun: Function): Tree = {
 
235
      fun.tpe match {
 
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}")
 
240
          fun.tpe = funTp
 
241
        case _ =>
 
242
          ()
 
243
      }
 
244
 
 
245
      deEta(fun) match {
 
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)
 
251
        case _ =>
 
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)
 
255
 
 
256
          val targs     = fun.tpe.typeArgs
 
257
          val (formals, restpe) = (targs.init, targs.last)
 
258
 
 
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)
 
263
            }
 
264
            methSym setInfoAndEnter MethodType(paramSyms, restpe)
 
265
 
 
266
            fun.vparams foreach  (_.symbol.owner =  methSym)
 
267
            fun.body changeOwner (fun.symbol     -> methSym)
 
268
 
 
269
            val body    = localTyper.typedPos(fun.pos)(fun.body)
 
270
            val methDef = DefDef(methSym, List(fun.vparams), body)
 
271
 
 
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)
 
275
            methDef
 
276
          }
 
277
 
 
278
          localTyper.typedPos(fun.pos) {
 
279
            Block(
 
280
              List(ClassDef(anonClass, NoMods, ListOfNil, ListOfNil, List(applyMethodDef), fun.pos)),
 
281
              Typed(New(anonClass.tpe), TypeTree(fun.tpe)))
 
282
          }
 
283
 
 
284
      }
 
285
    }
 
286
 
 
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
279
 
     *  to:
 
289
     *  to (assuming none of the cases is a default case):
280
290
     *
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
 
294
     *        ...
 
295
     *        case P_n if G_n => E_n
 
296
     *        case _ => default(expr)
 
297
     *      }
284
298
     *      def isDefinedAt(x: T): boolean = (x: @unchecked) match {
285
299
     *        case P_1 if G_1 => true
286
300
     *        ...
290
304
     *    }
291
305
     *    new $anon()
292
306
     *
293
 
     *  However, if one of the patterns P_i if G_i is a default pattern, generate instead
294
 
     *
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`
296
308
     */
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
302
 
 
303
 
      if (fun1 ne fun) fun1
304
 
      else {
305
 
        val (formals, restpe) = (targs.init, targs.last)
306
 
        val anonClass = owner newAnonymousFunctionClass fun.pos setFlag (FINAL | SYNTHETIC | inConstructorFlag)
307
 
        def parents =
308
 
          if (isFunctionType(fun.tpe)) List(abstractFunctionForFunctionType(fun.tpe), SerializableClass.tpe)
309
 
          else List(ObjectClass.tpe, fun.tpe, SerializableClass.tpe)
310
 
 
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)
316
 
 
317
 
        fun.vparams foreach (_.symbol.owner = applyMethod)
318
 
        new ChangeOwnerTraverser(fun.symbol, applyMethod) traverse fun.body
319
 
 
320
 
        def mkUnchecked(tree: Tree) = {
321
 
          def newUnchecked(expr: Tree) = Annotated(New(gen.scalaDot(UncheckedClass.name), List(Nil)), expr)
322
 
          tree match {
323
 
            case Match(selector, cases) => atPos(tree.pos) { Match(newUnchecked(selector), cases) }
324
 
            case _                      => tree
 
309
    def synthPartialFunction(fun: Function) = {
 
310
      if (!settings.XoldPatmat.value) debugwarn("Under the new pattern matching scheme, PartialFunction should have been synthesized during typers.")
 
311
 
 
312
      val targs             = fun.tpe.typeArgs
 
313
      val (formals, restpe) = (targs.init, targs.last)
 
314
 
 
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)
 
318
 
 
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
 
321
      val bodyForIDA = {
 
322
        val duped   = fun.body.duplicate
 
323
        val oldParams = new mutable.ListBuffer[Symbol]()
 
324
        val newParams = new mutable.ListBuffer[Symbol]()
 
325
 
 
326
        val oldSyms0 =
 
327
          duped filter {
 
328
            case l@LabelDef(_, params, _) =>
 
329
              params foreach {p =>
 
330
                val oldSym = p.symbol
 
331
                p.symbol = oldSym.cloneSymbol
 
332
                oldParams += oldSym
 
333
                newParams += p.symbol
 
334
              }
 
335
              true
 
336
            case _ => false
 
337
          } map (_.symbol)
 
338
        val oldSyms = oldParams.toList ++ oldSyms0
 
339
        val newSyms = newParams.toList ++ (oldSyms0 map (_.cloneSymbol))
 
340
        // println("duping "+ oldSyms +" --> "+ (newSyms map (_.ownerChain)))
 
341
 
 
342
        val substLabels = new TreeSymSubstituter(oldSyms, newSyms)
 
343
 
 
344
        substLabels(duped)
 
345
      }
 
346
 
 
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)
 
350
 
 
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))
 
357
 
 
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))
 
361
 
 
362
          substParam(fun.body) match {
 
363
            case orig@Match(selector, cases) =>
 
364
              if (cases exists treeInfo.isDefaultCase) orig
 
365
              else {
 
366
                val defaultCase = CaseDef(Ident(nme.WILDCARD), EmptyTree, defaultAction(selector.duplicate))
 
367
                Match(/*gen.mkUnchecked*/(selector), cases :+ defaultCase)
 
368
              }
 
369
 
325
370
          }
326
371
        }
327
 
 
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
331
 
        }
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
336
 
 
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))
342
 
 
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))
346
 
 
347
 
          DefDef(m, mkUnchecked(
348
 
            if (cases exists treeInfo.isDefaultCase) Literal(true)
349
 
            else Match(substTree(selector.duplicate), (cases map transformCase) :+ defaultCase)
350
 
          ))
351
 
        }
352
 
 
353
 
        val members =
354
 
          if (isPartial) List(applyMethodDef, isDefinedAtMethodDef)
355
 
          else List(applyMethodDef)
356
 
 
357
 
        localTyper.typedPos(fun.pos) {
358
 
          Block(
359
 
            List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, fun.pos)),
360
 
            Typed(
361
 
              New(TypeTree(anonClass.tpe), List(List())),
362
 
              TypeTree(fun.tpe)))
363
 
        }
 
372
        body.changeOwner(fun.symbol -> methSym)
 
373
 
 
374
        val methDef = DefDef(methSym, body)
 
375
 
 
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)
 
379
        methDef
 
380
      }
 
381
 
 
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)
 
386
 
 
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
 
389
 
 
390
        val body = bodyForIDA match {
 
391
          case Match(selector, cases) =>
 
392
            if (cases exists treeInfo.isDefaultCase) TRUE_typed
 
393
            else
 
394
              doSubst(Match(/*gen.mkUnchecked*/(selector),
 
395
                        (cases map (c => deriveCaseDef(c)(x => TRUE_typed))) :+ (
 
396
                        DEFAULT ==> FALSE_typed)))
 
397
 
 
398
        }
 
399
        body.changeOwner(fun.symbol -> methSym)
 
400
 
 
401
        DefDef(methSym, body)
 
402
      }
 
403
 
 
404
      localTyper.typedPos(fun.pos) {
 
405
        Block(
 
406
          List(ClassDef(anonClass, NoMods, ListOfNil, ListOfNil, List(applyOrElseMethodDef, isDefinedAtMethodDef), fun.pos)),
 
407
          Typed(New(anonClass.tpe), TypeTree(fun.tpe)))
364
408
      }
365
409
    }
366
410
 
372
416
 
373
417
        // when calling into scala varargs, make sure it's a sequence.
374
418
        def arrayToSequence(tree: Tree, elemtp: Type) = {
375
 
          atPhase(phase.next) {
 
419
          afterUncurry {
376
420
            localTyper.typedPos(pos) {
377
421
              val pt = arrayType(elemtp)
378
422
              val adaptedTree = // might need to cast to Array[elemtp], as arrays are not covariant
388
432
        def sequenceToArray(tree: Tree) = {
389
433
          val toArraySym = tree.tpe member nme.toArray
390
434
          assert(toArraySym != NoSymbol)
391
 
          def getManifest(tp: Type): Tree = {
392
 
            val manifestOpt = localTyper.findManifest(tp, false)
393
 
            if (!manifestOpt.tree.isEmpty) manifestOpt.tree
394
 
            else if (tp.bounds.hi ne tp) getManifest(tp.bounds.hi)
395
 
            else localTyper.getManifestTree(tree.pos, tp, false)
396
 
          }
397
 
          atPhase(phase.next) {
 
435
          def getClassTag(tp: Type): Tree = {
 
436
            val tag = localTyper.resolveClassTag(tree.pos, tp)
 
437
            // Don't want bottom types getting any further than this (SI-4024)
 
438
            if (tp.typeSymbol.isBottomClass) getClassTag(AnyClass.tpe)
 
439
            else if (!tag.isEmpty) tag
 
440
            else if (tp.bounds.hi ne tp) getClassTag(tp.bounds.hi)
 
441
            else localTyper.TyperErrorGen.MissingClassTagError(tree, tp)
 
442
          }
 
443
          def traversableClassTag(tpe: Type): Tree = {
 
444
            (tpe baseType TraversableClass).typeArgs match {
 
445
              case targ :: _  => getClassTag(targ)
 
446
              case _          => EmptyTree
 
447
            }
 
448
          }
 
449
          afterUncurry {
398
450
            localTyper.typedPos(pos) {
399
 
              Apply(gen.mkAttributedSelect(tree, toArraySym),
400
 
                    List(getManifest(tree.tpe.baseType(TraversableClass).typeArgs.head)))
 
451
              gen.mkMethodCall(tree, toArraySym, Nil, List(traversableClassTag(tree.tpe)))
401
452
            }
402
453
          }
403
454
        }
404
455
 
405
456
        var suffix: Tree =
406
457
          if (treeInfo isWildcardStarArgList args) {
407
 
            val Typed(tree, _) = args.last;
 
458
            val Typed(tree, _) = args.last
408
459
            if (isJava)
409
460
              if (tree.tpe.typeSymbol == ArrayClass) tree
410
461
              else sequenceToArray(tree)
411
462
            else
412
 
              if (tree.tpe.typeSymbol isSubClass TraversableClass) tree   // @PP: I suspect this should be SeqClass
 
463
              if (tree.tpe.typeSymbol isSubClass SeqClass) tree
413
464
              else arrayToSequence(tree, varargsElemType)
414
465
          }
415
466
          else {
419
470
            else arrayToSequence(mkArray, varargsElemType)
420
471
          }
421
472
 
422
 
        atPhase(phase.next) {
423
 
          if (isJava && isPrimitiveArray(suffix.tpe) && isArrayOfSymbol(fun.tpe.params.last.tpe, ObjectClass)) {
 
473
        afterUncurry {
 
474
          if (isJava && !isReferenceArray(suffix.tpe) && isArrayOfSymbol(fun.tpe.params.last.tpe, ObjectClass)) {
 
475
            // The array isn't statically known to be a reference array, so call ScalaRuntime.toObjectArray.
424
476
            suffix = localTyper.typedPos(pos) {
425
 
              gen.mkRuntimeCall("toObjectArray", List(suffix))
 
477
              gen.mkRuntimeCall(nme.toObjectArray, List(suffix))
426
478
            }
427
479
          }
428
480
        }
431
483
 
432
484
      val args1 = if (isVarArgTypes(formals)) transformVarargs(formals.last.typeArgs.head) else args
433
485
 
434
 
      (formals, args1).zipped map { (formal, arg) =>
435
 
        if (!isByNameParamType(formal)) {
 
486
      map2(formals, args1) { (formal, arg) =>
 
487
        if (!isByNameParamType(formal))
436
488
          arg
437
 
        } else if (isByNameRef(arg)) {
 
489
        else if (isByNameRef(arg)) {
438
490
          byNameArgs += arg
439
 
          arg setType functionType(List(), arg.tpe)
440
 
        } else {
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)
 
492
        }
 
493
        else {
 
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)
 
498
          )
 
499
          arg match {
 
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) =>
 
503
              recv
 
504
            case _ =>
 
505
              newFunction0(arg)
445
506
          }
446
 
 
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)
451
507
        }
452
508
      }
453
509
    }
454
510
 
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.
456
514
     */
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)
464
 
        true
 
515
    private def replaceElidableTree(tree: Tree): Tree = {
 
516
      tree match {
 
517
        case DefDef(_,_,_,_,_,_) =>
 
518
          deriveDefDef(tree)(rhs => Block(Nil, gen.mkZero(rhs.tpe)) setType rhs.tpe) setSymbol tree.symbol setType tree.tpe
 
519
        case _ =>
 
520
          gen.mkZero(tree.tpe) setType tree.tpe
465
521
      }
466
522
    }
467
523
 
 
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
 
527
      case _ => false
 
528
    }
 
529
 
 
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.
 
533
     */
 
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)
 
539
      case _ => tree
 
540
    }
468
541
    def isNonLocalReturn(ret: Return) = ret.symbol != currentOwner.enclMethod || currentOwner.isLazy
469
542
 
470
543
// ------ The tree transformers --------------------------------------------------------
484
557
      def shouldBeLiftedAnyway(tree: Tree) = false && // buggy, see #1981
485
558
        forMSIL && lookForReturns.found(tree)
486
559
 
487
 
      /** Transform tree `t' to { def f = t; f } where `f' is a fresh name
 
560
      /** Transform tree `t` to { def f = t; f } where `f` is a fresh name
488
561
       */
489
562
      def liftTree(tree: Tree) = {
490
 
        if (settings.debug.value)
491
 
          log("lifting tree at: " + (tree.pos))
492
 
        val sym = currentOwner.newMethod(tree.pos, unit.freshTermName("liftedTree"))
 
563
        debuglog("lifting tree at: " + (tree.pos))
 
564
        val sym = currentOwner.newMethod(unit.freshTermName("liftedTree"), tree.pos)
493
565
        sym.setInfo(MethodType(List(), tree.tpe))
494
 
        new ChangeOwnerTraverser(currentOwner, sym).traverse(tree)
 
566
        tree.changeOwner(currentOwner -> sym)
495
567
        localTyper.typedPos(tree.pos)(Block(
496
 
          List(DefDef(sym, List(Nil), tree)),
 
568
          List(DefDef(sym, ListOfNil, tree)),
497
569
          Apply(Ident(sym), Nil)
498
570
        ))
499
571
      }
505
577
        finally this.inConstructorFlag = saved
506
578
      }
507
579
 
508
 
      if (isElidable(tree)) elideIntoUnit(tree)
509
 
      else tree match {
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
 
581
      val result = (
 
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)
 
591
            })
 
592
 
 
593
            if (dd.symbol hasAnnotation VarargsClass) saveRepeatedParams(dd)
 
594
 
 
595
            withNeedLift(false) {
 
596
              if (dd.symbol.isClassConstructor) {
 
597
                atOwner(sym) {
 
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))
 
607
                  }
 
608
                  treeCopy.DefDef(
 
609
                    dd, mods, name, transformTypeDefs(tparams),
 
610
                    transformValDefss(vparamssNoRhs), transform(tpt), rhs1)
524
611
                }
525
 
                treeCopy.DefDef(
526
 
                  tree, mods, name, transformTypeDefs(tparams),
527
 
                  transformValDefss(vparamss), transform(tpt), rhs1)
 
612
              } else {
 
613
                super.transform(treeCopy.DefDef(dd, mods, name, tparams, vparamssNoRhs, tpt, rhs))
528
614
              }
529
 
            } else {
 
615
            }
 
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) }
 
620
            else
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")
 
628
            })
 
629
            treeCopy.UnApply(tree, fn1, args1)
 
630
 
 
631
          case Apply(fn, args) =>
 
632
            if (fn.symbol == Object_synchronized && shouldBeLiftedAnyway(args.head))
 
633
              transform(treeCopy.Apply(tree, fn, List(liftTree(args.head))))
 
634
            else {
 
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)))
 
639
              }
531
640
            }
532
 
          }
533
 
 
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) }
540
 
          else
 
641
 
 
642
          case Assign(_: RefTree, _) =>
 
643
            withNeedLift(true) { super.transform(tree) }
 
644
 
 
645
          case Assign(lhs, _) if lhs.symbol.owner != currentMethod || lhs.symbol.hasFlag(LAZY | ACCESSOR) =>
 
646
            withNeedLift(true) { super.transform(tree) }
 
647
 
 
648
          case ret @ Return(_) if (isNonLocalReturn(ret)) =>
 
649
            withNeedLift(true) { super.transform(ret) }
 
650
 
 
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)
542
 
/*
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)
546
 
          withNeedLift(true) {
547
 
            mainTransform(new TreeSubstituter(vparams map (_.symbol), args).transform(body))
548
 
          }
549
 
 
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)
555
 
          withNeedLift(true) {
556
 
            mainTransform(new TreeSubstituter(vparams map (_.symbol), args).transform(body))
557
 
          }
558
 
*/
559
 
        case UnApply(fn, args) =>
560
 
          inPattern = false
561
 
          val fn1 = transform(fn)
562
 
          inPattern = true
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")
567
 
          })
568
 
          treeCopy.UnApply(tree, fn1, args1)
569
 
 
570
 
        case Apply(fn, args) =>
571
 
          if (fn.symbol == Object_synchronized && shouldBeLiftedAnyway(args.head))
572
 
            transform(treeCopy.Apply(tree, fn, List(liftTree(args.head))))
573
 
          else
574
 
            withNeedLift(true) {
575
 
              val formals = fn.tpe.paramTypes
576
 
              treeCopy.Apply(tree, transform(fn), transformTrees(transformArgs(tree.pos, fn.symbol, args, formals)))
577
 
            }
578
 
 
579
 
        case Assign(Select(_, _), _) =>
580
 
          withNeedLift(true) { super.transform(tree) }
581
 
 
582
 
        case Assign(lhs, _) if lhs.symbol.owner != currentMethod || lhs.symbol.hasFlag(LAZY | ACCESSOR) =>
583
 
          withNeedLift(true) { super.transform(tree) }
584
 
 
585
 
        case ret @ Return(_) if (isNonLocalReturn(ret)) =>
586
 
          withNeedLift(true) { super.transform(ret) }
587
 
 
588
 
        case Try(block, catches, finalizer) =>
589
 
          if (needTryLift || shouldBeLiftedAnyway(tree)) transform(liftTree(tree))
590
 
          else super.transform(tree)
591
 
 
592
 
        case CaseDef(pat, guard, body) =>
593
 
          inPattern = true
594
 
          val pat1 = transform(pat)
595
 
          inPattern = false
596
 
          treeCopy.CaseDef(tree, pat1, transform(guard), transform(body))
597
 
 
598
 
        case fun @ Function(_, _) =>
599
 
          mainTransform(transformFunction(fun))
600
 
 
601
 
        case Template(_, _, _) =>
602
 
          withInConstructorFlag(0) { super.transform(tree) }
603
 
 
604
 
        case _ =>
605
 
          val tree1 = super.transform(tree)
606
 
          if (isByNameRef(tree1)) {
607
 
            val tree2 = tree1 setType functionType(Nil, tree1.tpe)
608
 
            return {
609
 
              if (noApply contains tree2) tree2
610
 
              else localTyper.typedPos(tree1.pos)(Apply(Select(tree2, nme.apply), Nil))
611
 
            }
612
 
          }
613
 
          tree1
614
 
      }
615
 
    } setType {
616
 
      assert(tree.tpe != null, tree + " tpe is null")
617
 
      uncurryTreeType(tree.tpe)
 
657
 
 
658
          case Try(block, catches, finalizer) =>
 
659
            if (needTryLift || shouldBeLiftedAnyway(tree)) transform(liftTree(tree))
 
660
            else super.transform(tree)
 
661
 
 
662
          case CaseDef(pat, guard, body) =>
 
663
            val pat1 = withInPattern(true)(transform(pat))
 
664
            treeCopy.CaseDef(tree, pat1, transform(guard), transform(body))
 
665
 
 
666
          case fun @ Function(_, _) =>
 
667
            mainTransform(transformFunction(fun))
 
668
 
 
669
          case Template(_, _, _) =>
 
670
            withInConstructorFlag(0) { super.transform(tree) }
 
671
 
 
672
          case _ =>
 
673
            val tree1 = super.transform(tree)
 
674
            if (isByNameRef(tree1)) {
 
675
              val tree2 = tree1 setType functionType(Nil, tree1.tpe)
 
676
              return {
 
677
                if (noApply contains tree2) tree2
 
678
                else localTyper.typedPos(tree1.pos)(Apply(Select(tree2, nme.apply), Nil))
 
679
              }
 
680
            }
 
681
            tree1
 
682
        }
 
683
      )
 
684
      assert(result.tpe != null, result + " tpe is null")
 
685
      result setType uncurryTreeType(result.tpe)
618
686
    }
619
687
 
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
623
 
        def repair = {
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
626
 
 
627
 
          atPos(tree.pos)(Apply(tree, Nil) setType tree.tpe.resultType)
628
 
        }
629
 
 
630
 
        if (needsParens) repair
631
 
        else if (tree.isType) TypeTree(tree.tpe) setPos tree.pos
632
 
        else tree
 
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)
 
695
        }
 
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
 
700
        else
 
701
          tree
 
702
      }
 
703
 
 
704
      def isThrowable(pat: Tree): Boolean = pat match {
 
705
        case Typed(Ident(nme.WILDCARD), tpt) =>
 
706
          tpt.tpe =:= ThrowableClass.tpe
 
707
        case Bind(_, pat) =>
 
708
          isThrowable(pat)
 
709
        case _ =>
 
710
          false
 
711
      }
 
712
 
 
713
      def isDefaultCatch(cdef: CaseDef) = isThrowable(cdef.pat) && cdef.guard.isEmpty
 
714
 
 
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)
 
722
          tree
 
723
        } else if (catches forall treeInfo.isCatchCase) {
 
724
          tree
 
725
        } else {
 
726
          val exname = unit.freshTermName("ex$")
 
727
          val cases =
 
728
            if ((catches exists treeInfo.isDefaultCase) || isDefaultCatch(catches.last)) catches
 
729
            else catches :+ CaseDef(Ident(nme.WILDCARD), EmptyTree, Throw(Ident(exname)))
 
730
          val catchall =
 
731
            atPos(tree.pos) {
 
732
              CaseDef(
 
733
                Bind(exname, Ident(nme.WILDCARD)),
 
734
                EmptyTree,
 
735
                Match(Ident(exname), cases))
 
736
            }
 
737
          debuglog("rewrote try: " + catches + " ==> " + catchall);
 
738
          val catches1 = localTyper.typedCases(
 
739
            List(catchall), ThrowableClass.tpe, WildcardType)
 
740
          treeCopy.Try(tree, body, catches1, finalizer)
 
741
        }
633
742
      }
634
743
 
635
744
      tree match {
636
745
        /* Some uncurry post transformations add members to templates.
637
 
         * When inside a template, the following sequence is available:
638
 
         * - newMembers
639
 
         * Any entry in this sequence will be added into the template
 
746
         *
 
747
         * Members registered by `addMembers` for the current template are added
640
748
         * once the template transformation has finished.
641
749
         *
642
750
         * In particular, this case will add:
643
751
         * - synthetic Java varargs forwarders for repeated parameters
644
752
         */
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]
650
 
          newMembers.clear
651
 
          tmpl
652
 
        case dd @ DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
653
 
          val rhs1 = nonLocalReturnKeys.get(tree.symbol) match {
654
 
            case None => rhs
655
 
            case Some(k) => atPos(rhs.pos)(nonLocalReturnTry(rhs, k, tree.symbol))
 
755
          useNewMembers(currentClass) {
 
756
            newMembers =>
 
757
              deriveTemplate(tree)(transformTrees(newMembers) ::: _)
656
758
          }
657
 
          val flatdd = treeCopy.DefDef(tree, mods, name, tparams, List(vparamss.flatten), tpt, rhs1)
658
 
          if (dd.symbol hasAnnotation VarargsClass) addJavaVarargsForwarders(dd, flatdd, tree)
659
 
          flatdd
660
 
        case Try(body, catches, finalizer) =>
661
 
          if (catches forall treeInfo.isCatchCase) tree
662
 
          else {
663
 
            val exname = unit.freshTermName("ex$")
664
 
            val cases =
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) =>
667
 
                      true
668
 
                    case CaseDef(Bind(_, Typed(Ident(nme.WILDCARD), tpt)), EmptyTree, _) if (tpt.tpe =:= ThrowableClass.tpe) =>
669
 
                      true
670
 
                    case _ =>
671
 
                      false
672
 
                  })) catches
673
 
              else catches :+ CaseDef(Ident(nme.WILDCARD), EmptyTree, Throw(Ident(exname)))
674
 
            val catchall =
675
 
              atPos(tree.pos) {
676
 
                CaseDef(
677
 
                  Bind(exname, Ident(nme.WILDCARD)),
678
 
                  EmptyTree,
679
 
                  Match(Ident(exname), cases))
 
759
 
 
760
        case dd @ DefDef(_, _, _, vparamss0, _, rhs0) =>
 
761
          val (newParamss, newRhs): (List[List[ValDef]], Tree) =
 
762
            if (dependentParamTypeErasure isDependent dd)
 
763
              dependentParamTypeErasure erase dd
 
764
            else {
 
765
              val vparamss1 = vparamss0 match {
 
766
                case _ :: Nil => vparamss0
 
767
                case _        => vparamss0.flatten :: Nil
680
768
              }
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)
685
 
          }
 
769
              (vparamss1, rhs0)
 
770
            }
 
771
 
 
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))
 
776
              case None    => newRhs
 
777
            }
 
778
          )
 
779
          addJavaVarargsForwarders(dd, flatdd)
 
780
 
 
781
        case tree: Try =>
 
782
          postTransformTry(tree)
 
783
 
686
784
        case Apply(Apply(fn, args), args1) =>
687
785
          treeCopy.Apply(tree, fn, args ::: args1)
 
786
 
688
787
        case Ident(name) =>
689
 
          assert(name != tpnme.WILDCARD_STAR)
 
788
          assert(name != tpnme.WILDCARD_STAR, tree)
690
789
          applyUnary()
691
790
        case Select(_, _) | TypeApply(_, _) =>
692
791
          applyUnary()
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() =>
697
796
          tree
700
799
      }
701
800
    }
702
801
 
 
802
    /**
 
803
     * When we concatenate parameter lists, formal parameter types that were dependent
 
804
     * on prior parameter values will no longer be correctly scoped.
 
805
     *
 
806
     * For example:
 
807
     *
 
808
     * {{{
 
809
     *   def foo(a: A)(b: a.B): a.type = {b; b}
 
810
     *   // after uncurry
 
811
     *   def foo(a: A, b: a/* NOT IN SCOPE! */.B): a.B = {b; b}
 
812
     * }}}
 
813
     *
 
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).
 
818
     *
 
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,
 
824
     *     precise type.
 
825
     *
 
826
     * For the example above, this results in:
 
827
     *
 
828
     * {{{
 
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 }
 
830
     * }}}
 
831
     */
 
832
    private object dependentParamTypeErasure {
 
833
      sealed abstract class ParamTransform {
 
834
        def param: ValDef
 
835
      }
 
836
      final case class Identity(param: ValDef) extends ParamTransform
 
837
      final case class Packed(param: ValDef, tempVal: ValDef) extends ParamTransform
 
838
 
 
839
      def isDependent(dd: DefDef): Boolean =
 
840
        beforeUncurry {
 
841
          val methType = dd.symbol.info
 
842
          methType.isDependentMethodType && mexists(methType.paramss)(_.info exists (_.isImmediatelyDependent))
 
843
        }
 
844
 
 
845
      /**
 
846
       * @return (newVparamss, newRhs)
 
847
       */
 
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)
 
854
            else {
 
855
              // The Uncurry info transformer existentially abstracted over value parameters
 
856
              // from the previous parameter lists.
 
857
 
 
858
              // Change the type of the param symbol
 
859
              p.symbol updateInfo packedType
 
860
 
 
861
              // Create a new param tree
 
862
              val newParam: ValDef = copyValDef(p)(tpt = TypeTree(packedType))
 
863
 
 
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)))
 
871
              }
 
872
              Packed(newParam, tempVal)
 
873
            }
 
874
          }
 
875
 
 
876
        val allParams = paramTransforms map (_.param)
 
877
        val (packedParams, tempVals) = paramTransforms.collect {
 
878
          case Packed(param, tempVal) => (param, tempVal)
 
879
        }.unzip
 
880
 
 
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)
 
887
          }
 
888
        }
 
889
 
 
890
        (allParams :: Nil, rhs1)
 
891
      }
 
892
    }
 
893
 
 
894
 
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.
716
908
 
717
909
    /* Called during post transform, after the method argument lists have been flattened.
718
910
     * It looks for the method in the `repeatedParams` map, and generates a Java-style
719
 
     * varargs forwarder. It then adds the forwarder to the `newMembers` sequence.
 
911
     * varargs forwarder.
720
912
     */
721
 
    private def addJavaVarargsForwarders(dd: DefDef, flatdd: DefDef, tree: Tree): Unit = {
722
 
      if (!repeatedParams.contains(dd.symbol))
723
 
        return
 
913
    private def addJavaVarargsForwarders(dd: DefDef, flatdd: DefDef): DefDef = {
 
914
      if (!dd.symbol.hasAnnotation(VarargsClass) || !repeatedParams.contains(dd.symbol))
 
915
        return flatdd
724
916
 
725
917
      def toSeqType(tp: Type): Type = {
726
918
        val arg = elementType(ArrayClass, tp)
739
931
        )
740
932
      }
741
933
 
742
 
      val reps          = repeatedParams(dd.symbol)
743
 
      val rpsymbols     = reps.map(_.symbol).toSet
744
 
      val theTyper      = typer.atOwner(tree, currentClass)
745
 
      val flatparams    = flatdd.vparamss.head
 
934
      val reps       = repeatedParams(dd.symbol)
 
935
      val rpsymbols  = reps.map(_.symbol).toSet
 
936
      val theTyper   = typer.atOwner(dd, currentClass)
 
937
      val flatparams = flatdd.vparamss.head
746
938
 
747
939
      // create the type
748
940
      val forwformals = flatparams map {
750
942
        case p                        => p.symbol.tpe
751
943
      }
752
944
      val forwresult = dd.symbol.tpe.finalResultType
753
 
      val forwformsyms = (forwformals, flatparams).zipped map ((tp, oldparam) =>
754
 
        currentClass.newValueParameter(oldparam.symbol.pos, oldparam.name).setInfo(tp)
 
945
      val forwformsyms = map2(forwformals, flatparams)((tp, oldparam) =>
 
946
        currentClass.newValueParameter(oldparam.name, oldparam.symbol.pos).setInfo(tp)
755
947
      )
756
948
      def mono = MethodType(forwformsyms, forwresult)
757
949
      val forwtype = dd.symbol.tpe match {
760
952
      }
761
953
 
762
954
      // create the symbol
763
 
      val forwsym = (
764
 
        currentClass.newMethod(dd.pos, dd.name)
765
 
        . setFlag (VARARGS | SYNTHETIC | flatdd.symbol.flags)
766
 
        . setInfo (forwtype)
767
 
      )
 
955
      val forwsym = currentClass.newMethod(dd.name, dd.pos, VARARGS | SYNTHETIC | flatdd.symbol.flags) setInfo forwtype
768
956
 
769
957
      // create the tree
770
958
      val forwtree = theTyper.typedPos(dd.pos) {
771
 
        val locals = (forwsym ARGS, flatparams).zipped map {
 
959
        val locals = map2(forwsym ARGS, flatparams) {
772
960
          case (_, fp) if !rpsymbols(fp.symbol) => null
773
961
          case (argsym, fp)                     =>
774
962
            Block(Nil,
778
966
              )
779
967
            )
780
968
        }
781
 
        val seqargs = (locals, forwsym ARGS).zipped map {
 
969
        val seqargs = map2(locals, forwsym ARGS) {
782
970
          case (null, argsym) => Ident(argsym)
783
971
          case (l, _)         => l
784
972
        }
797
985
        case None =>
798
986
          // enter symbol into scope
799
987
          currentClass.info.decls enter forwsym
800
 
 
801
 
          // add the method to `newMembers`
802
 
          newMembers += forwtree
 
988
          addNewMember(forwtree)
803
989
      }
804
 
    }
805
 
  }
806
 
 
807
 
  /** Set of mutable local variables that are free in some inner method. */
808
 
  private val freeMutableVars: mutable.Set[Symbol] = new mutable.HashSet
809
 
 
810
 
  /** PP: There is apparently some degree of overlap between the CAPTURED
811
 
   *  flag and the role being filled here.  I think this is how this was able
812
 
   *  to go for so long looking only at DefDef and Ident nodes, as bugs
813
 
   *  would only emerge under more complicated conditions such as #3855.
814
 
   *  I'll try to figure it all out, but if someone who already knows the
815
 
   *  whole story wants to fill it in, that too would be great.
816
 
   */
817
 
  private val freeLocalsTraverser = new Traverser {
818
 
    var currentMethod: Symbol = NoSymbol
819
 
    var maybeEscaping = false
820
 
 
821
 
    def withEscaping(body: => Unit) {
822
 
      val saved = maybeEscaping
823
 
      maybeEscaping = true
824
 
      try body
825
 
      finally maybeEscaping = saved
826
 
    }
827
 
 
828
 
    override def traverse(tree: Tree) = tree match {
829
 
      case DefDef(_, _, _, _, _, _) =>
830
 
        val lastMethod = currentMethod
831
 
        currentMethod = tree.symbol
832
 
        super.traverse(tree)
833
 
        currentMethod = lastMethod
834
 
      /** A method call with a by-name parameter represents escape. */
835
 
      case Apply(fn, args) if fn.symbol.paramss.nonEmpty =>
836
 
        traverse(fn)
837
 
        (fn.symbol.paramss.head, args).zipped foreach { (param, arg) =>
838
 
          if (param.tpe != null && isByNameParamType(param.tpe))
839
 
            withEscaping(traverse(arg))
840
 
          else
841
 
            traverse(arg)
842
 
        }
843
 
      /** The rhs of a closure represents escape. */
844
 
      case Function(vparams, body) =>
845
 
        vparams foreach traverse
846
 
        withEscaping(traverse(body))
847
 
 
848
 
      /** The appearance of an ident outside the method where it was defined or
849
 
       *  anytime maybeEscaping is true implies escape.
850
 
       */
851
 
      case Ident(_) =>
852
 
        val sym = tree.symbol
853
 
        if (sym.isVariable && sym.owner.isMethod && (maybeEscaping || sym.owner != currentMethod))
854
 
          freeMutableVars += sym
855
 
      case _ =>
856
 
        super.traverse(tree)
857
 
    }
858
 
  }
859
 
 
 
990
 
 
991
      flatdd
 
992
    }
 
993
  }
860
994
}