typers.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 1,553 行 · 第 1/5 页
SCALA
1,553 行
/* NSC -- new Scala compiler * Copyright 2005-2008 LAMP/EPFL * @author Martin Odersky */// $Id: Typers.scala 14550 2008-04-08 10:54:54Z odersky $//todo: rewrite or disllow new T where T is a mixin (currently: <init> not a member of T)//todo: use inherited type info also for vars and values//todo: disallow C#D in superclass//todo: treat :::= correctlypackage scala.tools.nsc.typecheckerimport scala.collection.mutable.{HashMap, ListBuffer}import scala.compat.Platform.currentTimeimport scala.tools.nsc.util.{HashSet, Position, Set, NoPosition, SourceFile}import symtab.Flags._import util.HashSet// Suggestion check whether we can do without priminng scopes with symbols of outer scopes,// like the IDE does. /** This trait provides methods to assign types to trees. * * @author Martin Odersky * @version 1.0 */trait Typers { self: Analyzer => import global._ import definitions._ import posAssigner.atPos var appcnt = 0 var idcnt = 0 var selcnt = 0 var implcnt = 0 var impltime = 0l private val transformed = new HashMap[Tree, Tree] private val superDefs = new HashMap[Symbol, ListBuffer[Tree]] def resetTyper() { resetContexts resetNamer() transformed.clear superDefs.clear } object UnTyper extends Traverser { override def traverse(tree: Tree) = { if (tree != EmptyTree) tree.tpe = null if (tree.hasSymbol) tree.symbol = NoSymbol super.traverse(tree) } } // IDE hooks def newTyper(context: Context): Typer = new NormalTyper(context) private class NormalTyper(context : Context) extends Typer(context) // hooks for auto completion /** when in 1.4 mode the compiler accepts and ignores useless * type parameters of Java generics */ def onePointFourMode = true // todo changeto: settings.target.value == "jvm-1.4" // Mode constants /** The three mode <code>NOmode</code>, <code>EXPRmode</code> * and <code>PATTERNmode</code> are mutually exclusive. */ val NOmode = 0x000 val EXPRmode = 0x001 val PATTERNmode = 0x002 val TYPEmode = 0x004 /** The mode <code>SCCmode</code> is orthogonal to above. When set we are * in the this or super constructor call of a constructor. */ val SCCmode = 0x008 /** The mode <code>FUNmode</code> is orthogonal to above. * When set we are looking for a method or constructor. */ val FUNmode = 0x010 /** The mode <code>POLYmode</code> is orthogonal to above. * When set expression types can be polymorphic. */ val POLYmode = 0x020 /** The mode <code>QUALmode</code> is orthogonal to above. When set * expressions may be packages and Java statics modules. */ val QUALmode = 0x040 /** The mode <code>TAPPmode</code> is set for the function/type constructor * part of a type application. When set we do not decompose PolyTypes. */ val TAPPmode = 0x080 /** The mode <code>SUPERCONSTRmode</code> is set for the <code>super</code> * in a superclass constructor call <code>super.<init></code>. */ val SUPERCONSTRmode = 0x100 /** The mode <code>SNDTRYmode</code> indicates that an application is typed * for the 2nd time. In that case functions may no longer be coerced with * implicit views. */ val SNDTRYmode = 0x200 /** The mode <code>LHSmode</code> is set for the left-hand side of an * assignment. */ val LHSmode = 0x400 /** The mode <code>REGPATmode</code> is set when regular expression patterns * are allowed. */ val REGPATmode = 0x1000 /** The mode <code>ALTmode</code> is set when we are under a pattern alternative */ val ALTmode = 0x2000 /** The mode <code>HKmode</code> is set when we are typing a higher-kinded type * adapt should then check kind-arity based on the prototypical type's kind arity * type arguments should not be inferred */ val HKmode = 0x4000 // @M: could also use POLYmode | TAPPmode private val stickyModes: Int = EXPRmode | PATTERNmode | TYPEmode | ALTmode private def funMode(mode: Int) = mode & (stickyModes | SCCmode) | FUNmode | POLYmode private def argMode(fun: Tree, mode: Int) = if (treeInfo.isSelfOrSuperConstrCall(fun)) mode | SCCmode else mode private val DivergentImplicit = new Exception() abstract class Typer(context0: Context) { import context0.unit val infer = new Inferencer(context0) { override def isCoercible(tp: Type, pt: Type): Boolean = ( tp.isError || pt.isError || context0.implicitsEnabled && // this condition prevents chains of views inferView(NoPosition, tp, pt, false) != EmptyTree ) } /** * @param pos ... * @param from ... * @param to ... * @param reportAmbiguous ... * @return ... */ private def inferView(pos: Position, from: Type, to: Type, reportAmbiguous: Boolean): Tree = { if (settings.debug.value) log("infer view from "+from+" to "+to)//debug if (phase.id > currentRun.typerPhase.id) EmptyTree else from match { case MethodType(_, _) => EmptyTree case OverloadedType(_, _) => EmptyTree case PolyType(_, _) => EmptyTree case _ => val result = inferImplicit(pos, MethodType(List(from), to), reportAmbiguous) if (result != EmptyTree) result else inferImplicit( pos, MethodType(List(appliedType(ByNameParamClass.typeConstructor, List(from))), to), reportAmbiguous) } } /** * @param pos ... * @param from ... * @param name ... * @param tp ... * @param reportAmbiguous ... * @return ... */ private def inferView(pos: Position, from: Type, name: Name, tp: Type, reportAmbiguous: Boolean): Tree = { val to = refinedType(List(WildcardType), NoSymbol) var psym = (if (name.isTypeName) to.typeSymbol.newAbstractType(pos, name) else to.typeSymbol.newValue(pos, name)) psym = to.decls enter psym psym setInfo tp inferView(pos, from, to, reportAmbiguous) } import infer._ private var namerCache: Namer = null def namer = { if ((namerCache eq null) || namerCache.context != context) namerCache = newNamer(context) namerCache } private[typechecker] var context = context0 def context1 = context /** Report a type error. * * @param pos0 The position where to report the error * @param ex The exception that caused the error */ def reportTypeError(pos0: Position, ex: TypeError) { if (settings.debug.value) ex.printStackTrace() val pos = if (ex.pos == NoPosition) pos0 else ex.pos ex match { case CyclicReference(sym, info: TypeCompleter) => val msg = info.tree match { case ValDef(_, _, tpt, _) if (tpt.tpe eq null) => "recursive "+sym+" needs type" case DefDef(_, _, _, _, tpt, _) if (tpt.tpe eq null) => (if (sym.owner.isClass && sym.owner.info.member(sym.name).hasFlag(OVERLOADED)) "overloaded " else "recursive ")+sym+" needs result type" case _ => ex.getMessage() } if (context.retyping) context.error(pos, msg) else context.unit.error(pos, msg) if (sym == ObjectClass) throw new FatalError("cannot redefine root "+sym) case _ => context.error(pos, ex) } } /** Check that <code>tree</code> is a stable expression. * * @param tree ... * @return ... */ def checkStable(tree: Tree): Tree = if (treeInfo.isPureExpr(tree)) tree else errorTree(tree, "stable identifier required, but " + tree + " found.") /** Check that `tpt' refers to a non-refinement class type */ def checkClassType(tpt: Tree, existentialOK: Boolean) { def check(tpe: Type): Unit = tpe.normalize match { case TypeRef(_, sym, _) if sym.isClass && !sym.isRefinementClass => ; case ErrorType => ; case PolyType(_, restpe) => check(restpe) case ExistentialType(_, restpe) if existentialOK => check(restpe) case t => error(tpt.pos, "class type required but "+t+" found") } check(tpt.tpe) } /** Check that type <code>tp</code> is not a subtype of itself. * * @param pos ... * @param tp ... * @return <code>true</code> if <code>tp</code> is not a subtype of itself. */ def checkNonCyclic(pos: Position, tp: Type): Boolean = { def checkNotLocked(sym: Symbol): Boolean = { sym.initialize if (sym hasFlag LOCKED) { error(pos, "cyclic aliasing or subtyping involving "+sym); false } else true } tp match { case TypeRef(pre, sym, args) => (checkNotLocked(sym)) && ( !sym.isTypeMember || checkNonCyclic(pos, appliedType(pre.memberInfo(sym), args), sym) // @M! info for a type ref to a type parameter now returns a polytype // @M was: checkNonCyclic(pos, pre.memberInfo(sym).subst(sym.typeParams, args), sym) ) case SingleType(pre, sym) => checkNotLocked(sym)/* case TypeBounds(lo, hi) => var ok = true for (t <- lo) ok = ok & checkNonCyclic(pos, t) ok*/ case st: SubType => checkNonCyclic(pos, st.supertype) case ct: CompoundType => var p = ct.parents while (!p.isEmpty && checkNonCyclic(pos, p.head)) p = p.tail p.isEmpty case _ => true } } def checkNonCyclic(pos: Position, tp: Type, lockedSym: Symbol): Boolean = { lockedSym.setFlag(LOCKED) val result = checkNonCyclic(pos, tp) lockedSym.resetFlag(LOCKED) result } def checkNonCyclic(sym: Symbol) { if (!checkNonCyclic(sym.pos, sym.tpe)) sym.setInfo(ErrorType) } def checkNonCyclic(defn: Tree, tpt: Tree) { if (!checkNonCyclic(defn.pos, tpt.tpe, defn.symbol)) { tpt.tpe = ErrorType defn.symbol.setInfo(ErrorType) } } def checkParamsConvertible(pos: Position, tpe: Type) { tpe match {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?