unapplies.scala

来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 189 行

SCALA
189
字号
/* NSC -- new Scala compiler * Copyright 2005-2006 LAMP/EPFL * @author  Martin Odersky */// $Id: Unapplies.scala 14543 2008-04-07 15:57:07Z odersky $package scala.tools.nsc.typecheckerimport symtab.Flags._/* *  @author  Martin Odersky *  @version 1.0 */trait Unapplies { self: Analyzer =>  import global._  import definitions._  import posAssigner.atPos  /** returns type list for return type of the extraction */  def unapplyTypeList(ufn: Symbol, ufntpe: Type) = {    assert(ufn.isMethod)    //Console.println("utl "+ufntpe+" "+ufntpe.typeSymbol)    ufn.name match {      case nme.unapply    => unapplyTypeListFromReturnType(ufntpe)      case nme.unapplySeq => unapplyTypeListFromReturnTypeSeq(ufntpe)      case _ => throw new TypeError(ufn+" is not an unapply or unapplySeq")    }  }  /** (the inverse of unapplyReturnTypeSeq)   *  for type Boolean, returns Nil   *  for type Option[T] or Some[T]:   *   - returns T0...Tn if n>0 and T <: Product[T0...Tn]]   *   - returns T otherwise   */  def unapplyTypeListFromReturnType(tp1: Type): List[Type] =  { // rename: unapplyTypeListFromReturnType    val tp = unapplyUnwrap(tp1)    val B = BooleanClass    val O = OptionClass     val S = SomeClass     tp.typeSymbol match { // unapplySeqResultToMethodSig      case  B => Nil      case  O | S =>        val prod = tp.typeArgs.head        getProductArgs(prod)  match {          case Some(all @ (x1::x2::xs)) => all       // n >= 2          case _                        => prod::Nil // special n == 0 ||  n == 1         }      case _ => throw new TypeError("result type "+tp+" of unapply not in {boolean, Option[_], Some[_]}")    }  }  /** let type be the result type of the (possibly polymorphic) unapply method   *  for type Option[T] or Some[T]    *  -returns T0...Tn-1,Tn* if n>0 and T <: Product[T0...Tn-1,Seq[Tn]]],    *  -returns R* if T = Seq[R]   */  def unapplyTypeListFromReturnTypeSeq(tp1: Type): List[Type] = {    val tp = unapplyUnwrap(tp1)    val   O = OptionClass; val S = SomeClass; tp.typeSymbol match {     case  O                  | S =>      val ts = unapplyTypeListFromReturnType(tp1)      val last1 = ts.last.baseType(SeqClass) match {        case TypeRef(pre, seqClass, args) => typeRef(pre, RepeatedParamClass, args)        case _ => throw new TypeError("last not seq")      }      ts.init ::: List(last1)      case _ => throw new TypeError("result type "+tp+" of unapply not in {Option[_], Some[_]}")    }  }  /** returns type of the unapply method returning T_0...T_n   *  for n == 0, boolean   *  for n == 1, Some[T0]   *  else Some[Product[Ti]]  def unapplyReturnType(elems: List[Type], useWildCards: Boolean) =     if (elems.isEmpty)      BooleanClass.tpe    else if (elems.length == 1)      optionType(if(useWildCards) WildcardType else elems(0))    else       productType({val es = elems; if(useWildCards) elems map { x => WildcardType} else elems})   */  def unapplyReturnTypeExpected(argsLength: Int) = argsLength match {    case 0 => BooleanClass.tpe    case 1 => optionType(WildcardType)    case n => optionType(productType(List.range(0,n).map (arg => WildcardType)))  }  /** returns unapply or unapplySeq if available */  def unapplyMember(tp: Type): Symbol = {    var unapp = tp.member(nme.unapply)    if (unapp == NoSymbol) unapp = tp.member(nme.unapplySeq)    unapp  }  private def copyUntyped[T <: Tree](tree: T): T = {    val tree1 = tree.duplicate    UnTyper.traverse(tree1)    tree1  }  private def classType(cdef: ClassDef, tparams: List[TypeDef]): Tree = {    val tycon = gen.mkAttributedRef(cdef.symbol)    if (tparams.isEmpty) tycon else AppliedTypeTree(tycon, tparams map (x => Ident(x.name)))  }  private def constrParams(cdef: ClassDef): List[List[ValDef]] = {    val constr = treeInfo.firstConstructor(cdef.impl.body)    (constr: @unchecked) match {      case DefDef(_, _, _, vparamss, _, _) => vparamss map (_ map copyUntyped[ValDef])    }  }  /** The return value of an unapply method of a case class C[Ts]   *  @param param  The name of the parameter of the unapply method, assumed to be of type C[Ts]   *  @param caseclazz  The case class C[Ts]   */  private def caseClassUnapplyReturnValue(param: Name, caseclazz: Symbol) = {    def caseFieldAccessorValue(selector: Symbol) = Select(Ident(param), selector)    val accessors = caseclazz.caseFieldAccessors    if (accessors.isEmpty) Literal(true)    else       Apply(        gen.scalaDot(nme.Some),         List(          if (accessors.tail.isEmpty) caseFieldAccessorValue(accessors.head)          else Apply(            gen.scalaDot(newTermName("Tuple" + accessors.length)),             accessors map caseFieldAccessorValue)))  }  /** The module corresponding to a case class; without any member definitions   */  def caseModuleDef(cdef: ClassDef): ModuleDef = atPos(cdef.pos) {    var parents = List(gen.scalaScalaObjectConstr)    if (!(cdef.mods hasFlag ABSTRACT) && cdef.tparams.isEmpty && constrParams(cdef).length == 1)      parents = gen.scalaFunctionConstr(constrParams(cdef).head map (_.tpt),                                         Ident(cdef.name)) :: parents    ModuleDef(      Modifiers(cdef.mods.flags & AccessFlags | SYNTHETIC, cdef.mods.privateWithin),      cdef.name.toTermName,      Template(parents, emptyValDef, Modifiers(0), List(), List(List()), List()))  }  /** The apply method corresponding to a case class   */  def caseModuleApplyMeth(cdef: ClassDef): DefDef = {    val tparams = cdef.tparams map copyUntyped[TypeDef]    def paramToArg(param: ValDef) = {      val id = Ident(param.name)      if (treeInfo.isRepeatedParamType(param.tpt)) Typed(id, Ident(nme.WILDCARD_STAR.toTypeName))      else id    }    val cparams = constrParams(cdef)    atPos(cdef.pos) {      DefDef(        Modifiers(SYNTHETIC | CASE),         nme.apply,         tparams,         cparams,        classType(cdef, tparams),        New(classType(cdef, tparams), cparams map (_ map paramToArg)))    }  }  /** The unapply method corresponding to a case class   */  def caseModuleUnapplyMeth(cdef: ClassDef): DefDef = {    val tparams = cdef.tparams map copyUntyped[TypeDef]    val unapplyParamName = newTermName("x$0")    val hasVarArg = constrParams(cdef) match {      case (cps @ (_ :: _)) :: _ => treeInfo.isRepeatedParamType(cps.last.tpt)      case _ => false    }    atPos(cdef.pos) {      DefDef(        Modifiers(SYNTHETIC | CASE),        if (hasVarArg) nme.unapplySeq else nme.unapply,        tparams,        List(List(ValDef(Modifiers(PARAM | SYNTHETIC), unapplyParamName,                          classType(cdef, tparams), EmptyTree))),        TypeTree(),        caseClassUnapplyReturnValue(unapplyParamName, cdef.symbol))    }  }}

⌨️ 快捷键说明

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