From d318cafbb92518a39c84539c0387c2c93815bb7a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 10 Aug 2013 11:43:01 +0200 Subject: Added typing of all forms of type trees. --- src/dotty/tools/dotc/ast/Desugar.scala | 27 +++++--- src/dotty/tools/dotc/ast/Trees.scala | 4 ++ src/dotty/tools/dotc/typer/Applications.scala | 2 +- src/dotty/tools/dotc/typer/Mode.scala | 2 +- src/dotty/tools/dotc/typer/Typer.scala | 97 +++++++++++++++++++++++++-- 5 files changed, 115 insertions(+), 17 deletions(-) diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala index 5c87517d2..cc26033f8 100644 --- a/src/dotty/tools/dotc/ast/Desugar.scala +++ b/src/dotty/tools/dotc/ast/Desugar.scala @@ -19,16 +19,22 @@ object desugar { def valDef(vdef: ValDef)(implicit ctx: Context): Tree = { val ValDef(mods, name, tpt, rhs) = vdef if (!ctx.owner.isClass || (mods is Private)) vdef - else { - val lname = name.toLocalName - val field = cpy.ValDef(vdef, mods, lname, tpt, rhs) - val getter = cpy.DefDef(vdef, mods, name, Nil, Nil, tpt, Ident(lname)) - if (!(mods is Mutable)) Thicket(field, getter) + else flatTree { + val (field, getterRhs) = + if (rhs.isEmpty) + (EmptyTree, EmptyTree) + else { + val lname = name.toLocalName + (cpy.ValDef(vdef, mods, lname, tpt, rhs), Ident(lname)) + } + val getter = cpy.DefDef(vdef, mods | Accessor, name, Nil, Nil, tpt, getterRhs) + if (!(mods is Mutable)) field :: getter :: Nil else { - val setterParam = makeSyntheticParameter(tpt = TypeTree(field)) + val setterParam = makeSyntheticParameter(tpt = TypeTree(getter)) val setter = cpy.DefDef(vdef, - mods, name.getterToSetter, Nil, (setterParam :: Nil) :: Nil, EmptyTree, refOfDef(setterParam)) - Thicket(field, getter, setter) + mods | Accessor, name.getterToSetter, Nil, (setterParam :: Nil) :: Nil, + EmptyTree, refOfDef(setterParam)) + field :: getter :: setter :: Nil } } } @@ -545,6 +551,11 @@ object desugar { } }.withPos(tree.pos) + def refinedTypeToClass(tree: RefinedTypeTree)(implicit ctx: Context): TypeDef = { + val impl = Template(emptyConstructor, tree.tpt :: Nil, EmptyValDef, tree.refinements) + TypeDef(Modifiers(), tpnme.REFINE_CLASS, impl) + } + /** If tree is a variable pattern, return its name and type, otherwise return None. */ private object VarPattern { diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala index f31f7373c..a266eaf87 100644 --- a/src/dotty/tools/dotc/ast/Trees.scala +++ b/src/dotty/tools/dotc/ast/Trees.scala @@ -922,6 +922,10 @@ object Trees { case tree: SeqLiteral if (elems eq tree.elems) => tree case _ => finalize(tree, untpd.SeqLiteral(elems)) } + def TypeTree(tree: Tree, original: Tree): TypeTree = tree match { + case tree: TypeTree if original eq tree.original => tree + case _ => finalize(tree, untpd.TypeTree(original)) + } def SingletonTypeTree(tree: Tree, ref: Tree): SingletonTypeTree = tree match { case tree: SingletonTypeTree if (ref eq tree.ref) => tree case _ => finalize(tree, untpd.SingletonTypeTree(ref)) diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 7a6094078..242acc43b 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -511,7 +511,7 @@ trait Applications extends Compatibility { self: Typer => val result = app.result ConstFold(result) orElse result case _ => - fun1.exprType match { + fun1.qualifierType match { case ErrorType => tree.withType(ErrorType) } diff --git a/src/dotty/tools/dotc/typer/Mode.scala b/src/dotty/tools/dotc/typer/Mode.scala index fe2692a88..88bb3d4d8 100644 --- a/src/dotty/tools/dotc/typer/Mode.scala +++ b/src/dotty/tools/dotc/typer/Mode.scala @@ -30,7 +30,7 @@ object Mode { val Type = newMode(1, "Type") val ImplicitsDisabled = newMode(2, "ImplicitsDisabled") - val InSuperInit = newMode(3, "inSuperInit") + val InSuperInit = newMode(3, "InSuperInit") val PatternOrType = Pattern | Type } \ No newline at end of file diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 7995da312..0869aff43 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -43,8 +43,9 @@ object Typer { } implicit class TreeDecorator(tree: Tree) { - def exprType(implicit ctx: Context): Type = tree.tpe match { + def qualifierType(implicit ctx: Context): Type = tree.tpe match { case tpe: TermRef if !tpe.symbol.isStable => tpe.info + case tpe: TypeRef => tpe.info case tpe => tpe } } @@ -69,7 +70,7 @@ class Typer extends Namer with Applications with Implicits { */ private var importedFromRoot: Set[Symbol] = Set() - def typedSelection(site: Type, name: Name, pos: Position)(implicit ctx: Context): Type = { + def selectionType(site: Type, name: Name, pos: Position)(implicit ctx: Context): Type = { val ref = if (name == nme.CONSTRUCTOR) site.decl(name) else site.member(name) @@ -83,6 +84,12 @@ class Typer extends Namer with Applications with Implicits { } } + def checkedSelectionType(qual1: Tree, tree: untpd.RefTree)(implicit ctx: Context): Type = { + val ownType = selectionType(qual1.qualifierType, tree.name, tree.pos) + if (!ownType.isError) checkAccessible(ownType, qual1.isInstanceOf[Super], tree.pos) + ownType + } + def checkAccessible(tpe: Type, superAccess: Boolean, pos: Position)(implicit ctx: Context): Type = tpe match { case tpe: NamedType => val pre = tpe.prefix @@ -215,9 +222,9 @@ class Typer extends Namer with Applications with Implicits { } selectors match { case Pair(Ident(from), Ident(`name`)) :: rest => - checkUnambiguous(typedSelection(site, name, tree.pos)) + checkUnambiguous(selectionType(site, name, tree.pos)) case Ident(`name`) :: rest => - checkUnambiguous(typedSelection(site, name, tree.pos)) + checkUnambiguous(selectionType(site, name, tree.pos)) case _ :: rest => namedImportRef(site, rest) case nil => @@ -301,9 +308,7 @@ class Typer extends Namer with Applications with Implicits { def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = { val qual1 = typedExpr(tree.qualifier, RefinedType(WildcardType, tree.name, pt)) - val ownType = typedSelection(qual1.exprType, tree.name, tree.pos) - if (!ownType.isError) checkAccessible(ownType, qual1.isInstanceOf[Super], tree.pos) - cpy.Select(tree, qual1, tree.name).withType(ownType) + cpy.Select(tree, qual1, tree.name).withType(checkedSelectionType(qual1, tree)) } def typedThis(tree: untpd.This)(implicit ctx: Context): Tree = { @@ -539,6 +544,84 @@ class Typer extends Namer with Applications with Implicits { cpy.SeqLiteral(tree, elems1) withType ctx.lub(elems1.tpes) } + def typedTypeTree(tree: untpd.TypeTree)(implicit ctx: Context): TypeTree = { + val (original1, ownType) = tree.original match { + case untpd.EmptyTree => + (EmptyTree, errorType("internal error: missing type in TypeTree", tree.pos)) + case original: DefDef => + val meth = ctx.lookup(original.name).first + assert(meth.exists, meth) + (EmptyTree, meth.info.resultType) + case original => + val original1 = typed(original) + (original1, original1.tpe) + } + cpy.TypeTree(tree, original1) withType ownType + } + + def typedSingletonTypeTree(tree: untpd.SingletonTypeTree)(implicit ctx: Context): SingletonTypeTree = { + val ref1 = typedExpr(tree.ref) + checkStable(ref1.qualifierType, tree.pos) + cpy.SingletonTypeTree(tree, ref1) withType ref1.tpe + } + + def typedSelectFromTypeTree(tree: untpd.SelectFromTypeTree, pt: Type)(implicit ctx: Context): SelectFromTypeTree = { + val qual1 = typedType(tree.qualifier, RefinedType(WildcardType, tree.name, pt)) + cpy.SelectFromTypeTree(tree, qual1, tree.name).withType(checkedSelectionType(qual1, tree)) + } + + def typedAndTypeTree(tree: untpd.AndTypeTree, pt: Type)(implicit ctx: Context): AndTypeTree = { + val left1 = typed(tree.left) + val right1 = typed(tree.right) + cpy.AndTypeTree(tree, left1, right1) withType left1.tpe & right1.tpe + } + + def typedOrTypeTree(tree: untpd.OrTypeTree, pt: Type)(implicit ctx: Context): OrTypeTree = { + val left1 = typed(tree.left, pt) + val right1 = typed(tree.right, pt) + cpy.OrTypeTree(tree, left1, right1) withType left1.tpe | right1.tpe + } + + def typedRefinedTypeTree(tree: untpd.RefinedTypeTree)(implicit ctx: Context): RefinedTypeTree = { + val tpt1 = typedAheadType(tree.tpt) + val refineClsDef = desugar.refinedTypeToClass(tree) + val throwAwayScopeCtx = ctx.fresh.withNewScope + val refineCls = createSymbol(refineClsDef)(throwAwayScopeCtx).asClass + val TypeDef(_, _, Template(_, _, _, refinements1)) = typed(refineClsDef) + assert(tree.refinements.length == refinements1.length, s"${tree.refinements} != $refinements1") + def addRefinement(parent: Type, refinement: Tree): Type = { + foreachSubTreeOf(refinement) { + case tree: RefTree => + if (tree.symbol.owner == refineCls && tree.pos.start <= tree.symbol.pos.end) + ctx.error(s"illegal forward reference in refinement", tree.pos) + case _ => + } + val rsym = refinement.symbol + val rinfo = if (rsym is Accessor) rsym.info.resultType else rsym.info + RefinedType(parent, rsym.name, rt => rinfo.substThis(refineCls, RefinedThis(rt))) + } + cpy.RefinedTypeTree(tree, tpt1, refinements1) withType + (tpt1.tpe /: refinements1)(addRefinement) + } + + def typedAppliedTypeTree(tree: untpd.AppliedTypeTree)(implicit ctx: Context): AppliedTypeTree = { + val tpt1 = typed(tree.tpt) + val args1 = tree.args map (typed(_)) + val tparams = tpt1.tpe.typeParams + if (args1.length != tparams.length) + ctx.error(s"wrong number of type arguments for ${tpt1.tpe.show}, 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) + } + + def typedTypeBounds(tree: untpd.TypeBoundsTree)(implicit ctx: Context): TypeBoundsTree = { + val lo1 = typed(tree.lo) + val hi1 = typed(tree.hi) + if (!(lo1.tpe <:< hi1.tpe)) + ctx.error(s"lower bound ${lo1.tpe.show} does not conform to upper bound ${hi1.tpe.show}", tree.pos) + cpy.TypeBoundsTree(tree, lo1, hi1) withType TypeBounds(lo1.tpe, hi1.tpe) + } + def typedBind(tree: untpd.Bind, pt: Type)(implicit ctx: Context): Bind = { val body1 = typed(tree.body, pt) val sym = ctx.newSymbol(ctx.owner, tree.name.asTermName, EmptyFlags, pt, coord = tree.pos) -- cgit v1.2.3