typers.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 1,553 行 · 第 1/5 页
SCALA
1,553 行
if sym.isAliasType && tr.normalize.isInstanceOf[ExistentialType] && ((mode & (EXPRmode | LHSmode)) == EXPRmode) => adapt(tree setType tr.normalize.skolemizeExistential(context.owner, tree), mode, pt) case et @ ExistentialType(_, _) if ((mode & (EXPRmode | LHSmode)) == EXPRmode) => adapt(tree setType et.skolemizeExistential(context.owner, tree), mode, pt) case PolyType(tparams, restpe) if ((mode & (TAPPmode | PATTERNmode)) == 0) => // (3) assert((mode & HKmode) == 0) //@M val tparams1 = cloneSymbols(tparams) val tree1 = if (tree.isType) tree else TypeApply(tree, tparams1 map (tparam => TypeTree(tparam.tpe) setOriginal tree)) setPos tree.pos context.undetparams = context.undetparams ::: tparams1 adapt(tree1 setType restpe.substSym(tparams, tparams1), mode, pt) case mt: ImplicitMethodType if ((mode & (EXPRmode | FUNmode | LHSmode)) == EXPRmode) => // (4.1) if (!context.undetparams.isEmpty & (mode & POLYmode) == 0) { // (9) val tparams = context.undetparams context.undetparams = List() inferExprInstance(tree, tparams, pt) adapt(tree, mode, pt) } else { val typer1 = constrTyperIf(treeInfo.isSelfOrSuperConstrCall(tree)) typer1.typed(typer1.applyImplicitArgs(tree), mode, pt) } case mt: MethodType if (((mode & (EXPRmode | FUNmode | LHSmode)) == EXPRmode) && (context.undetparams.isEmpty || (mode & POLYmode) != 0)) => val meth = tree.symbol if (!meth.isConstructor && //isCompatible(tparamsToWildcards(mt, context.undetparams), pt) && isFunctionType(pt))/* && (pt <:< functionType(mt.paramTypes map (t => WildcardType), WildcardType)))*/ { // (4.2) if (settings.debug.value) log("eta-expanding "+tree+":"+tree.tpe+" to "+pt) checkParamsConvertible(tree.pos, tree.tpe) typed(etaExpand(context.unit, tree), mode, pt) } else if (!meth.isConstructor && mt.paramTypes.isEmpty) { // (4.3) adapt(typed(Apply(tree, List()) setPos tree.pos), mode, pt) } else if (context.implicitsEnabled) { errorTree(tree, "missing arguments for "+meth+meth.locationString+ (if (meth.isConstructor) "" else ";\nfollow this method with `_' if you want to treat it as a partially applied function")) } else { setError(tree) } case _ => def applyPossible = { def applyMeth = member(adaptToName(tree, nme.apply), nme.apply) if ((mode & TAPPmode) != 0) tree.tpe.typeParams.isEmpty && applyMeth.filter(! _.tpe.typeParams.isEmpty) != NoSymbol else applyMeth.filter(_.tpe.paramSectionCount > 0) != NoSymbol } if (tree.isType) { if ((mode & FUNmode) != 0) { tree } else if (tree.hasSymbol && !tree.symbol.typeParams.isEmpty && (mode & HKmode) == 0) { // (7) // @M When not typing a higher-kinded type ((mode & HKmode) == 0), types must be of kind *, // and thus parameterised types must be applied to their type arguments // @M TODO: why do kind-* tree's have symbols, while higher-kinded ones don't? errorTree(tree, tree.symbol+" takes type parameters") tree setType tree.tpe } else if ( // (7.1) @M: check kind-arity // @M: removed check for tree.hasSymbol and replace tree.symbol by tree.tpe.symbol (TypeTree's must also be checked here, and they don't directly have a symbol) ((mode & HKmode) != 0) && // @M: don't check tree.tpe.symbol.typeParams. check tree.tpe.typeParams!!! // (e.g., m[Int] --> tree.tpe.symbol.typeParams.length == 1, tree.tpe.typeParams.length == 0!) tree.tpe.typeParams.length != pt.typeParams.length && !(tree.tpe.typeSymbol==AnyClass || tree.tpe.typeSymbol==AllClass || pt == WildcardType )) { // Check that the actual kind arity (tree.symbol.typeParams.length) conforms to the expected // kind-arity (pt.typeParams.length). Full checks are done in checkKindBounds in Infer. // Note that we treat Any and Nothing as kind-polymorphic. // We can't perform this check when typing type arguments to an overloaded method before the overload is resolved // (or in the case of an error type) -- this is indicated by pt == WildcardType (see case TypeApply in typed1). errorTree(tree, tree.tpe+" takes "+reporter.countElementsAsString(tree.tpe.typeParams.length, "type parameter")+ ", expected: "+reporter.countAsString(pt.typeParams.length)) tree setType tree.tpe } else tree match { // (6) case TypeTree() => tree case _ => TypeTree(tree.tpe) setOriginal(tree) } } else if ((mode & (PATTERNmode | FUNmode)) == (PATTERNmode | FUNmode)) { // (5) val extractor = tree.symbol.filter(sym => unapplyMember(sym.tpe).exists) if (extractor != NoSymbol) { tree setSymbol extractor val unapply = unapplyMember(extractor.tpe) val clazz = if (unapply.tpe.paramTypes.length == 1) unapply.tpe.paramTypes.head.typeSymbol else NoSymbol if ((unapply hasFlag CASE) && (clazz hasFlag CASE) && !(clazz.info.baseClasses.tail exists (_ hasFlag CASE))) { if (!phase.erasedTypes) checkStable(tree) //todo: do we need to demand this? // convert synthetic unapply of case class to case class constructor val prefix = tree.tpe.prefix val tree1 = TypeTree(clazz.primaryConstructor.tpe.asSeenFrom(prefix, clazz.owner)) .setOriginal(tree) try { inferConstructorInstance(tree1, clazz.typeParams, pt) } catch { case tpe : TypeError => throw tpe case t : Exception => logError("CONTEXT: " + (tree.pos).dbgString, t) throw t } tree1 } else { tree } } else { errorTree(tree, tree.symbol + " is not a case class constructor, nor does it have an unapply/unapplySeq method") } } else if ((mode & (EXPRmode | FUNmode)) == (EXPRmode | FUNmode) && !tree.tpe.isInstanceOf[MethodType] && !tree.tpe.isInstanceOf[OverloadedType] && applyPossible) { assert((mode & HKmode) == 0) //@M val qual = adaptToName(tree, nme.apply) match { case id @ Ident(_) => val pre = if (id.symbol.owner.isPackageClass) id.symbol.owner.thisType else if (id.symbol.owner.isClass) context.enclosingSubClassContext(id.symbol.owner).prefix else NoPrefix stabilize(id, pre, EXPRmode | QUALmode, WildcardType) case sel @ Select(qualqual, _) => stabilize(sel, qualqual.tpe, EXPRmode | QUALmode, WildcardType) case other => other } typed(atPos(tree.pos)(Select(qual, nme.apply)), mode, pt) } else if (!context.undetparams.isEmpty && (mode & POLYmode) == 0) { // (9) assert((mode & HKmode) == 0) //@M instantiate(tree, mode, pt) } else if (tree.tpe <:< pt) { def isStructuralType(tpe: Type): Boolean = tpe match { case RefinedType(ps, decls) => decls.toList exists (x => x.isTerm && x.allOverriddenSymbols.isEmpty) case _ => false } if (isStructuralType(pt) && tree.tpe.typeSymbol == ArrayClass) { // all Arrays used as structural refinement typed values must be boxed // this does not solve the case where the type to be adapted to comes // from a type variable that was bound by a strctural but is instantiated typed(Apply(Select(gen.mkAttributedRef(ScalaRunTimeModule), nme.forceBoxedArray), List(tree))) } else tree } else { if ((mode & PATTERNmode) != 0) { if ((tree.symbol ne null) && tree.symbol.isModule) inferModulePattern(tree, pt) if (isPopulated(tree.tpe, approximateAbstracts(pt))) return tree } val tree1 = constfold(tree, pt) // (10) (11) if (tree1.tpe <:< pt) adapt(tree1, mode, pt) else { if ((mode & (EXPRmode | FUNmode)) == EXPRmode) { pt.normalize match { case TypeRef(_, sym, _) => // note: was if (pt.typeSymbol == UnitClass) but this leads to a potentially // infinite expansion if pt is constant type () if (sym == UnitClass && tree.tpe <:< AnyClass.tpe) // (12) return typed(atPos(tree.pos)(Block(List(tree), Literal(()))), mode, pt) case _ => } if (!context.undetparams.isEmpty) { return instantiate(tree, mode, pt) } if (context.implicitsEnabled && !tree.tpe.isError && !pt.isError) { // (13); the condition prevents chains of views if (settings.debug.value) log("inferring view from "+tree.tpe+" to "+pt) val coercion = inferView(tree.pos, tree.tpe, pt, true) // convert forward views of delegate types into closures wrapped around // the delegate's apply method (the "Invoke" method, which was translated into apply) if (forMSIL && coercion != null && isCorrespondingDelegate(tree.tpe, pt)) { val meth: Symbol = tree.tpe.member(nme.apply) if(settings.debug.value) log("replacing forward delegate view with: " + meth + ":" + meth.tpe) return typed(Select(tree, meth), mode, pt) } if (coercion != EmptyTree) { if (settings.debug.value) log("inferred view from "+tree.tpe+" to "+pt+" = "+coercion+":"+coercion.tpe) return typed(Apply(coercion, List(tree)) setPos tree.pos, mode, pt) } } } if (settings.debug.value) { log("error tree = "+tree) if (settings.explaintypes.value) explainTypes(tree.tpe, pt) } typeErrorTree(tree, tree.tpe, pt) } } } /** * @param tree ... * @param mode ... * @param pt ... * @return ... */ def instantiate(tree: Tree, mode: Int, pt: Type): Tree = { val tparams = context.undetparams context.undetparams = List() inferExprInstance(tree, tparams, pt) adapt(tree, mode, pt) } /** * @param qual ... * @param name ... * @param tp ... * @return ... */ def adaptToMember(qual: Tree, name: Name, tp: Type): Tree = { val qtpe = qual.tpe.widen if (qual.isTerm && ((qual.symbol eq null) || !qual.symbol.isTerm || qual.symbol.isValue) && phase.id <= currentRun.typerPhase.id && !qtpe.isError && !tp.isError && qtpe.typeSymbol != AllRefClass && qtpe.typeSymbol != AllClass && qtpe != WildcardType) { val coercion = inferView(qual.pos, qtpe, name, tp, true) if (coercion != EmptyTree) typedQualifier(atPos(qual.pos)(Apply(coercion, List(qual)))) else qual } else qual } def adaptToName(qual: Tree, name: Name) = if (member(qual, name) != NoSymbol) qual else adaptToMember(qual, name, WildcardType) private def typePrimaryConstrBody(clazz : Symbol, cbody: Tree, tparams: List[Symbol], enclTparams: List[Symbol], vparamss: List[List[ValDef]]): Tree = { // XXX: see about using the class's symbol.... enclTparams foreach (sym => context.scope.enter(sym)) namer.enterValueParams(context.owner, vparamss) typed(cbody) } def parentTypes(templ: Template): List[Tree] = if (templ.parents.isEmpty) List() else try { val clazz = context.owner // Normalize supertype and mixins so that supertype is always a class, not a trait. var supertpt = typedTypeConstructor(templ.parents.head) val firstParent = supertpt.tpe.typeSymbol var mixins = templ.parents.tail map typedType // If first parent is a trait, make it first mixin and add its superclass as first parent while ((supertpt.tpe.typeSymbol ne null) && supertpt.tpe.typeSymbol.initialize.isTrait) { val supertpt1 = typedType(supertpt) if (!supertpt1.tpe.isError) { mixins = supertpt1 :: mixins supertpt = TypeTree(supertpt1.tpe.parents.head) setOriginal supertpt /* setPos supertpt.pos */ } } // Determine // - supertparams: Missing type parameters from supertype // - supertpe: Given supertype, polymorphic in supertparams val supertparams = if (supertpt.hasSymbol) supertpt.symbol.typeParams else List() var supertpe = supertpt.tpe if (!supertparams.isEmpty) supertpe = PolyType(supertparams, appliedType(supertpe, supertparams map (_.tpe))) // A method to replace a super reference by a New in a supercall def transformSuperCall(scall: Tree): Tree = (scall: @unchecked) match { case Apply(fn, args) => copy.Apply(scall, transformSuperCall(fn), args map (_.duplicate)) case Select(Super(_, _), nme.CONSTRUCTOR) => copy.Select( scall, New(TypeTree(supertpe) setOriginal supertpt) setType supertpe setPos supertpt.pos, nme.CONSTRUCTOR) } treeInfo.firstConstructor(templ.body) match { case constr @ DefDef(_, _, _, vparamss, _, cbody @ Block(cstats, cunit)) => // Convert constructor body to block in environment and typecheck it val cstats1: List[Tree] = cstats map (_.duplicate) val scall = if (cstats.isEmpty) EmptyTree else cstats.last val cbody1 = scall match { case Apply(_, _) => copy.Block(cbody, cstats1.init, if (supertparams.isEmpty) cunit.duplicate else transformSuperCall(scall)) case _ => copy.Block(cbody, cstats1, cunit.duplicate) } val outercontext = context.outer assert(clazz != NoSymbol) val cscope = outercontext.makeNewScope(constr, outercontext.owner)(ParentTypesScopeKind(clazz)) val cbody2 = newTyper(cscope) // called both during completion AND typing. .typePrimaryConstrBody(clazz, cbody1, supertparams, clazz.unsafeTypeParams, vparamss map (_.map(_.duplicate))) scall match { case Apply(_, _) => val sarg = treeInfo.firstArgument(scall) if (sarg != EmptyTree && supertpe.typeSymbol != firstParent) error(sarg.pos, firstParent+" is a trait; does not take constructor arguments") if (!supertparams.isEmpty) supertpt = TypeTree(cbody2.tpe) setPos supertpt.pos case _ => if (!supertparams.isEmpty) error(supertpt.pos, "missing type arguments") } List.map2(cstats1, treeInfo.preSuperFields(templ.body)) { (ldef, gdef) => gdef.tpt.tpe = ldef.symbol.tpe } case _ => if (!supertparams.isEmpty) error(supertpt.pos, "missing type arguments")
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?