diff options
Diffstat (limited to 'src/dotty/tools/dotc/transform/PostTyper.scala')
-rw-r--r-- | src/dotty/tools/dotc/transform/PostTyper.scala | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/src/dotty/tools/dotc/transform/PostTyper.scala b/src/dotty/tools/dotc/transform/PostTyper.scala new file mode 100644 index 000000000..55270f233 --- /dev/null +++ b/src/dotty/tools/dotc/transform/PostTyper.scala @@ -0,0 +1,169 @@ +package dotty.tools.dotc +package transform + +import dotty.tools.dotc.transform.TreeTransforms.{TransformerInfo, TreeTransform, TreeTransformer} +import dotty.tools.dotc.ast.{Trees, tpd} +import scala.collection.{ mutable, immutable } +import ValueClasses._ +import scala.annotation.tailrec +import core._ +import typer.ErrorReporting._ +import typer.Checking +import Types._, Contexts._, Constants._, Names._, NameOps._, Flags._, DenotTransformers._ +import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Scopes._, Denotations._ +import util.Positions._ +import Decorators._ +import Symbols._, TypeUtils._ + +/** A macro transform that runs immediately after typer and that performs the following functions: + * + * (1) Add super accessors and protected accessors (@see SuperAccessors) + * + * (2) Convert parameter fields that have the same name as a corresponding + * public parameter field in a superclass to a forwarder to the superclass + * field (corresponding = super class field is initialized with subclass field) + * (@see ForwardParamAccessors) + * + * (3) Add synthetic methods (@see SyntheticMethods) + * + * (4) Check that `New` nodes can be instantiated, and that annotations are valid + * + * (5) Convert all trees representing types to TypeTrees. + * + * (6) Check the bounds of AppliedTypeTrees + * + * (7) Insert `.package` for selections of package object members + * + * (8) Replaces self references by name with `this` + * + * The reason for making this a macro transform is that some functions (in particular + * super and protected accessors and instantiation checks) are naturally top-down and + * don't lend themselves to the bottom-up approach of a mini phase. The other two functions + * (forwarding param accessors and synthetic methods) only apply to templates and fit + * mini-phase or subfunction of a macro phase equally well. But taken by themselves + * they do not warrant their own group of miniphases before pickling. + */ +class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTransformer => + + import tpd._ + + /** the following two members override abstract members in Transform */ + override def phaseName: String = "posttyper" + + override def transformPhase(implicit ctx: Context) = thisTransformer.next + + protected def newTransformer(implicit ctx: Context): Transformer = + new PostTyperTransformer + + val superAcc = new SuperAccessors(thisTransformer) + val paramFwd = new ParamForwarding(thisTransformer) + val synthMth = new SyntheticMethods(thisTransformer) + + private def newPart(tree: Tree): Option[New] = methPart(tree) match { + case Select(nu: New, _) => Some(nu) + case _ => None + } + + private def checkValidJavaAnnotation(annot: Tree)(implicit ctx: Context): Unit = { + // TODO fill in + } + + private def normalizeTypeTree(tree: Tree)(implicit ctx: Context) = { + def norm(tree: Tree) = if (tree.isType) TypeTree(tree.tpe).withPos(tree.pos) else tree + tree match { + case tree: TypeTree => + tree + case AppliedTypeTree(tycon, args) => + val tparams = tycon.tpe.typeSymbol.typeParams + val bounds = tparams.map(tparam => + tparam.info.asSeenFrom(tycon.tpe.normalizedPrefix, tparam.owner.owner).bounds) + Checking.checkBounds(args, bounds, _.substDealias(tparams, _)) + norm(tree) + case _ => + norm(tree) + } + } + + class PostTyperTransformer extends Transformer { + + private var inJavaAnnot: Boolean = false + + private var parentNews: Set[New] = Set() + + private def transformAnnot(annot: Tree)(implicit ctx: Context): Tree = { + val saved = inJavaAnnot + inJavaAnnot = annot.symbol is JavaDefined + if (inJavaAnnot) checkValidJavaAnnotation(annot) + try transform(annot) + finally inJavaAnnot = saved + } + + private def transformAnnot(annot: Annotation)(implicit ctx: Context): Annotation = + annot.derivedAnnotation(transformAnnot(annot.tree)) + + private def transformAnnots(tree: MemberDef)(implicit ctx: Context): Unit = + tree.symbol.transformAnnotations(transformAnnot) + + private def transformSelect(tree: Select, targs: List[Tree])(implicit ctx: Context) = { + val qual = tree.qualifier + qual.symbol.moduleClass.denot match { + case pkg: PackageClassDenotation if !tree.symbol.maybeOwner.is(Package) => + assert(targs.isEmpty) + cpy.Select(tree)(qual select pkg.packageObj.symbol, tree.name) + case _ => + superAcc.transformSelect(super.transform(tree), targs) + } + } + + override def transform(tree: Tree)(implicit ctx: Context): Tree = + try normalizeTypeTree(tree) match { + case tree: Ident => + tree.tpe match { + case tpe: ThisType => This(tpe.cls).withPos(tree.pos) + case _ => tree + } + case tree: Select => + transformSelect(tree, Nil) + case tree @ TypeApply(sel: Select, args) => + val args1 = transform(args) + val sel1 = transformSelect(sel, args1) + if (superAcc.isProtectedAccessor(sel1)) sel1 else cpy.TypeApply(tree)(sel1, args1) + case tree @ Assign(sel: Select, _) => + superAcc.transformAssign(super.transform(tree)) + case tree: Template => + val saved = parentNews + parentNews ++= tree.parents.flatMap(newPart) + try + synthMth.addSyntheticMethods( + paramFwd.forwardParamAccessors( + superAcc.wrapTemplate(tree)( + super.transform(_).asInstanceOf[Template]))) + finally parentNews = saved + case tree: DefDef => + transformAnnots(tree) + superAcc.wrapDefDef(tree)(super.transform(tree).asInstanceOf[DefDef]) + case tree: MemberDef => + transformAnnots(tree) + super.transform(tree) + case tree: New if !inJavaAnnot && !parentNews.contains(tree) => + Checking.checkInstantiable(tree.tpe, tree.pos) + super.transform(tree) + case tree @ Annotated(annot, annotated) => + cpy.Annotated(tree)(transformAnnot(annot), transform(annotated)) + case tree: TypeTree => + tree.withType( + tree.tpe match { + case AnnotatedType(annot, tpe) => AnnotatedType(transformAnnot(annot), tpe) + case tpe => tpe + } + ) + case tree => + super.transform(tree) + } + catch { + case ex : AssertionError => + println(i"error while transforming $tree") + throw ex + } + } +} |