|
|
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 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
*
* 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)
/** Check that `tp` refers to a nonAbstract class
* and that the instance conforms to the self type of the created class.
*/
private def checkInstantiable(tp: Type, pos: Position)(implicit ctx: Context): Unit =
tp.underlyingClassRef(refinementOK = false) match {
case tref: TypeRef =>
val cls = tref.symbol
if (cls.is(AbstractOrTrait))
ctx.error(d"$cls is abstract; cannot be instantiated", pos)
if (!cls.is(Module)) {
val selfType = tp.givenSelfType.asSeenFrom(tref.prefix, cls.owner)
if (selfType.exists && !(tp <:< selfType))
ctx.error(d"$tp does not conform to its self type $selfType; cannot be instantiated")
}
case _ =>
}
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
}
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)
override def transform(tree: Tree)(implicit ctx: Context): Tree =
try tree match {
case impl: Template =>
val saved = parentNews
parentNews ++= impl.parents.flatMap(newPart)
try
synthMth.addSyntheticMethods(
paramFwd.forwardParamAccessors(
superAcc.wrapTemplate(impl)(
super.transform(_).asInstanceOf[Template])))
finally parentNews = saved
case tree @ TypeApply(sel: Select, args) =>
val args1 = transform(args)
val sel1 = superAcc.transformSelect(super.transform(sel), args1)
if (superAcc.isProtectedAccessor(sel1)) sel1 else cpy.TypeApply(tree)(sel1, args1)
case sel: Select =>
superAcc.transformSelect(super.transform(sel), Nil)
case tree @ Assign(sel: Select, _) =>
superAcc.transformAssign(super.transform(tree))
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) =>
checkInstantiable(tree.tpe, tree.pos)
super.transform(tree)
case 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 _ =>
super.transform(tree)
}
catch {
case ex : AssertionError =>
println(i"error while transforming $tree")
throw ex
}
}
}
|