diff options
author | Martin Odersky <odersky@gmail.com> | 2014-03-06 19:01:42 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2014-03-07 11:15:38 +0100 |
commit | 6aa88d6dfe501a695183761c2b5f4bd201cdf2c0 (patch) | |
tree | becb8b13bb8d94c9aac7e8e280cde50491ba3efa /src/dotty/tools/dotc/typer | |
parent | dbd5a4d22b6164b708a87b508d9b9f135b44a3ee (diff) | |
download | dotty-6aa88d6dfe501a695183761c2b5f4bd201cdf2c0.tar.gz dotty-6aa88d6dfe501a695183761c2b5f4bd201cdf2c0.tar.bz2 dotty-6aa88d6dfe501a695183761c2b5f4bd201cdf2c0.zip |
Main Typer reorg.
Common code between tpd and Typer has been factored out into class TypeAssigner.
Diffstat (limited to 'src/dotty/tools/dotc/typer')
-rw-r--r-- | src/dotty/tools/dotc/typer/Applications.scala | 41 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Checking.scala | 13 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Namer.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/TypeAssigner.scala | 317 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 266 |
5 files changed, 406 insertions, 233 deletions
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 26325e57e..cf0d7d0a1 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -398,8 +398,9 @@ trait Applications extends Compatibility { self: Typer => val result = { var typedArgs = typedArgBuf.toList - val ownType = - if (!success) ErrorType + val app0 = cpy.Apply(app, normalizedFun, typedArgs) + val app1 = + if (!success) app0.withType(ErrorType) else { if (!sameSeq(args, orderedArgs)) { // need to lift arguments to maintain evaluation order in the @@ -411,9 +412,9 @@ trait Applications extends Compatibility { self: Typer => } if (sameSeq(typedArgs, args)) // trick to cut down on tree copying typedArgs = args.asInstanceOf[List[Tree]] - methodType.instantiate(typedArgs.tpes) + assignType(app0, normalizedFun, typedArgs) } - wrapDefs(liftedDefs, cpy.Apply(app, normalizedFun, typedArgs).withType(ownType)) + wrapDefs(liftedDefs, app1) } } @@ -513,21 +514,11 @@ trait Applications extends Compatibility { self: Typer => def typedTypeApply(tree: untpd.TypeApply, pt: Type)(implicit ctx: Context): Tree = track("typedTypeApply") { val typedArgs = tree.args mapconserve (typedType(_)) val typedFn = typedExpr(tree.fun, PolyProto(typedArgs.tpes, pt)) - val ownType = typedFn.tpe.widen match { - case pt: PolyType => - checkBounds(typedArgs, pt, tree.pos) - val argTypes = typedArgs.tpes - if (argTypes.length == pt.paramNames.length) - pt.resultType.substParams(pt, typedArgs.tpes) - else { - ctx.error(i"wrong number of type parameters for ${typedFn.tpe}; expected: ${pt.paramNames.length}", tree.pos) - ErrorType - } + typedFn.tpe.widen match { + case pt: PolyType => checkBounds(typedArgs, pt, tree.pos) case _ => - ctx.error(s"${err.exprStr(typedFn)} does not take type parameters", tree.pos) - ErrorType } - cpy.TypeApply(tree, typedFn, typedArgs).withType(ownType) + assignType(cpy.TypeApply(tree, typedFn, typedArgs), typedFn, typedArgs) } def typedUnApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = track("typedUnApply") { @@ -577,13 +568,13 @@ trait Applications extends Compatibility { self: Typer => /** Produce a typed qual.unappy or qual.unappySeq tree, or * else if this fails follow a type alias and try again. */ - val unapply = trySelectUnapply(qual) { sel => + val unapplyFn = trySelectUnapply(qual) { sel => val qual1 = followTypeAlias(qual) if (qual1.isEmpty) notAnExtractor(sel) else trySelectUnapply(qual1)(_ => notAnExtractor(sel)) } - def fromScala2x = unapply.symbol.exists && (unapply.symbol.owner is Scala2x) + def fromScala2x = unapplyFn.symbol.exists && (unapplyFn.symbol.owner is Scala2x) def unapplyArgs(unapplyResult: Type)(implicit ctx: Context): List[Type] = { def extractorMemberType(tp: Type, name: Name) = { @@ -609,7 +600,7 @@ trait Applications extends Compatibility { self: Typer => // println(s"unapply $unapplyResult ${extractorMemberType(unapplyResult, nme.isDefined)}") if (extractorMemberType(unapplyResult, nme.isDefined) isRef defn.BooleanClass) { if (getTp.exists) - if (unapply.symbol.name == nme.unapplySeq) { + if (unapplyFn.symbol.name == nme.unapplySeq) { val seqArg = boundsToHi(getTp.firstBaseArgInfo(defn.SeqClass)) if (seqArg.exists) return args map Function.const(seqArg) } @@ -634,7 +625,7 @@ trait Applications extends Compatibility { self: Typer => case _ => false } - unapply.tpe.widen match { + unapplyFn.tpe.widen match { case mt: MethodType if mt.paramTypes.length == 1 && !mt.isDependent => val unapplyArgType = mt.paramTypes.head unapp.println(s"unapp arg tpe = ${unapplyArgType.show}, pt = ${pt.show}") @@ -661,7 +652,7 @@ trait Applications extends Compatibility { self: Typer => // can open unsoundness holes. See SI-7952 for an example of the hole this opens. if (ctx.settings.verbose.value) ctx.warning(msg, tree.pos) } else { - unapp.println(s" ${unapply.symbol.owner} ${unapply.symbol.owner is Scala2x}") + unapp.println(s" ${unapplyFn.symbol.owner} ${unapplyFn.symbol.owner is Scala2x}") ctx.error(msg, tree.pos) } case _ => @@ -677,7 +668,7 @@ trait Applications extends Compatibility { self: Typer => } val dummyArg = dummyTreeOfType(unapplyArgType) - val unapplyApp = typedExpr(untpd.TypedSplice(Apply(unapply, dummyArg :: Nil))) + val unapplyApp = typedExpr(untpd.TypedSplice(Apply(unapplyFn, dummyArg :: Nil))) val unapplyImplicits = unapplyApp match { case Apply(Apply(unapply, `dummyArg` :: Nil), args2) => assert(args2.nonEmpty); args2 case Apply(unapply, `dummyArg` :: Nil) => Nil @@ -695,12 +686,12 @@ trait Applications extends Compatibility { self: Typer => List.fill(argTypes.length - args.length)(WildcardType) } val unapplyPatterns = (bunchedArgs, argTypes).zipped map (typed(_, _)) - val result = cpy.UnApply(tree, unapply, unapplyImplicits, unapplyPatterns) withType ownType + val result = assignType(cpy.UnApply(tree, unapplyFn, unapplyImplicits, unapplyPatterns), ownType) unapp.println(s"unapply patterns = $unapplyPatterns") if ((ownType eq pt) || ownType.isError) result else Typed(result, TypeTree(ownType)) case tp => - val unapplyErr = if (tp.isError) unapply else notAnExtractor(unapply) + val unapplyErr = if (tp.isError) unapplyFn else notAnExtractor(unapplyFn) val typedArgsErr = args mapconserve (typed(_, defn.AnyType)) cpy.UnApply(tree, unapplyErr, Nil, typedArgsErr) withType ErrorType } diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala index 5c21584bd..25e6a7aa7 100644 --- a/src/dotty/tools/dotc/typer/Checking.scala +++ b/src/dotty/tools/dotc/typer/Checking.scala @@ -5,7 +5,7 @@ package typer import core._ import ast._ import Contexts._, Types._, Flags._, Denotations._, Names._, StdNames._, NameOps._, Symbols._ -import Trees._ +import Trees._, ProtoTypes._ import Constants._ import Scopes._ import annotation.unchecked @@ -20,6 +20,7 @@ import collection.mutable trait NoChecking { import tpd._ + def checkValue(tree: Tree, proto: Type)(implicit ctx: Context): tree.type = tree def checkBounds(args: List[tpd.Tree], poly: PolyType, pos: Position)(implicit ctx: Context): Unit = () def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit = () def checkClassTypeWithStablePrefix(tp: Type, pos: Position, traitReq: Boolean)(implicit ctx: Context): Type = tp @@ -33,6 +34,16 @@ trait Checking extends NoChecking { import tpd._ + /** Check that Java statics and packages can only be used in selections. + */ + override def checkValue(tree: Tree, proto: Type)(implicit ctx: Context): tree.type = { + if (!proto.isInstanceOf[SelectionProto]) { + val sym = tree.tpe.termSymbol + if ((sym is Package) || (sym is JavaModule)) ctx.error(i"$sym is not a value", tree.pos) + } + tree + } + /** Check that type arguments `args` conform to corresponding bounds in `poly` */ override def checkBounds(args: List[tpd.Tree], poly: PolyType, pos: Position)(implicit ctx: Context): Unit = for ((arg, bounds) <- args zip poly.paramBounds) { diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index 6e91e4754..c24021936 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -591,7 +591,7 @@ class Namer { typer: Typer => (paramSymss.isEmpty || paramSymss.head.nonEmpty && (paramSymss.head.head is Implicit))) paramSymss = Nil :: paramSymss val restpe1 = // try to make anonymous functions non-dependent, so that they can be used in closures - if (name == nme.ANON_FUN) tpd.avoid(restpe, paramSymss.flatten) + if (name == nme.ANON_FUN) avoid(restpe, paramSymss.flatten) else restpe val monotpe = (paramSymss :\ restpe1) { (params, restpe) => diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index e711ee949..6eeec56e1 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -4,15 +4,182 @@ package typer import core._ import ast._ -import Scopes._, Contexts._, Constants._, Types._, Symbols._ +import Scopes._, Contexts._, Constants._, Types._, Symbols._, Names._, Flags._, Decorators._ +import ErrorReporting._, Annotations._, Denotations._, SymDenotations._, StdNames._ +import util.Positions._ +import config.Printers._ -trait TypeAssigner extends NoChecking { +trait TypeAssigner { + import tpd._ - def assignType(tree: untpd.New)(implicit ctx: Context) = { - checkClassTypeWithStablePrefix(tree.tpt.tpe, tree.tpt.pos, traitReq = false) - tree.withType(tree.tpt.tpe) + /** The enclosing class, except if we are in a super call, in which case + * it is the next outer one. + */ + def effectiveEnclosingClass(implicit ctx: Context) = { + val enclClass = ctx.owner.enclosingClass + if ((ctx.mode is Mode.InSuperCall) && enclClass.exists) enclClass.owner.enclosingClass + else enclClass } + /** The qualifying class of a this or super with prefix `qual` (which might be empty). + * @param packageOk The qualifier may refer to a package. + */ + def qualifyingClass(tree: untpd.Tree, qual: Name, packageOK: Boolean)(implicit ctx: Context): Symbol = { + effectiveEnclosingClass.ownersIterator.find(o => qual.isEmpty || o.isClass && o.name == qual) match { + case Some(c) if packageOK || !(c is Package) => + c + case _ => + ctx.error( + if (qual.isEmpty) tree.show + " can be used only in a class, object, or template" + else qual.show + " is not an enclosing class", tree.pos) + NoSymbol + } + } + + def avoid(tp: Type, syms: => List[Symbol])(implicit ctx: Context): Type = { + val widenMap = new TypeMap { + lazy val forbidden = syms.toSet + def toAvoid(tp: Type): Boolean = tp match { + case tp: TermRef => + val sym = tp.symbol + sym.exists && ( + sym.owner.isTerm && (forbidden contains sym) + || !(sym.owner is Package) && toAvoid(tp.prefix) + ) + case _ => + false + } + def apply(tp: Type) = tp match { + case tp: TermRef if toAvoid(tp) && variance > 0 => + apply(tp.info) + case tp: TypeRef if toAvoid(tp.prefix) => + tp.info match { + case TypeAlias(ref) => apply(ref) + case _ => mapOver(tp) + } + case tp: RefinedType => + val tp1 @ RefinedType(parent1, _) = mapOver(tp) + if (tp1.refinedInfo existsPart toAvoid) { + typr.println(s"dropping refinement from $tp1") + parent1 + } + else tp1 + case _ => + mapOver(tp) + } + } + widenMap(tp) + } + + def localSyms(stats: List[tpd.Tree])(implicit ctx: Context): List[Symbol] = + for (stat <- stats if stat.isDef) yield stat.symbol + + def seqToRepeated(tree: Tree)(implicit ctx: Context): Tree = + Typed(tree, TypeTree(tree.tpe.widen.translateParameterized(defn.SeqClass, defn.RepeatedParamClass))) + + /** A denotation exists really if it exists and does not point to a stale symbol. */ + final def reallyExists(denot: Denotation)(implicit ctx: Context): Boolean = try + denot match { + case denot: SymDenotation => + denot.exists && { + denot.ensureCompleted + !denot.isAbsent + } + case denot: SingleDenotation => + val sym = denot.symbol + (sym eq NoSymbol) || reallyExists(sym.denot) + case _ => + true + } + catch { + case ex: StaleSymbol => false + } + + /** If `tpe` is a named type, check that its denotation is accessible in the + * current context. Return the type with those alternatives as denotations + * which are accessible. + */ + def ensureAccessible(tpe: Type, superAccess: Boolean, pos: Position)(implicit ctx: Context): Type = { + def test(tpe: Type, firstTry: Boolean): Type = tpe match { + case tpe: NamedType => + val pre = tpe.prefix + val name = tpe.name + val d = tpe.denot.accessibleFrom(pre, superAccess) + if (!d.exists) { + // it could be that we found an inaccessbile private member, but there is + // an inherited non-private member with the same name and signature. + val d2 = pre.nonPrivateMember(name) + if (reallyExists(d2) && firstTry) test(pre.select(name, d2), false) + else { + val alts = tpe.denot.alternatives.map(_.symbol).filter(_.exists) + val what = alts match { + case Nil => + name.toString + case sym :: Nil => + if (sym.owner == pre.typeSymbol) sym.show else sym.showLocated + case _ => + i"none of the overloaded alternatives named $name" + } + val where = if (ctx.owner.exists) s" from ${ctx.owner.enclosingClass}" else "" + val whyNot = new StringBuffer + alts foreach (_.isAccessibleFrom(pre, superAccess, whyNot)) + if (!tpe.isError) + ctx.error(i"$what cannot be accessed as a member of $pre$where.$whyNot", pos) + ErrorType + } + } else if (d.symbol is TypeParamAccessor) // always dereference type param accessors + ensureAccessible(d.info.bounds.hi, superAccess, pos) + else + tpe withDenot d + case _ => + tpe + } + test(tpe, true) + } + + /** The type of a selection with `name` of a tree with type `site`. + */ + def selectionType(site: Type, name: Name, pos: Position)(implicit ctx: Context): Type = { + val mbr = site.member(name) + if (reallyExists(mbr)) site.select(name, mbr) + else { + if (!site.isErroneous) { + ctx.error( + if (name == nme.CONSTRUCTOR) i"$site does not have a constructor" + else i"$name is not a member of $site", pos) + } + ErrorType + } + } + + /** The selection type, which is additionally checked for accessibility. + */ + def accessibleSelectionType(tree: untpd.RefTree, qual1: Tree)(implicit ctx: Context): Type = { + val ownType = selectionType(qual1.tpe.widenIfUnstable, tree.name, tree.pos) + ensureAccessible(ownType, qual1.isInstanceOf[Super], tree.pos) + } + + /** Type assignment method. Each method takes as parameters + * - an untpd.Tree to which it assigns a type, + * - typed child trees it needs to access to cpmpute that type, + * - any further information it needs to access to compute that type. + */ + + def assignType(tree: untpd.Ident, rawType: Type)(implicit ctx: Context) = { + tree.withType(if (tree.isType) rawType else rawType.underlyingIfRepeated) + } + + def assignType(tree: untpd.Select, qual: Tree)(implicit ctx: Context) = { + tree.withType(accessibleSelectionType(tree, qual)) + } + + def assignType(tree: untpd.SelectFromTypeTree, qual: Tree)(implicit ctx: Context) = { + tree.withType(accessibleSelectionType(tree, qual)) + } + + def assignType(tree: untpd.New, tpt: Tree)(implicit ctx: Context) = + tree.withType(tpt.tpe) + def assignType(tree: untpd.Literal)(implicit ctx: Context) = tree.withType { tree.const.tag match { @@ -21,6 +188,146 @@ trait TypeAssigner extends NoChecking { case _ => ConstantType(tree.const) } } + + def assignType(tree: untpd.This)(implicit ctx: Context) = { + val cls = qualifyingClass(tree, tree.qual, packageOK = false) + tree.withType(cls.thisType) + } + + def assignType(tree: untpd.Super, qual: Tree, inConstrCall: Boolean)(implicit ctx: Context) = { + val mix = tree.mix + val cls = qual.tpe.widen.typeSymbol + + def findMixinSuper(site: Type): Type = site.parents filter (_.name == mix) match { + case p :: Nil => + p + case Nil => + errorType(i"$mix does not name a parent class of $cls", tree.pos) + case p :: q :: _ => + errorType(s"ambiguous parent class qualifier", tree.pos) + } + val owntype = + if (!mix.isEmpty) findMixinSuper(cls.info) + else if (inConstrCall) cls.info.firstParent + else cls.info.parents.reduceLeft((x: Type, y: Type) => AndType(x, y)) + tree.withType(SuperType(cls.thisType, owntype)) + } + + def assignType(tree: untpd.Apply, fn: Tree, args: List[Tree])(implicit ctx: Context) = { + val ownType = fn.tpe.widen match { + case fntpe @ MethodType(_, ptypes) => + if (sameLength(ptypes, args)) fntpe.instantiate(args.tpes) + else errorType(s"wrong number of type parameters for ${fn.tpe}; expected: ${ptypes.length}", tree.pos) + case t => + errorType(s"${err.exprStr(fn)} does not take type parameters", tree.pos) + } + tree.withType(ownType) + } + + def assignType(tree: untpd.TypeApply, fn: Tree, args: List[Tree])(implicit ctx: Context) = { + val ownType = fn.tpe.widen match { + case pt: PolyType => + val argTypes = args.tpes + if (sameLength(argTypes, pt.paramNames)) pt.instantiate(args.tpes) + else errorType(i"wrong number of type parameters for ${fn.tpe}; expected: ${pt.paramNames.length}", tree.pos) + case _ => + errorType(s"${err.exprStr(fn)} does not take type parameters", tree.pos) + } + tree.withType(ownType) + } + + def assignType(tree: untpd.Pair, left: Tree, right: Tree)(implicit ctx: Context) = + tree.withType(defn.PairType.appliedTo(left.tpe :: right.tpe :: Nil)) + + def assignType(tree: untpd.Typed, tpt: Tree)(implicit ctx: Context) = + tree.withType(tpt.tpe) + + def assignType(tree: untpd.NamedArg, arg: Tree)(implicit ctx: Context) = + tree.withType(arg.tpe) + + def assignType(tree: untpd.Assign)(implicit ctx: Context) = + tree.withType(defn.UnitType) + + def assignType(tree: untpd.Block, stats: List[Tree], expr: Tree)(implicit ctx: Context) = + tree.withType(avoid(expr.tpe, localSyms(stats))) + + def assignType(tree: untpd.If, thenp: Tree, elsep: Tree)(implicit ctx: Context) = + tree.withType(thenp.tpe | elsep.tpe) + + def assignType(tree: untpd.Closure, meth: Tree, target: Tree)(implicit ctx: Context) = + tree.withType(if (target.isEmpty) meth.tpe.widen.toFunctionType else target.tpe) + + def assignType(tree: untpd.CaseDef, body: Tree)(implicit ctx: Context) = + tree.withType(body.tpe) + + def assignType(tree: untpd.Match, cases: List[CaseDef])(implicit ctx: Context) = + tree.withType(ctx.typeComparer.lub(cases.tpes)) + + def assignType(tree: untpd.Return)(implicit ctx: Context) = + tree.withType(defn.NothingType) + + def assignType(tree: untpd.Try, expr: Tree, handler: Tree)(implicit ctx: Context) = { + val handlerTypeArgs = handler.tpe.baseArgTypesHi(defn.FunctionClass(1)) + tree.withType(if (handlerTypeArgs.nonEmpty) expr.tpe | handlerTypeArgs(1) else expr.tpe) + } + + def assignType(tree: untpd.Throw)(implicit ctx: Context) = + tree.withType(defn.NothingType) + + def assignType(tree: untpd.SeqLiteral, elems: List[Tree])(implicit ctx: Context) = + tree.withType(defn.SeqType.appliedTo(ctx.typeComparer.lub(elems.tpes))) + + def assignType(tree: untpd.SingletonTypeTree, ref: Tree)(implicit ctx: Context) = + tree.withType(ref.tpe) + + def assignType(tree: untpd.AndTypeTree, left: Tree, right: Tree)(implicit ctx: Context) = + tree.withType(left.tpe & right.tpe) + + def assignType(tree: untpd.OrTypeTree, left: Tree, right: Tree)(implicit ctx: Context) = + tree.withType(left.tpe | right.tpe) + + // RefinedTypeTree is missing, handled specially in Typer and Unpickler. + + def assignType(tree: untpd.AppliedTypeTree, tycon: Tree, args: List[Tree])(implicit ctx: Context) = { + val tparams = tycon.tpe.typeParams + val ownType = + if (sameLength(tparams, args)) tycon.tpe.appliedTo(args.tpes) + else errorType(i"wrong number of type arguments for ${tycon.tpe}, should be ${tparams.length}", tree.pos) + tree.withType(ownType) + } + + def assignType(tree: untpd.ByNameTypeTree, result: Tree)(implicit ctx: Context) = + tree.withType(ExprType(result.tpe)) + + def assignType(tree: untpd.TypeBoundsTree, lo: Tree, hi: Tree)(implicit ctx: Context) = + tree.withType(TypeBounds(lo.tpe, hi.tpe)) + + def assignType(tree: untpd.Bind, sym: TermSymbol)(implicit ctx: Context) = + tree.withType(TermRef(NoPrefix, sym)) + + def assignType(tree: untpd.Alternative, trees: List[Tree])(implicit ctx: Context) = + tree.withType(ctx.typeComparer.lub(trees.tpes)) + + def assignType(tree: untpd.UnApply, proto: Type)(implicit ctx: Context) = + tree.withType(proto) + + def assignType(tree: untpd.ValDef, sym: Symbol)(implicit ctx: Context) = + tree.withType(if (sym.exists) sym.valRef else NoType) + + def assignType(tree: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = + tree.withType(sym.termRefWithSig) + + def assignType(tree: untpd.TypeDef, sym: Symbol)(implicit ctx: Context) = + tree.withType(sym.typeRef) + + def assignType(tree: untpd.Import, sym: Symbol)(implicit ctx: Context) = + tree.withType(sym.termRef) + + def assignType(tree: untpd.Annotated, annot: Tree, arg: Tree)(implicit ctx: Context) = + tree.withType(AnnotatedType(Annotation(annot), arg.tpe)) + + def assignType(tree: untpd.PackageDef, pid: Tree)(implicit ctx: Context) = + tree.withType(pid.symbol.valRef) } object TypeAssigner extends TypeAssigner diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index c545641a0..51eba3b02 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -62,120 +62,6 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit */ private var importedFromRoot: Set[Symbol] = Set() - /** A denotation exists really if it exists and does not point to a stale symbol. */ - final def reallyExists(denot: Denotation)(implicit ctx: Context): Boolean = try - denot match { - case denot: SymDenotation => - denot.exists && { - denot.ensureCompleted - !denot.isAbsent - } - case denot: SingleDenotation => - val sym = denot.symbol - (sym eq NoSymbol) || reallyExists(sym.denot) - case _ => - true - } - catch { - case ex: StaleSymbol => false - } - - /** The type of a selection with `name` of a tree with type `site`. - */ - def selectionType(site: Type, name: Name, pos: Position)(implicit ctx: Context): Type = { - val mbr = site.member(name) - if (reallyExists(mbr)) site.select(name, mbr) - else { - if (!site.isErroneous) { - ctx.error( - if (name == nme.CONSTRUCTOR) i"$site does not have a constructor" - else i"$name is not a member of $site", pos) - } - ErrorType - } - } - - /** The selection type, which is additionally checked for accessibility. - */ - def checkedSelectionType(qual1: Tree, tree: untpd.RefTree)(implicit ctx: Context): Type = { - val ownType = selectionType(qual1.tpe.widenIfUnstable, tree.name, tree.pos) - checkAccessible(ownType, qual1.isInstanceOf[Super], tree.pos) - } - - /** Check that Java statics and packages can only be used in selections. - */ - def checkValue(tpe: Type, proto: Type, pos: Position)(implicit ctx: Context): Unit = - if (!proto.isInstanceOf[SelectionProto]) { - val sym = tpe.termSymbol - if ((sym is Package) || (sym is JavaModule)) ctx.error(i"$sym is not a value", pos) - } - - /** If `tpe` is a named type, check that its denotation is accessible in the - * current context. Return the type with those alternatives as denotations - * which are accessible. - */ - def checkAccessible(tpe: Type, superAccess: Boolean, pos: Position)(implicit ctx: Context): Type = { - def test(tpe: Type, firstTry: Boolean): Type = tpe match { - case tpe: NamedType => - val pre = tpe.prefix - val name = tpe.name - val d = tpe.denot.accessibleFrom(pre, superAccess) - if (!d.exists) { - // it could be that we found an inaccessbile private member, but there is - // an inherited non-private member with the same name and signature. - val d2 = pre.nonPrivateMember(name) - if (reallyExists(d2) && firstTry) test(pre.select(name, d2), false) - else { - val alts = tpe.denot.alternatives.map(_.symbol).filter(_.exists) - val what = alts match { - case Nil => - name.toString - case sym :: Nil => - if (sym.owner == pre.typeSymbol) sym.show else sym.showLocated - case _ => - i"none of the overloaded alternatives named $name" - } - val where = if (ctx.owner.exists) s" from ${ctx.owner.enclosingClass}" else "" - val whyNot = new StringBuffer - alts foreach (_.isAccessibleFrom(pre, superAccess, whyNot)) - if (!tpe.isError) - ctx.error(i"$what cannot be accessed as a member of $pre$where.$whyNot", pos) - ErrorType - } - } else if (d.symbol is TypeParamAccessor) // always dereference type param accessors - checkAccessible(d.info.bounds.hi, superAccess, pos) - else - tpe withDenot d - case _ => - tpe - } - test(tpe, true) - } - - /** The enclosing class, except if we are in a super call, in which case - * it is the next outer one. - */ - def effectiveEnclosingClass(implicit ctx: Context) = { - val enclClass = ctx.owner.enclosingClass - if ((ctx.mode is Mode.InSuperCall) && enclClass.exists) enclClass.owner.enclosingClass - else enclClass - } - - /** The qualifying class of a this or super with prefix `qual` (which might be empty). - * @param packageOk The qualifier may refer to a package. - */ - def qualifyingClass(tree: untpd.Tree, qual: Name, packageOK: Boolean)(implicit ctx: Context): Symbol = { - effectiveEnclosingClass.ownersIterator.find(o => qual.isEmpty || o.isClass && o.name == qual) match { - case Some(c) if packageOK || !(c is Package) => - c - case _ => - ctx.error( - if (qual.isEmpty) tree.show + " can be used only in a class, object, or template" - else qual.show + " is not an enclosing class", tree.pos) - NoSymbol - } - } - /** Attribute an identifier consisting of a simple name or wildcard * * @param tree The tree representing the identifier. @@ -366,50 +252,38 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val rawType = try findRef(NoType, BindingPrec.nothingBound, NoContext) finally importedFromRoot = saved - checkValue(rawType, pt, tree.pos) val ownType = if (rawType.exists) - checkAccessible(rawType, superAccess = false, tree.pos) + ensureAccessible(rawType, superAccess = false, tree.pos) else { error(i"not found: $kind$name", tree.pos) ErrorType } - tree.withType(ownType.underlyingIfRepeated) + checkValue(tree.withType(ownType.underlyingIfRepeated), pt) } def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = track("typedSelect") { val qual1 = typedExpr(tree.qualifier, selectionProto(tree.name, pt, this)) - val ownType = checkedSelectionType(qual1, tree) - checkValue(ownType, pt, tree.pos) - cpy.Select(tree, qual1, tree.name).withType(ownType) + checkValue(assignType(cpy.Select(tree, qual1, tree.name), qual1), pt) + } + + def typedSelectFromTypeTree(tree: untpd.SelectFromTypeTree, pt: Type)(implicit ctx: Context): SelectFromTypeTree = track("typedSelectFromTypeTree") { + val qual1 = typedType(tree.qualifier, selectionProto(tree.name, pt, this)) + assignType(cpy.SelectFromTypeTree(tree, qual1, tree.name), qual1) } def typedThis(tree: untpd.This)(implicit ctx: Context): Tree = track("typedThis") { - val cls = qualifyingClass(tree, tree.qual, packageOK = false) - tree.withType(cls.thisType) + assignType(tree) } def typedSuper(tree: untpd.Super, pt: Type)(implicit ctx: Context): Tree = track("typedSuper") { - val mix = tree.mix val qual1 = typed(tree.qual) - val cls = qual1.tpe.widen.typeSymbol - - def findMixinSuper(site: Type): Type = site.parents filter (_.name == mix) match { - case p :: Nil => - p - case Nil => - errorType(i"$mix does not name a parent class of $cls", tree.pos) - case p :: q :: _ => - errorType(s"ambiguous parent class qualifier", tree.pos) + val inConstrCall = pt match { + case pt: SelectionProto if pt.name == nme.CONSTRUCTOR => true + case _ => false } - val owntype = - if (!mix.isEmpty) findMixinSuper(cls.info) - else pt match { - case pt: SelectionProto if pt.name == nme.CONSTRUCTOR => cls.info.firstParent - case _ => cls.info.parents.reduceLeft((x: Type, y: Type) => AndType(x, y)) - } - cpy.Super(tree, qual1, mix).withType(SuperType(cls.thisType, owntype)) + assignType(cpy.Super(tree, qual1, tree.mix), qual1, inConstrCall) } def typedLiteral(tree: untpd.Literal)(implicit ctx: Context) = track("typedLiteral") { @@ -425,7 +299,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit typed(cpy.Block(tree, clsDef :: Nil, New(Ident(x), Nil)), pt) case _ => val tpt1 = typedType(tree.tpt) - assignType(cpy.New(tree, tpt1)) + checkClassTypeWithStablePrefix(tpt1.tpe, tpt1.pos, traitReq = false) + assignType(cpy.New(tree, tpt1), tpt1) // todo in a later phase: checkInstantiatable(cls, tpt1.pos) } } @@ -437,7 +312,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } val left1 = typed(tree.left, leftProto) val right1 = typed(tree.right, rightProto) - cpy.Pair(tree, left1, right1).withType(defn.PairType.appliedTo(left1.tpe :: right1.tpe :: Nil)) + assignType(cpy.Pair(tree, left1, right1), left1, right1) } def typedTyped(tree: untpd.Typed, pt: Type)(implicit ctx: Context): Tree = track("typedTyped") { @@ -446,7 +321,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val expr1 = if (isWildcard) tree.expr withType tpt1.tpe else typedExpr(tree.expr, tpt1.tpe) - cpy.Typed(tree, expr1, tpt1).withType(tpt1.tpe) + assignType(cpy.Typed(tree, expr1, tpt1), tpt1) } tree.expr match { case id: untpd.Ident if (ctx.mode is Mode.Pattern) && isVarPattern(id) => @@ -465,7 +340,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def typedNamedArg(tree: untpd.NamedArg, pt: Type)(implicit ctx: Context) = track("typedNamedArg") { val arg1 = typed(tree.arg, pt) - cpy.NamedArg(tree, tree.name, arg1).withType(arg1.tpe) + assignType(cpy.NamedArg(tree, tree.name, arg1), arg1) } def typedAssign(tree: untpd.Assign, pt: Type)(implicit ctx: Context) = track("typedAssign") { @@ -481,7 +356,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def lhs1 = typed(untpd.TypedSplice(lhsCore)) lhsCore.tpe match { case ref: TermRef if ref.symbol is (Mutable, butNot = Accessor) => - cpy.Assign(tree, lhs1, typed(tree.rhs, ref.info)).withType(defn.UnitType) + assignType(cpy.Assign(tree, lhs1, typed(tree.rhs, ref.info))) case _ => def reassignmentToVal = errorTree(cpy.Assign(tree, lhsCore, typed(tree.rhs, lhs1.tpe.widen)), @@ -494,7 +369,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit lhsCore match { case lhsCore: RefTree if setter.exists => val setterTypeRaw = pre select (setterName, setter) - val setterType = checkAccessible(setterTypeRaw, isSuperSelection(lhsCore), tree.pos) + val setterType = ensureAccessible(setterTypeRaw, isSuperSelection(lhsCore), tree.pos) val lhs2 = lhsCore.withName(setterName).withType(setterType) typed(cpy.Apply(tree, untpd.TypedSplice(lhs2), tree.rhs :: Nil)) case _ => @@ -511,8 +386,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val exprCtx = index(tree.stats) val stats1 = typedStats(tree.stats, ctx.owner) val expr1 = typedExpr(tree.expr, pt)(exprCtx) - val result = cpy.Block(tree, stats1, expr1).withType(avoid(expr1.tpe, localSyms(stats1))) - checkNoLocalRefs(result, pt) + ensureNoLocalRefs(assignType(cpy.Block(tree, stats1, expr1), stats1, expr1), pt) } /** Check that block's type can be expressed without references to locally defined @@ -522,17 +396,18 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit * 2. If (1) fails, force all type variables so that the block's type is * fully defined and try again. */ - def checkNoLocalRefs(block: Block, pt: Type, forcedDefined: Boolean = false)(implicit ctx: Context): Tree = { + private def ensureNoLocalRefs(block: Block, pt: Type, forcedDefined: Boolean = false)(implicit ctx: Context): Tree = { val Block(stats, expr) = block val leaks = CheckTrees.escapingRefs(block) if (leaks.isEmpty) block else if (isFullyDefined(pt, ForceDegree.all)) { - val expr1 = typed(untpd.Typed(untpd.TypedSplice(expr), untpd.TypeTree(pt))) - untpd.Block(stats, expr1) withType expr1.tpe + val expr1 = Typed(expr, TypeTree(pt)) + cpy.Block(block, stats, expr1) withType expr1.tpe // no assignType here because avoid is redundant } else if (!forcedDefined) { fullyDefinedType(block.tpe, "block", block.pos) - val block1 = block.withType(avoid(block.tpe, localSyms(stats))) - checkNoLocalRefs(block1, pt, forcedDefined = true) + val expr1 = Typed(expr, TypeTree(avoid(block.tpe, localSyms(stats)))) + val block1 = cpy.Block(block, stats, expr1) withType expr1.tpe // no assignType here because avoid is already done + ensureNoLocalRefs(block1, pt, forcedDefined = true) } else errorTree(block, i"local definition of ${leaks.head.name} escapes as part of block's type ${block.tpe}"/*; full type: ${result.tpe.toString}"*/) @@ -542,7 +417,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val cond1 = typed(tree.cond, defn.BooleanType) val thenp1 = typed(tree.thenp, pt) val elsep1 = typed(tree.elsep orElse untpd.unitLiteral withPos tree.pos, pt) - cpy.If(tree, cond1, thenp1, elsep1).withType(thenp1.tpe | elsep1.tpe) + assignType(cpy.If(tree, cond1, thenp1, elsep1), thenp1, elsep1) } def typedFunction(tree: untpd.Function, pt: Type)(implicit ctx: Context) = track("typedFunction") { @@ -649,21 +524,21 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def typedClosure(tree: untpd.Closure, pt: Type)(implicit ctx: Context) = track("typedClosure") { val env1 = tree.env mapconserve (typed(_)) val meth1 = typedUnadapted(tree.meth) - val (ownType, target) = meth1.tpe.widen match { + val target = meth1.tpe.widen match { case mt: MethodType => pt match { case SAMType(meth) if !defn.isFunctionType(pt) && mt <:< meth.info => if (!isFullyDefined(pt, ForceDegree.all)) ctx.error(i"result type of closure is an underspecified SAM type $pt", tree.pos) - (pt, TypeTree(pt)) + TypeTree(pt) case _ => - if (!mt.isDependent) (mt.toFunctionType, EmptyTree) + if (!mt.isDependent) EmptyTree else throw new Error(i"internal error: cannot turn dependent method type $mt into closure, position = ${tree.pos}, raw type = ${mt.toString}") // !!! DEBUG. Eventually, convert to an error? } case tp => throw new Error(i"internal error: closing over non-method $tp, pos = ${tree.pos}") } - cpy.Closure(tree, env1, meth1, target).withType(ownType) + assignType(cpy.Closure(tree, env1, meth1, target), meth1, target) } def typedMatch(tree: untpd.Match, pt: Type)(implicit ctx: Context) = track("typedMatch") { @@ -706,7 +581,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } val guard1 = typedExpr(tree.guard, defn.BooleanType) val body1 = typedExpr(tree.body, pt) - cpy.CaseDef(tree, pat, guard1, body1) withType body1.tpe + assignType(cpy.CaseDef(tree, pat, guard1, body1), body1) } val doCase: () => CaseDef = () => caseRest(typedPattern(tree.pat, selType))(ctx.fresh.withNewScope) @@ -714,7 +589,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } val cases1 = tree.cases mapconserve typedCase - cpy.Match(tree, sel1, cases1).withType(ctx.typeComparer.lub(cases1.tpes)) + assignType(cpy.Match(tree, sel1, cases1), cases1) } } @@ -736,27 +611,25 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } val (from, proto) = enclMethInfo(ctx) val expr1 = typedExpr(tree.expr orElse untpd.unitLiteral.withPos(tree.pos), proto) - cpy.Return(tree, expr1, from) withType defn.NothingType + assignType(cpy.Return(tree, expr1, from)) } def typedTry(tree: untpd.Try, pt: Type)(implicit ctx: Context): Try = track("typedTry") { val expr1 = typed(tree.expr, pt) val handler1 = typed(tree.handler, defn.FunctionType(defn.ThrowableType :: Nil, pt)) val finalizer1 = typed(tree.finalizer, defn.UnitType) - val handlerTypeArgs = handler1.tpe.baseArgTypesHi(defn.FunctionClass(1)) - val ownType = if (handlerTypeArgs.nonEmpty) expr1.tpe | handlerTypeArgs(1) else expr1.tpe - cpy.Try(tree, expr1, handler1, finalizer1) withType ownType + assignType(cpy.Try(tree, expr1, handler1, finalizer1), expr1, handler1) } def typedThrow(tree: untpd.Throw)(implicit ctx: Context): Throw = track("typedThrow") { val expr1 = typed(tree.expr, defn.ThrowableType) - cpy.Throw(tree, expr1) withType defn.NothingType + assignType(cpy.Throw(tree, expr1)) } def typedSeqLiteral(tree: untpd.SeqLiteral, pt: Type)(implicit ctx: Context): SeqLiteral = track("typedSeqLiteral") { val proto1 = pt.elemType orElse WildcardType val elems1 = tree.elems mapconserve (typed(_, proto1)) - cpy.SeqLiteral(tree, elems1) withType defn.SeqType.appliedTo(ctx.typeComparer.lub(elems1.tpes)) + assignType(cpy.SeqLiteral(tree, elems1), elems1) } def typedTypeTree(tree: untpd.TypeTree, pt: Type)(implicit ctx: Context): TypeTree = track("typedTypeTree") { @@ -770,24 +643,19 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def typedSingletonTypeTree(tree: untpd.SingletonTypeTree)(implicit ctx: Context): SingletonTypeTree = track("typedSingletonTypeTree") { val ref1 = typedExpr(tree.ref) checkStable(ref1.tpe, tree.pos) - cpy.SingletonTypeTree(tree, ref1) withType ref1.tpe - } - - def typedSelectFromTypeTree(tree: untpd.SelectFromTypeTree, pt: Type)(implicit ctx: Context): SelectFromTypeTree = track("typedSelectFromTypeTree") { - val qual1 = typedType(tree.qualifier, selectionProto(tree.name, pt, this)) - cpy.SelectFromTypeTree(tree, qual1, tree.name).withType(checkedSelectionType(qual1, tree)) + assignType(cpy.SingletonTypeTree(tree, ref1), ref1) } def typedAndTypeTree(tree: untpd.AndTypeTree)(implicit ctx: Context): AndTypeTree = track("typedAndTypeTree") { val left1 = typed(tree.left) val right1 = typed(tree.right) - cpy.AndTypeTree(tree, left1, right1) withType left1.tpe & right1.tpe + assignType(cpy.AndTypeTree(tree, left1, right1), left1, right1) } def typedOrTypeTree(tree: untpd.OrTypeTree)(implicit ctx: Context): OrTypeTree = track("typedOrTypeTree") { val left1 = typed(tree.left) val right1 = typed(tree.right) - cpy.OrTypeTree(tree, left1, right1) withType left1.tpe | right1.tpe + assignType(cpy.OrTypeTree(tree, left1, right1), left1, right1) } def typedRefinedTypeTree(tree: untpd.RefinedTypeTree)(implicit ctx: Context): RefinedTypeTree = track("typedRefinedTypeTree") { @@ -818,16 +686,13 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def typedAppliedTypeTree(tree: untpd.AppliedTypeTree)(implicit ctx: Context): AppliedTypeTree = track("typedAppliedTypeTree") { val tpt1 = typed(tree.tpt) val args1 = tree.args mapconserve (typed(_)) - val tparams = tpt1.tpe.typeParams - if (args1.length != tparams.length) - ctx.error(i"wrong number of type arguments for ${tpt1.tpe}, should be ${tparams.length}") // todo in later phase: check arguments conform to parameter bounds - cpy.AppliedTypeTree(tree, tpt1, args1) withType tpt1.tpe.appliedTo(args1.tpes) + assignType(cpy.AppliedTypeTree(tree, tpt1, args1), tpt1, args1) } def typedByNameTypeTree(tree: untpd.ByNameTypeTree)(implicit ctx: Context): ByNameTypeTree = track("typedByNameTypeTree") { val result1 = typed(tree.result) - cpy.ByNameTypeTree(tree, result1) withType ExprType(result1.tpe) + assignType(cpy.ByNameTypeTree(tree, result1), result1) } def typedTypeBoundsTree(tree: untpd.TypeBoundsTree)(implicit ctx: Context): TypeBoundsTree = track("typedTypeBoundsTree") { @@ -836,19 +701,19 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val hi1 = typed(hi) if (!(lo1.tpe <:< hi1.tpe)) ctx.error(i"lower bound ${lo1.tpe} does not conform to upper bound ${hi1.tpe}", tree.pos) - cpy.TypeBoundsTree(tree, lo1, hi1) withType TypeBounds(lo1.tpe, hi1.tpe) + assignType(cpy.TypeBoundsTree(tree, lo1, hi1), lo1, hi1) } def typedBind(tree: untpd.Bind, pt: Type)(implicit ctx: Context): Bind = track("typedBind") { val body1 = typed(tree.body, pt) typr.println(s"typed bind ${tree.show} pt = ${pt.show} bodytpe = ${body1.tpe.show}") val sym = ctx.newSymbol(ctx.owner, tree.name.asTermName, EmptyFlags, body1.tpe, coord = tree.pos) - cpy.Bind(tree, tree.name, body1) withType TermRef(NoPrefix, sym) + assignType(cpy.Bind(tree, tree.name, body1), sym) } def typedAlternative(tree: untpd.Alternative, pt: Type)(implicit ctx: Context): Alternative = track("typedAlternative") { val trees1 = tree.trees mapconserve (typed(_, pt)) - cpy.Alternative(tree, trees1) withType ctx.typeComparer.lub(trees1.tpes) + assignType(cpy.Alternative(tree, trees1), trees1) } def typedModifiers(mods: untpd.Modifiers)(implicit ctx: Context): Modifiers = track("typedModifiers") { @@ -870,8 +735,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit case Ident(nme.WILDCARD) => rhs withType tpt1.tpe case _ => typedExpr(rhs, tpt1.tpe) } - val refType = if (sym.exists) sym.valRef else NoType - cpy.ValDef(vdef, mods1, name, tpt1, rhs1).withType(refType) + assignType(cpy.ValDef(vdef, mods1, name, tpt1, rhs1), sym) } def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = track("typedDefDef") { @@ -885,7 +749,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } val tpt1 = typedType(tpt) val rhs1 = typedExpr(rhs, tpt1.tpe) - cpy.DefDef(ddef, mods1, name, tparams1, vparamss1, tpt1, rhs1).withType(sym.termRefWithSig) + assignType(cpy.DefDef(ddef, mods1, name, tparams1, vparamss1, tpt1, rhs1), sym) //todo: make sure dependent method types do not depend on implicits or by-name params } @@ -893,7 +757,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val TypeDef(mods, name, rhs) = tdef val mods1 = typedModifiers(mods) val _ = typedType(rhs) // unused, typecheck only to remove from typedTree - cpy.TypeDef(tdef, mods1, name, TypeTree(sym.info)).withType(sym.typeRef) + assignType(cpy.TypeDef(tdef, mods1, name, TypeTree(sym.info)), sym) } def typedClassDef(cdef: untpd.TypeDef, cls: ClassSymbol)(implicit ctx: Context) = track("typedClassDef") { @@ -928,7 +792,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit checkNoDoubleDefs(cls) val impl1 = cpy.Template(impl, constr1, parents1, self1, body1) .withType(localDummy.termRef) - cpy.TypeDef(cdef, mods1, name, impl1).withType(cls.typeRef) + assignType(cpy.TypeDef(cdef, mods1, name, impl1), cls) // todo later: check that // 1. If class is non-abstract, it is instantiatable: @@ -942,23 +806,9 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def typedImport(imp: untpd.Import, sym: Symbol)(implicit ctx: Context): Import = track("typedImport") { val expr1 = typedExpr(imp.expr, AnySelectionProto) checkStable(expr1.tpe, imp.expr.pos) - cpy.Import(imp, expr1, imp.selectors).withType(sym.termRef) - } - - def typedAnnotated(tree: untpd.Annotated, pt: Type)(implicit ctx: Context): Tree = track("typedAnnotated") { - val annot1 = typed(tree.annot, defn.AnnotationClass.typeRef) - val arg1 = typed(tree.arg, pt) - val underlyingType = if (arg1.isTerm) arg1.tpe.widen else arg1.tpe - val ownType = AnnotatedType(Annotation(annot1), underlyingType) - if (ctx.mode is Mode.Type) - cpy.Annotated(tree, annot1, arg1) withType ownType - else - cpy.Typed(tree, arg1, TypeTree(ownType)) withType ownType + assignType(cpy.Import(imp, expr1, imp.selectors), sym) } - def typedAsFunction(tree: untpd.Tree, pt: Type)(implicit ctx: Context): Tree = - typed(tree, if (defn.isFunctionType(pt)) pt else AnyFunctionProto) - def typedPackageDef(tree: untpd.PackageDef)(implicit ctx: Context): Tree = track("typedPackageDef") { val pid1 = typedExpr(tree.pid, AnySelectionProto) val pkg = pid1.symbol @@ -972,6 +822,20 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit cpy.PackageDef(tree, pid1.asInstanceOf[RefTree], stats1) withType pkg.valRef } + def typedAnnotated(tree: untpd.Annotated, pt: Type)(implicit ctx: Context): Tree = track("typedAnnotated") { + val annot1 = typed(tree.annot, defn.AnnotationClass.typeRef) + val arg1 = typed(tree.arg, pt) + if (ctx.mode is Mode.Type) + assignType(cpy.Annotated(tree, annot1, arg1), annot1, arg1) + else { + val tpt = TypeTree(AnnotatedType(Annotation(annot1), arg1.tpe.widen)) + assignType(cpy.Typed(tree, arg1, tpt), tpt) + } + } + + def typedAsFunction(tree: untpd.Tree, pt: Type)(implicit ctx: Context): Tree = + typed(tree, if (defn.isFunctionType(pt)) pt else AnyFunctionProto) + def typedUnadapted(initTree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = { record("typedUnadapted") val xtree = expanded(initTree) |