From 7e60221120015be2607947f2de55ca4984db7077 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 22 Apr 2015 13:15:11 +0200 Subject: Roll InstChecks into PostTyper Move InstChecks functionality into PostTyper in order to save a separate traversal. --- src/dotty/tools/dotc/transform/PostTyper.scala | 89 ++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 13 deletions(-) (limited to 'src/dotty/tools/dotc/transform/PostTyper.scala') diff --git a/src/dotty/tools/dotc/transform/PostTyper.scala b/src/dotty/tools/dotc/transform/PostTyper.scala index 4ad2cef01..98c110e11 100644 --- a/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/src/dotty/tools/dotc/transform/PostTyper.scala @@ -7,7 +7,7 @@ import scala.collection.{ mutable, immutable } import ValueClasses._ import scala.annotation.tailrec import core._ -import typer.InstChecks +import typer.ErrorReporting._ import Types._, Contexts._, Constants._, Names._, NameOps._, Flags._, DenotTransformers._ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Scopes._, Denotations._ import util.Positions._ @@ -22,6 +22,8 @@ import Symbols._, TypeUtils._ * 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) 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 @@ -44,28 +46,89 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran val superAcc = new SuperAccessors(thisTransformer) val paramFwd = new ParamForwarding(thisTransformer) -// val instChecks = new InstChecks + + /** 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 => - def trans(impl: Template) = - cpy.Template(impl)(body = transformStats(impl.body, impl.symbol)) - paramFwd.forwardParamAccessors(superAcc.wrapTemplate(impl)(trans)) + val saved = parentNews + parentNews ++= impl.parents.flatMap(newPart) + try + paramFwd.forwardParamAccessors( + superAcc.wrapTemplate(impl)( + super.transform(_).asInstanceOf[Template])) + finally parentNews = saved case tree @ TypeApply(sel: Select, args) => - val sel1 = superAcc.transformSelect(super.transform(sel), args) - if (superAcc.isProtectedAccessor(sel1)) sel1 else cpy.TypeApply(tree)(sel1, 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: DefDef => - superAcc.wrapDefDef(tree)(cpy.DefDef(tree)(rhs = transform(tree.rhs))) - case tree: Assign => + case tree @ Assign(sel: Select, _) => superAcc.transformAssign(super.transform(tree)) -// case tree: Apply if tree.symbol.isConstructor => -// instChecks.checkInstantiable(tree) -// 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) } -- cgit v1.2.3