|
| 1 | +package dotty.tools.dotc |
| 2 | +package typer |
| 3 | + |
| 4 | +import core._ |
| 5 | +import Contexts.Context |
| 6 | +import Decorators._ |
| 7 | +import Phases._ |
| 8 | +import Types._, Symbols._, Flags._, StdNames._ |
| 9 | +import util.Positions._ |
| 10 | +import ast.Trees._ |
| 11 | +import typer.ErrorReporting._ |
| 12 | + |
| 13 | +/** This checks `New` nodes, verifying that they can be instantiated. */ |
| 14 | +class InstChecks extends Phase { |
| 15 | + import ast.tpd._ |
| 16 | + |
| 17 | + override def phaseName: String = "instchecks" |
| 18 | + |
| 19 | + override def run(implicit ctx: Context): Unit = |
| 20 | + instCheck.traverse(ctx.compilationUnit.tpdTree) |
| 21 | + |
| 22 | + /** Check that `tp` refers to a nonAbstract class |
| 23 | + * and that the instance conforms to the self type of the created class. |
| 24 | + */ |
| 25 | + def checkInstantiatable(tp: Type, pos: Position)(implicit ctx: Context): Unit = |
| 26 | + tp.underlyingClassRef(refinementOK = false) match { |
| 27 | + case tref: TypeRef => |
| 28 | + val cls = tref.symbol |
| 29 | + if (cls.is(AbstractOrTrait)) |
| 30 | + ctx.error(d"$cls is abstract; cannot be instantiated", pos) |
| 31 | + if (!cls.is(Module)) { |
| 32 | + val selfType = tp.givenSelfType.asSeenFrom(tref.prefix, cls.owner) |
| 33 | + if (selfType.exists && !(tp <:< selfType)) |
| 34 | + ctx.error(d"$tp does not conform to its self type $selfType; cannot be instantiated") |
| 35 | + } |
| 36 | + case _ => |
| 37 | + } |
| 38 | + |
| 39 | + def checkValidJavaAnnotation(annot: Tree)(implicit ctx: Context): Unit = { |
| 40 | + // TODO fill in |
| 41 | + } |
| 42 | + |
| 43 | + val instCheck = new TreeTraverser { |
| 44 | + |
| 45 | + def checkAnnot(annot: Tree)(implicit ctx: Context): Unit = |
| 46 | + if (annot.symbol.is(JavaDefined)) checkValidJavaAnnotation(annot) |
| 47 | + else traverse(annot) |
| 48 | + |
| 49 | + def traverseNoCheck(tree: Tree)(implicit ctx: Context): Unit = tree match { |
| 50 | + case Apply(fn, args) => |
| 51 | + traverseNoCheck(fn) |
| 52 | + args.foreach(traverse) |
| 53 | + case TypeApply(fn, args) => |
| 54 | + traverseNoCheck(fn) |
| 55 | + args.foreach(traverse) |
| 56 | + case Select(qual, nme.CONSTRUCTOR) => |
| 57 | + traverseNoCheck(qual) |
| 58 | + case New(tpt) => |
| 59 | + traverse(tpt) |
| 60 | + case _ => |
| 61 | + traverse(tree) |
| 62 | + } |
| 63 | + |
| 64 | + def traverse(tree: Tree)(implicit ctx: Context): Unit = tree match { |
| 65 | + case tree: New => |
| 66 | + checkInstantiatable(tree.tpe, tree.pos) |
| 67 | + traverseChildren(tree) |
| 68 | + case impl @ Template(constr, parents, self, _) => |
| 69 | + traverse(constr) |
| 70 | + parents.foreach(traverseNoCheck) |
| 71 | + traverse(self) |
| 72 | + impl.body.foreach(traverse) |
| 73 | + case Annotated(annot, tree) => |
| 74 | + checkAnnot(annot) |
| 75 | + traverse(tree) |
| 76 | + case TypeTree(original) => |
| 77 | + tree.tpe match { |
| 78 | + case AnnotatedType(annot, tpe) => checkAnnot(annot.tree) |
| 79 | + case _ => |
| 80 | + } |
| 81 | + traverse(original) |
| 82 | + case tree: MemberDef => |
| 83 | + tree.symbol.annotations.foreach(annot => checkAnnot(annot.tree)) |
| 84 | + traverseChildren(tree) |
| 85 | + case _ => |
| 86 | + traverseChildren(tree) |
| 87 | + } |
| 88 | + } |
| 89 | +} |
0 commit comments