uncurry.scala

来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 600 行 · 第 1/2 页

SCALA
600
字号
                cases)            }          case _ =>            tree        }        val members =           if (fun.tpe.typeSymbol == PartialFunctionClass) {            val isDefinedAtMethod = anonClass.newMethod(fun.pos, nme.isDefinedAt)              .setFlag(FINAL).setInfo(MethodType(formals, BooleanClass.tpe))            anonClass.info.decls enter isDefinedAtMethod            def idbody(idparam: Symbol) = fun.body match {              case Match(_, cases) =>                val substParam = new TreeSymSubstituter(List(fun.vparams.head.symbol), List(idparam));                def transformCase(cdef: CaseDef): CaseDef =                  substParam(                    resetAttrs(                      CaseDef(cdef.pat.duplicate, cdef.guard.duplicate, Literal(true))))                if (cases exists treeInfo.isDefaultCase) Literal(true)                else                   Match(                    Ident(idparam),                    (cases map transformCase) :::                       List(CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(false))))            }            List(applyMethodDef(mkUnchecked(fun.body)),                 DefDef(isDefinedAtMethod, vparamss => mkUnchecked(idbody(vparamss.head.head))))          } else {            List(applyMethodDef(fun.body))          }        localTyper.typed {          atPos(fun.pos) {            Block(              List(ClassDef(anonClass, NoMods, List(List()), List(List()), members)),              Typed(                New(TypeTree(anonClass.tpe), List(List())),                TypeTree(fun.tpe)))                      }        }      }    }    def transformArgs(pos: Position, args: List[Tree], formals: List[Type]) = {      if (formals.isEmpty) {        assert(args.isEmpty); List()      } else {        val args1 =          formals.last match {            case TypeRef(pre, sym, List(elempt)) if (sym == RepeatedParamClass) =>              def mkArrayValue(ts: List[Tree]) =                atPos(pos)(ArrayValue(TypeTree(elempt), ts) setType formals.last);              if (args.isEmpty)                List(mkArrayValue(args))              else {                val suffix: Tree = args.last match {                  case Typed(arg, Ident(name)) if name == nme.WILDCARD_STAR.toTypeName =>                    arg /*setType seqType(arg.tpe)*/                  case _ =>                     mkArrayValue(args.drop(formals.length - 1))                }                args.take(formals.length - 1) ::: List(suffix)              }            case _ => args          }        List.map2(formals, args1) { (formal, arg) =>          if (formal.typeSymbol != ByNameParamClass) {            arg          } else if (isByNameRef(arg)) {            byNameArgs.addEntry(arg)            arg setType functionType(List(), arg.tpe)          } else {            val fun = localTyper.typed(              Function(List(), arg) setPos arg.pos).asInstanceOf[Function];            new ChangeOwnerTraverser(currentOwner, fun.symbol).traverse(arg);            transformFunction(fun)          }        }      }    }// ------ The tree transformers --------------------------------------------------------    def mainTransform(tree: Tree): Tree = {      def withNeedLift(needLift: Boolean)(f: => Tree): Tree = {        val savedNeedTryLift = needTryLift        needTryLift = needLift        val t = f        needTryLift = savedNeedTryLift        t      }      /** A try or synchronized needs to be lifted anyway for MSIL if it contains       *  return statements. These are disallowed in the CLR. By lifting       *  such returns will be converted to throws.       */      def shouldBeLiftedAnyway(tree: Tree) =        forMSIL && lookForReturns.found(tree)      /** Transform tree `t' to { def f = t; f } where `f' is a fresh name       */      def liftTree(tree: Tree) = {        if (settings.debug.value)          log("lifting tree at: " + (tree.pos))        val sym = currentOwner.newMethod(tree.pos, unit.fresh.newName("liftedTree"))        sym.setInfo(MethodType(List(), tree.tpe))        new ChangeOwnerTraverser(currentOwner, sym).traverse(tree)        localTyper.typed {          atPos(tree.pos) {            Block(List(DefDef(sym, List(List()), tree)),                  Apply(Ident(sym), Nil))          }        }      }          def withInConstructorFlag(inConstructorFlag: Long)(f: => Tree): Tree = {        val savedInConstructorFlag = this.inConstructorFlag        this.inConstructorFlag = inConstructorFlag        val t = f        this.inConstructorFlag = savedInConstructorFlag        t      }      tree match {        case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>          withNeedLift(false) {            if (tree.symbol.isClassConstructor) {              atOwner(tree.symbol) {                val rhs1 = (rhs: @unchecked) match {                  case Block(stat :: stats, expr) =>                    copy.Block(                      rhs,                      withInConstructorFlag(INCONSTRUCTOR) { transform(stat) } :: transformTrees(stats),                      transform(expr));                }                copy.DefDef(                  tree, mods, name, transformTypeDefs(tparams),                  transformValDefss(vparamss), transform(tpt), rhs1)              }            } else {               super.transform(tree)             }          }        case ValDef(_, _, _, rhs)          if (!tree.symbol.owner.isSourceMethod) =>            withNeedLift(true) { super.transform(tree) }/*        case Apply(Select(Block(List(), Function(vparams, body)), nme.apply), args) =>          // perform beta-reduction; this helps keep view applications small          println("beta-reduce1: "+tree)          withNeedLift(true) {            mainTransform(new TreeSubstituter(vparams map (_.symbol), args).transform(body))          }        case Apply(Select(Function(vparams, body), nme.apply), args) =>//        if (List.forall2(vparams, args)((vparam, arg) => treeInfo.isAffineIn(body) || //                                        treeInfo.isPureExpr(arg))) =>          // perform beta-reduction; this helps keep view applications small          println("beta-reduce2: "+tree)          withNeedLift(true) {            mainTransform(new TreeSubstituter(vparams map (_.symbol), args).transform(body))          }*/        case UnApply(fn, args) =>          inPattern = false          val fn1 = transform(fn)          inPattern = true          val args1 = transformTrees(            if (fn.symbol.name == nme.unapply)              args            else if (fn.symbol.name == nme.unapplySeq)              transformArgs(tree.pos, args, analyzer.unapplyTypeListFromReturnTypeSeq(fn.tpe))            else { assert(false,"internal error: UnApply node has wrong symbol"); null })          copy.UnApply(tree, fn1, args1)        case Apply(fn, args) =>          if (settings.noassertions.value &&              (fn.symbol ne null) &&              (fn.symbol.name == nme.assert_ || fn.symbol.name == nme.assume_) &&              fn.symbol.owner == PredefModule.moduleClass) {            Literal(()).setPos(tree.pos).setType(UnitClass.tpe)          } else if (fn.symbol == Object_synchronized && shouldBeLiftedAnyway(args.head)) {            transform(copy.Apply(tree, fn, List(liftTree(args.head))))          } else {            withNeedLift(true) {              val formals = fn.tpe.paramTypes;              copy.Apply(tree, transform(fn), transformTrees(transformArgs(tree.pos, args, formals)))            }          }        case Assign(Select(_, _), _) =>          withNeedLift(true) { super.transform(tree) }        case Assign(lhs, _) if lhs.symbol.owner != currentMethod =>          withNeedLift(true) { super.transform(tree) }        case Try(block, catches, finalizer) =>          if (needTryLift || shouldBeLiftedAnyway(tree)) transform(liftTree(tree))          else super.transform(tree)        case CaseDef(pat, guard, body) =>          inPattern = true          val pat1 = transform(pat)          inPattern = false          copy.CaseDef(tree, pat1, transform(guard), transform(body))        case fun @ Function(_, _) =>          mainTransform(transformFunction(fun))        case Template(_, _, _) =>          withInConstructorFlag(0) { super.transform(tree) }        case _ =>           val tree1 = super.transform(tree)          if (isByNameRef(tree1)) {            val tree2 = tree1 setType functionType(List(), tree1.tpe)            return {              if (noApply contains tree2) tree2              else localTyper.typed {                 atPos(tree1.pos) { Apply(Select(tree2, nme.apply), List()) }              }            }           }          tree1      }    } setType uncurryTreeType(tree.tpe)    def postTransform(tree: Tree): Tree = atPhase(phase.next) {      def applyUnary(tree: Tree): Tree =         if (tree.symbol.isMethod &&             (!tree.tpe.isInstanceOf[PolyType] || tree.tpe.typeParams.isEmpty)) {          if (!tree.tpe.isInstanceOf[MethodType]) tree.tpe = MethodType(List(), tree.tpe);          atPos(tree.pos)(Apply(tree, List()) setType tree.tpe.resultType)        } else if (tree.isType) {          TypeTree(tree.tpe) setPos tree.pos        } else {          tree        }      tree match {        case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>          val rhs1 = nonLocalReturnKeys.get(tree.symbol) match {            case None => rhs            case Some(k) => atPos(rhs.pos)(nonLocalReturnTry(rhs, k, tree.symbol))          }          copy.DefDef(tree, mods, name, tparams, List(List.flatten(vparamss)), tpt, rhs1)        case Try(body, catches, finalizer) =>          if (catches forall treeInfo.isCatchCase) tree          else {            val exname = unit.fresh.newName("ex$")            val cases =              if ((catches exists treeInfo.isDefaultCase) || (catches.last match {  // bq: handle try { } catch { ... case ex:Throwable => ...}                    case CaseDef(Typed(Ident(nme.WILDCARD), tpt), EmptyTree, _) if (tpt.tpe =:= ThrowableClass.tpe) =>                      true                    case CaseDef(Bind(_, Typed(Ident(nme.WILDCARD), tpt)), EmptyTree, _) if (tpt.tpe =:= ThrowableClass.tpe) =>                      true                    case _ =>                      false                  })) catches              else catches ::: List(CaseDef(Ident(nme.WILDCARD), EmptyTree, Throw(Ident(exname))));            val catchall =               atPos(tree.pos) {                CaseDef(                  Bind(exname, Ident(nme.WILDCARD)),                  EmptyTree,                  Match(Ident(exname), cases))              }            if (settings.debug.value) log("rewrote try: " + catches + " ==> " + catchall);            val catches1 = localTyper.typedCases(              tree, List(catchall), ThrowableClass.tpe, WildcardType);            copy.Try(tree, body, catches1, finalizer)          }        case Apply(Apply(fn, args), args1) =>          copy.Apply(tree, fn, args ::: args1)        case Ident(name) =>          assert(name != nme.WILDCARD_STAR.toTypeName)          applyUnary(tree);        case Select(qual, name) =>          /* Function1.apply to ByNameFunction.apply if qualifier is a ByNameFunction */          /*          if (qual.tpe.typeSymbol == ByNameFunctionClass) {            assert(tree.symbol.name == nme.apply && tree.symbol.owner == FunctionClass(1), tree.symbol)            tree.symbol = getMember(ByNameFunctionClass, nme.apply)          }          */          applyUnary(tree)        case TypeApply(_, _) =>          applyUnary(tree)        case Return(expr) if (tree.symbol != currentOwner.enclMethod) =>          if (settings.debug.value) log("non local return in "+tree.symbol+" from "+currentOwner.enclMethod)          atPos(tree.pos)(nonLocalReturnThrow(expr, tree.symbol))        case TypeTree() =>          tree        case _ =>           if (tree.isType) TypeTree(tree.tpe) setPos tree.pos else tree      }    }  }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?