diff options
Diffstat (limited to 'src/dotty/tools/dotc/typer/InstChecks.scala')
-rw-r--r-- | src/dotty/tools/dotc/typer/InstChecks.scala | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/src/dotty/tools/dotc/typer/InstChecks.scala b/src/dotty/tools/dotc/typer/InstChecks.scala new file mode 100644 index 000000000..91c109ce8 --- /dev/null +++ b/src/dotty/tools/dotc/typer/InstChecks.scala @@ -0,0 +1,89 @@ +package dotty.tools.dotc +package typer + +import core._ +import Contexts.Context +import Decorators._ +import Phases._ +import Types._, Symbols._, Flags._, StdNames._ +import util.Positions._ +import ast.Trees._ +import typer.ErrorReporting._ + +/** This checks `New` nodes, verifying that they can be instantiated. */ +class InstChecks extends Phase { + import ast.tpd._ + + override def phaseName: String = "instchecks" + + override def run(implicit ctx: Context): Unit = + instCheck.traverse(ctx.compilationUnit.tpdTree) + + /** Check that `tp` refers to a nonAbstract class + * and that the instance conforms to the self type of the created class. + */ + def checkInstantiatable(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 _ => + } + + def checkValidJavaAnnotation(annot: Tree)(implicit ctx: Context): Unit = { + // TODO fill in + } + + val instCheck = new TreeTraverser { + + def checkAnnot(annot: Tree)(implicit ctx: Context): Unit = + if (annot.symbol.is(JavaDefined)) checkValidJavaAnnotation(annot) + else traverse(annot) + + def traverseNoCheck(tree: Tree)(implicit ctx: Context): Unit = tree match { + case Apply(fn, args) => + traverseNoCheck(fn) + args.foreach(traverse) + case TypeApply(fn, args) => + traverseNoCheck(fn) + args.foreach(traverse) + case Select(qual, nme.CONSTRUCTOR) => + traverseNoCheck(qual) + case New(tpt) => + traverse(tpt) + case _ => + traverse(tree) + } + + def traverse(tree: Tree)(implicit ctx: Context): Unit = tree match { + case tree: New => + checkInstantiatable(tree.tpe, tree.pos) + traverseChildren(tree) + case impl @ Template(constr, parents, self, _) => + traverse(constr) + parents.foreach(traverseNoCheck) + traverse(self) + impl.body.foreach(traverse) + case Annotated(annot, tree) => + checkAnnot(annot) + traverse(tree) + case TypeTree(original) => + tree.tpe match { + case AnnotatedType(annot, tpe) => checkAnnot(annot.tree) + case _ => + } + traverse(original) + case tree: MemberDef => + tree.symbol.annotations.foreach(annot => checkAnnot(annot.tree)) + traverseChildren(tree) + case _ => + traverseChildren(tree) + } + } +} |