typers.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 1,553 行 · 第 1/5 页
SCALA
1,553 行
case MethodType(formals, restpe) => /* if (formals.exists(_.typeSymbol == ByNameParamClass) && formals.length != 1) error(pos, "methods with `=>'-parameter can be converted to function values only if they take no other parameters") if (formals exists (_.typeSymbol == RepeatedParamClass)) error(pos, "methods with `*'-parameters cannot be converted to function values"); */ if (restpe.isDependent) error(pos, "method with dependent type "+tpe+" cannot be converted to function value"); checkParamsConvertible(pos, restpe) case _ => } } def checkRegPatOK(pos: Position, mode: Int) = if ((mode & REGPATmode) == 0) error(pos, "no regular expression pattern allowed here\n"+ "(regular expression patterns are only allowed in arguments to *-parameters)") /** Check that type of given tree does not contain local or private * components. */ object checkNoEscaping extends TypeMap { private var owner: Symbol = _ private var scope: Scope = _ private var hiddenSymbols: List[Symbol] = _ /** Check that type <code>tree</code> does not refer to private * components unless itself is wrapped in something private * (<code>owner</code> tells where the type occurs). * * @param owner ... * @param tree ... * @return ... */ def privates[T <: Tree](owner: Symbol, tree: T): T = check(owner, EmptyScope, WildcardType, tree) /** Check that type <code>tree</code> does not refer to entities * defined in scope <code>scope</code>. * * @param scope ... * @param pt ... * @param tree ... * @return ... */ def locals[T <: Tree](scope: Scope, pt: Type, tree: T): T = check(NoSymbol, scope, pt, tree) def check[T <: Tree](owner: Symbol, scope: Scope, pt: Type, tree: T): T = { this.owner = owner this.scope = scope hiddenSymbols = List() val tp1 = apply(tree.tpe) if (hiddenSymbols.isEmpty || inIDE) tree setType tp1 // @S: because arguments of classes are owned by the classes' owner else if (hiddenSymbols exists (_.isErroneous)) setError(tree) else if (isFullyDefined(pt)) tree setType pt //todo: eliminate else if (tp1.typeSymbol.isAnonymousClass) // todo: eliminate check(owner, scope, pt, tree setType tp1.typeSymbol.classBound) else if (owner == NoSymbol) tree setType packSymbols(hiddenSymbols.reverse, tp1) else { // privates val badSymbol = hiddenSymbols.head error(tree.pos, (if (badSymbol hasFlag PRIVATE) "private " else "") + badSymbol + " escapes its defining scope as part of type "+tree.tpe) setError(tree) } } def addHidden(sym: Symbol) = if (!(hiddenSymbols contains sym)) hiddenSymbols = sym :: hiddenSymbols override def apply(t: Type): Type = { def checkNoEscape(sym: Symbol) { if (sym.hasFlag(PRIVATE)) { var o = owner while (o != NoSymbol && o != sym.owner && !o.isLocal && !o.hasFlag(PRIVATE) && !o.privateWithin.hasTransOwner(sym.owner)) o = o.owner if (o == sym.owner) addHidden(sym) } else if (sym.owner.isTerm && !sym.isTypeParameterOrSkolem) { var e = scope.lookupEntry(sym.name) var found = false while (!found && (e ne null) && e.owner == scope) { if (e.sym == sym) { found = true addHidden(sym) } else { e = scope.lookupNextEntry(e) } } } } mapOver( t match { case TypeRef(_, sym, args) => checkNoEscape(sym) if (!hiddenSymbols.isEmpty && hiddenSymbols.head == sym && sym.isAliasType && sym.typeParams.length == args.length) { hiddenSymbols = hiddenSymbols.tail t.normalize } else t case SingleType(_, sym) => checkNoEscape(sym) t case _ => t }) } } def reenterValueParams(vparamss: List[List[ValDef]]) { for (vparams <- vparamss) for (vparam <- vparams) vparam.symbol = context.scope enter vparam.symbol } def reenterTypeParams(tparams: List[TypeDef]): List[Symbol] = for (tparam <- tparams) yield { tparam.symbol = context.scope enter tparam.symbol tparam.symbol.deSkolemize } /** The qualifying class of a this or super with prefix <code>qual</code>. * * @param tree ... * @param qual ... * @return ... */ def qualifyingClassContext(tree: Tree, qual: Name): Context = { if (qual.isEmpty) { if (context.enclClass.owner.isPackageClass) error(tree.pos, tree+" can be used only in a class, object, or template") context.enclClass } else { var c = context.enclClass while (c != NoContext && c.owner.name != qual) c = c.outer.enclClass if (c == NoContext) error(tree.pos, qual+" is not an enclosing class") c } } /** The typer for an expression, depending on where we are. If we are before a superclass * call, this is a typer over a constructor context; otherwise it is the current typer. */ def constrTyperIf(inConstr: Boolean): Typer = if (inConstr) newTyper(context.makeConstructorContext) else this /** The typer for a label definition. If this is part of a template we * first have to enter the label definition. */ def labelTyper(ldef: LabelDef): Typer = if (ldef.symbol == NoSymbol) { // labeldef is part of template val typer1 = newTyper(context.makeNewScope(ldef, context.owner)(LabelScopeKind)) typer1.enterLabelDef(ldef) typer1 } else this final val xtypes = false /** Does the context of tree <code>tree</code> require a stable type? */ private def isStableContext(tree: Tree, mode: Int, pt: Type) = isNarrowable(tree.tpe) && ((mode & (EXPRmode | LHSmode)) == EXPRmode) && (xtypes || (pt.isStable || (mode & QUALmode) != 0 && !tree.symbol.isConstant || pt.typeSymbol.isAbstractType && pt.bounds.lo.isStable && !(tree.tpe <:< pt))) /** <p> * Post-process an identifier or selection node, performing the following: * </p> * <ol> * <!--(1)--><li>Check that non-function pattern expressions are stable</li> * <!--(2)--><li>Check that packages and static modules are not used as values</li> * <!--(3)--><li>Turn tree type into stable type if possible and required by context.</li> * </ol> */ private def stabilize(tree: Tree, pre: Type, mode: Int, pt: Type): Tree = { if (tree.symbol.hasFlag(OVERLOADED) && (mode & FUNmode) == 0) inferExprAlternative(tree, pt) val sym = tree.symbol if (tree.tpe.isError) tree else if ((mode & (PATTERNmode | FUNmode)) == PATTERNmode && tree.isTerm) { // (1) checkStable(tree) } else if ((mode & (EXPRmode | QUALmode)) == EXPRmode && !sym.isValue) { // (2) errorTree(tree, sym+" is not a value") } else { if (sym.isStable && pre.isStable && tree.tpe.typeSymbol != ByNameParamClass && (isStableContext(tree, mode, pt) || sym.isModule && !sym.isMethod)) tree.setType(singleType(pre, sym)) else tree } } private def isNarrowable(tpe: Type): Boolean = tpe match { case TypeRef(_, _, _) | RefinedType(_, _) => true case ExistentialType(_, tpe1) => isNarrowable(tpe1) case AnnotatedType(_, tpe1, _) => isNarrowable(tpe1) case PolyType(_, tpe1) => isNarrowable(tpe1) case _ => !phase.erasedTypes } private def stabilizedType(tree: Tree): Type = tree.tpe/*{ val sym = tree.symbol val res = tree match { case Ident(_) if (sym.isStable) => val pre = if (sym.owner.isClass) sym.owner.thisType else NoPrefix singleType(pre, sym) case Select(qual, _) if (qual.tpe.isStable && sym.isStable) => singleType(qual.tpe, sym) case _ => tree.tpe } res }*/ /** * @param tree ... * @param mode ... * @param pt ... * @return ... */ def stabilizeFun(tree: Tree, mode: Int, pt: Type): Tree = { val sym = tree.symbol val pre = tree match { case Select(qual, _) => qual.tpe case _ => NoPrefix } if (tree.tpe.isInstanceOf[MethodType] && pre.isStable && sym.tpe.paramTypes.isEmpty && (isStableContext(tree, mode, pt) || sym.isModule)) tree.setType(MethodType(List(), singleType(pre, sym))) else tree } /** The member with given name of given qualifier tree */ def member(qual: Tree, name: Name) = qual.tpe match { case ThisType(clazz) if (context.enclClass.owner.hasTransOwner(clazz)) => qual.tpe.member(name) case _ => if (phase.next.erasedTypes) qual.tpe.member(name) else qual.tpe.nonLocalMember(name) } def silent(op: Typer => Tree): AnyRef /* in fact, TypeError or Tree */ = try { if (context.reportGeneralErrors) { val context1 = context.makeSilent(context.reportAmbiguousErrors) context1.undetparams = context.undetparams context1.savedTypeBounds = context.savedTypeBounds val typer1 = newTyper(context1) val result = op(typer1) context.undetparams = context1.undetparams context.savedTypeBounds = context1.savedTypeBounds result } else { op(this) } } catch { case ex: CyclicReference => throw ex case ex: TypeError => ex } /** Perform the following adaptations of expression, pattern or type `tree' wrt to * given mode `mode' and given prototype `pt': * (0) Convert expressions with constant types to literals * (1) Resolve overloading, unless mode contains FUNmode * (2) Apply parameterless functions * (3) Apply polymorphic types to fresh instances of their type parameters and * store these instances in context.undetparams, * unless followed by explicit type application. * (4) Do the following to unapplied methods used as values: * (4.1) If the method has only implicit parameters pass implicit arguments * (4.2) otherwise, if `pt' is a function type and method is not a constructor, * convert to function by eta-expansion, * (4.3) otherwise, if the method is nullary with a result type compatible to `pt' * and it is not a constructor, apply it to () * otherwise issue an error * (5) Convert constructors in a pattern as follows: * (5.1) If constructor refers to a case class factory, set tree's type to the unique * instance of its primary constructor that is a subtype of the expected type. * (5.2) If constructor refers to an exractor, convert to application of * unapply or unapplySeq method. * * (6) Convert all other types to TypeTree nodes. * (7) When in TYPEmode but not FUNmode or HKmode, check that types are fully parameterized * (7.1) In HKmode, higher-kinded types are allowed, but they must have the expected kind-arity * (8) When in both EXPRmode and FUNmode, add apply method calls to values of object type. * (9) If there are undetermined type variables and not POLYmode, infer expression instance * Then, if tree's type is not a subtype of expected type, try the following adaptations: * (10) If the expected type is Byte, Short or Char, and the expression * is an integer fitting in the range of that type, convert it to that type. * (11) Widen numeric literals to their expected type, if necessary * (12) When in mode EXPRmode, convert E to { E; () } if expected type is scala.Unit. * (13) When in mode EXPRmode, apply a view * If all this fails, error */ protected def adapt(tree: Tree, mode: Int, pt: Type): Tree = tree.tpe match { case ct @ ConstantType(value) if ((mode & (TYPEmode | FUNmode)) == 0 && (ct <:< pt) && !inIDE) => // (0) copy.Literal(tree, value) case OverloadedType(pre, alts) if ((mode & FUNmode) == 0) => // (1) inferExprAlternative(tree, pt) adapt(tree, mode, pt) case PolyType(List(), restpe) => // (2) adapt(tree setType restpe, mode, pt) case TypeRef(_, sym, List(arg)) if ((mode & EXPRmode) != 0 && sym == ByNameParamClass) => // (2) adapt(tree setType arg, mode, pt) case tr @ TypeRef(_, sym, _)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?