parallelmatching.scala

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

SCALA
1,405
字号
                  // `typeRef(definitions.ScalaPackageClass.tpe, definitions.EqualsPatternClass, List(stpe))'                  // and force an equality check. However, exhaustivity checking would not work anymore.                  // so first, extend exhaustivity check to equalspattern                }              val p = Ident(nme.WILDCARD) setType tpe              val q = Typed(p, TypeTree(tpe)) setType tpe              pats = (makeBind( vs, q) setType tpe) :: pats             case o @ Select(stor,_) =>              DBG("Select")              val stpe =                 if (!o.symbol.isValue) {                  singleType(o.tpe.prefix, o.symbol)                } else {                  singleType(NoPrefix, o.symbol) // equals-check                }              val p = Ident(nme.WILDCARD) setType stpe              val q = makeBind(vs,Typed(p, TypeTree(stpe)) setType stpe) setType stpe               pats = q::pats             case UnApply(Apply(TypeApply(sel @ Select(stor, nme.unapplySeq),List(tptArg)),_),ArrayValue(_,xs)::Nil) if (stor.symbol eq definitions.ListModule) =>               DBG("Unapply(...TypeApply...)")              //@pre: is not right-ignoring (no star pattern)              // no exhaustivity check, please              temp(j).setFlag(symtab.Flags.TRANS_FLAG)              val listType = typeRef(mkThisType(definitions.ScalaPackage), definitions.ListClass, List(tptArg.tpe))              val nmlzdPat = normalizedListPattern(xs, tptArg.tpe)              pats = makeBind(vs, nmlzdPat) :: pats            //@todo: rewrite, using __UnApply instead of UnApply like so:            //case  ua @ __UnApply(_,argtpe,_) =>              //val ua = prepat            //  val npat = (if (temp(j).tpe <:< argtpe) ua else Typed(ua,TypeTree(argtpe)).setType(argtpe))            //  pats = (makeBind(vs, npat) setType argtpe)::pats            case ua @ UnApply(Apply(fn, _), _) =>               DBG("Unapply(Apply())")              fn.tpe match {                case MethodType(List(argtpe,_*),_) =>                   val npat = (if (temp(j).tpe <:< argtpe) ua else Typed(ua,TypeTree(argtpe)).setType(argtpe))                  pats = (makeBind(vs, npat) setType argtpe)::pats              }            case o @ Apply(fn, List()) if !isCaseClass(o.tpe) || /*see t301*/ !Apply_Value.unapply(o).isEmpty =>               DBG("Apply !isCaseClass")              val stpe: Type = fn match {                 case _ if (o.symbol.isModule) =>                   singleType(o.tpe.prefix, o.symbol)                case _ if (o.tpe.termSymbol.isModule) =>                   singleType(o.tpe.prefix, o.symbol)                case Select(path,sym) =>                  path.tpe match {                    case ThisType(sym) =>                       singleType(path.tpe, o.symbol)                                                     case _ => // e.g. `case Some(p._2)' in scala.collection.jcl.Map                      if (path.isInstanceOf[Apply])                         new PseudoType(o) // outer-matching, see test/files/pos/t154.scala                      else                        singleType(singleType(path.tpe.prefix, path.symbol), o.symbol)  // old                                        }                case o @ Ident(_) =>                  if (!o.symbol.isValue)                    singleType(o.tpe.prefix, o.symbol)                  else                    singleType(NoPrefix, o.symbol)              }              val ttst = typeRef(NoPrefix, definitions.EqualsPatternClass, List(stpe))              val p = Ident(nme.WILDCARD) setType ttst              val q = makeBind(vs,Typed(p, TypeTree(stpe)) setType ttst)              pats = q::pats             case Apply_Value(pre, sym) =>               DBG("Apply_Value")              val tpe = typeRef(NoPrefix, definitions.EqualsPatternClass, singleType(pre, sym)::Nil)              val q = makeBind(vs,Typed(EmptyTree, TypeTree(tpe)) setType tpe)              pats = q :: pats            case Apply_CaseClass_NoArgs(tpe) =>  // no-args case class pattern               DBG("Apply_CaseClass_NoArgs")              val q = makeBind(vs, Typed(EmptyTree, TypeTree(tpe)) setType tpe)              pats = q :: pats            case Apply_CaseClass_WithArgs() =>  // case class pattern with args              DBG("Apply_CaseClass_WithArgs")              pats = opat :: pats            case ArrayValue(_,xs) =>              DBG("ArrayValue")              pats = opat :: pats          }          opats = opats.tail          j += 1        }        pats = pats.reverse        if (indexOfAlternative == -1) {          val res = List(Row(pats, subst, g, bx))          DBG("finished: result "+res)          res        }        else {          val prefix = pats.take( indexOfAlternative )          val alts   = getAlternativeBranches(pats( indexOfAlternative ))          val suffix = pats.drop(indexOfAlternative + 1)          val intermediary_result = alts map { p => Row(prefix ::: p :: suffix, subst, g, bx) }          DBG("not finished: intermediary_result = "+intermediary_result)          intermediary_result        }    }    if (unchanged) {      val ri = RepImpl(temp,row).init      ri    } else {      this.make(temp,row) // recursive call    }  }}  abstract class Rep {    val temp:List[Symbol]    val row:List[Row]    var sealedCols = List[Int]()    var sealedComb = List[Set[Symbol]]()    final def init: this.type = {      temp.zipWithIndex.foreach {      case (sym,i) =>         if (sym.hasFlag(symtab.Flags.MUTABLE) &&  // indicates that have not yet checked exhaustivity            !sym.hasFlag(symtab.Flags.TRANS_FLAG) &&  // indicates @unchecked            sym.tpe.typeSymbol.hasFlag(symtab.Flags.SEALED)) {                            sym.resetFlag(symtab.Flags.MUTABLE)              sealedCols = i::sealedCols              // this should enumerate all cases... however, also the superclass is taken if it is not abstract              def candidates(tpesym: Symbol): SymSet =                 if (!tpesym.hasFlag(symtab.Flags.SEALED)) emptySymbolSet else                   tpesym.children.flatMap { x =>                     val z = candidates(x)                     if (x.hasFlag(symtab.Flags.ABSTRACT)) z else z + x                   }              val cases = candidates(sym.tpe.typeSymbol)              sealedComb = cases::sealedComb            }      }      //  computes cartesian product, keeps indices available      def combine(colcom: List[(Int,Set[Symbol])]): List[List[(Int,Symbol)]] = colcom match {        case Nil => Nil        case (i,syms)::Nil => syms.toList.map { sym => List((i,sym)) }        case (i,syms)::cs  => for (s <- syms.toList; rest <- combine(cs)) yield (i,s) :: rest      }            if (!sealedCols.isEmpty) {        val allcomb = combine(sealedCols zip sealedComb)        /** returns true if pattern vector pats covers a type symbols "combination"         *  @param pats pattern vector         *  @param comb pairs of (column index, type symbol)         */        def covers(pats: List[Tree], comb:List[(Int,Symbol)]) =           comb forall {             case (i,sym) =>               val p = strip2(pats(i));             val res =               isDefaultPattern(p) || p.isInstanceOf[UnApply] || p.isInstanceOf[ArrayValue] || {                val ptpe = patternType_wrtEquals(p.tpe)                val symtpe = if (sym.hasFlag(symtab.Flags.MODULE) && (sym.linkedModuleOfClass ne NoSymbol)) {                  singleType(sym.tpe.prefix, sym.linkedModuleOfClass) // e.g. None, Nil                } else sym.tpe                (ptpe.typeSymbol == sym) || (symtpe <:< ptpe) ||                 (symtpe.parents.exists(_.typeSymbol eq ptpe.typeSymbol)) || // e.g. Some[Int] <: Option[&b]                /* outer, see scala.util.parsing.combinator.lexical.Scanner */                (ptpe.prefix.memberType(sym) <:< ptpe)              }            res          }        val coversAll = allcomb forall { combination => row exists { r => (r.guard eq EmptyTree) && covers(r.pat, combination)}}        if (!coversAll) {          val sb = new StringBuilder()          sb.append("match is not exhaustive!\n")          for (open <- allcomb if !(row exists { r => covers(r.pat, open)})) {            sb.append("missing combination ")            val NPAD = 15            def pad(s:String) = { 1.until(NPAD - s.length).foreach { x => sb.append(" ") }; sb.append(s) }            List.range(0, temp.length) foreach {              i => open.find { case (j,sym) => j==i } match {                case None => pad("*")                case Some((_,sym)) => pad(sym.name.toString)              }            }            sb.append('\n')          }          cunit.warning(temp.head.pos, sb.toString)        }      }      return this    }        /*   internal representation is (temp:List[Symbol], row:List[Row])     *        *         tmp1       tmp_m     */    final def applyRule(implicit theOwner: Symbol, rep: RepFactory): RuleApplication = row match {      case Nil =>        ErrorRule()      case Row(pats, subst, g, bx)::xs =>         var px = 0; var rpats = pats; var bnd = subst; var temps = temp; while((bnd ne null) && (rpats ne Nil)) {          val (vs,p) = strip(rpats.head);          if (!isDefaultPattern(p)) { /*break*/ bnd = null; } else {            bnd = bnd.add(vs.elements,temps.head)            rpats = rpats.tail            temps = temps.tail            px += 1 // pattern index          }        }        /*    Row(   _   ...   _     g_1  b_1 ) :: rows     it's all default patterns         */        if (bnd ne null) {    // all default patterns          val rest = if (g eq EmptyTree) null else rep.make(temp, xs)          DBG("\n---\nmixture rule is = VariableRule")          return VariableRule (bnd, g, rest, bx)        }      /*    Row( _  ... _ p_1i  ...  p_1n   g_m  b_m ) :: rows       */        // cut out column px that contains the non-default pattern        val column   = rpats.head :: (row.tail map { case Row(pats,_,_,_) => pats(px) })         val restTemp =                                               temp.take(px) ::: temp.drop(px+1)        val restRows = row map { case Row(pats, subst, g, bx) => Row(pats.take(px) ::: pats.drop(px+1), subst, g, bx) }        val mr = MixtureRule(temps.head, column, rep.make(restTemp,restRows))        DBG("\n---\nmixture rule is = "+mr.getClass.toString)        mr    }    // a fancy toString method for debugging    override final def toString = {      val sb   = new StringBuilder      val NPAD = 15      def pad(s:String) = { 1.until(NPAD - s.length).foreach { x => sb.append(" ") }; sb.append(s) }      for (tmp <- temp) pad(tmp.name.toString)      sb.append('\n')      for ((r,i) <- row.zipWithIndex) {        for (c <- r.pat ::: List(r.subst, r.guard, r.bx)) {          pad(c.toString)        }        sb.append('\n')      }      sb.toString    } /* def toString */  } /* class Rep */    /** creates initial clause matrix   */  final def initRep(roots: List[Symbol], cases: List[Tree], rep:RepFactory)(implicit theOwner: Symbol) = {    // communicate whether exhaustiveness-checking is enabled via some flag    var bx = 0;    val targets = new ListBuffer[Tree]    val vss = new ListBuffer[SymList]     val row = new ListBuffer[Row]    var cs = cases; while (cs ne Nil) cs.head match {  // stash away pvars and bodies for later      case CaseDef(pat,g,b) =>         vss     += definedVars(pat)        targets += b        if (roots.length > 1) pat match {          case Apply(fn, pargs)    =>             row += Row(pargs, NoBinding, g, bx)          case Ident(nme.WILDCARD) =>            row += Row(getDummies(roots.length), NoBinding, g, bx)        } else          row     += Row(List(pat), NoBinding, g, bx)         bx      += 1        cs = cs.tail    }    rep.make(roots, row.toList, targets.toList, vss.toList)  }  final def newVar(pos: Position, name: Name, tpe: Type)(implicit theOwner: Symbol): Symbol = {    if (tpe eq null) assert(tpe ne null, "newVar("+name+", null)")    val sym = theOwner.newVariable(pos, name) // careful: pos has special meaning    sym setInfo tpe    sym  }    final def newVar(pos: Position, tpe: Type)(implicit theOwner: Symbol): Symbol =    newVar(pos, cunit.fresh.newName("temp"), tpe) setFlag symtab.Flags.SYNTHETIC  /** returns the condition in "if (cond) k1 else k2"    */  final def condition(tpe: Type, scrut: Symbol): Tree = {    assert(scrut ne NoSymbol)    condition(tpe, mkIdent(scrut))  }  final def condition(tpe: Type, scrutineeTree: Tree): Tree = {    assert(tpe ne NoType)    assert(scrutineeTree.tpe ne NoType)    if (tpe.isInstanceOf[SingletonType] && !tpe.isInstanceOf[ConstantType]) {      if (tpe.termSymbol.isModule) {// object        //if (scrutineeTree.tpe <:< definitions.AnyRefClass.tpe)        //  Eq(gen.mkAttributedRef(tpe.termSymbol), scrutineeTree)             // object        //else          Equals(gen.mkAttributedRef(tpe.termSymbol), scrutineeTree)         // object      } else {         val x =           if (tpe.prefix ne NoPrefix) gen.mkIsInstanceOf(scrutineeTree, tpe)          else           Equals(gen.mkAttributedRef(tpe.termSymbol), scrutineeTree)        typed { x }      }    } else if (tpe.isInstanceOf[ConstantType]) {      val value = tpe.asInstanceOf[ConstantType].value      if (value == Constant(null) && scrutineeTree.tpe <:< definitions.AnyRefClass.tpe)         Eq(scrutineeTree, Literal(value))             // constant      else        Equals(scrutineeTree, Literal(value))             // constant    } else if (scrutineeTree.tpe <:< tpe && tpe <:< definitions.AnyRefClass.tpe) {      NotNull(scrutineeTree)    } else {       gen.mkIsInstanceOf(scrutineeTree, tpe)    }  }  /** adds a test comparing the dynamic outer to the static outer */  final def addOuterCondition(cond:Tree, tpe2test: Type, scrutinee: Tree, handleOuter: Tree=>Tree) = {    val TypeRef(prefix,_,_) = tpe2test    assert(prefix ne NoPrefix)    var theRef = prefix match {      case ThisType(clazz) => gen.mkAttributedThis(clazz)       case _               => gen.mkAttributedRef(prefix.prefix, prefix.termSymbol)     }    // needs explicitouter treatment    theRef = handleOuter(theRef)        val outerAcc = outerAccessor(tpe2test.typeSymbol)    if (outerAcc == NoSymbol) {      if (settings_debug) cunit.warning(scrutinee.pos, "no outer acc for "+tpe2test.typeSymbol)      cond    } else      And(cond,          Eq(Apply(Select(            gen.mkAsInstanceOf(scrutinee, tpe2test, true), outerAcc),List()), theRef))  }  }

⌨️ 快捷键说明

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