diff options
author | Martin Odersky <odersky@gmail.com> | 2014-08-24 18:04:22 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2014-08-24 18:09:01 +0200 |
commit | aa7a0399ad5424dd5292f2f1941c7293c16d6b79 (patch) | |
tree | fcc3efccc01f6d5160774c0b3998481f2d492500 /src | |
parent | 70abd73e9306eca3ec4de1d98b877e4fafe66ad0 (diff) | |
download | dotty-aa7a0399ad5424dd5292f2f1941c7293c16d6b79.tar.gz dotty-aa7a0399ad5424dd5292f2f1941c7293c16d6b79.tar.bz2 dotty-aa7a0399ad5424dd5292f2f1941c7293c16d6b79.zip |
Check that idents don't assume magic.
In TreeChecker, make sure that every identifier has a type with an elidable prefix.
This excludes identifiers pointing to members of random prefixes without making the
prefix explicit in the tree as part of a Select node.
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/ast/TreeTypeMap.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/tpd.scala | 21 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Annotations.scala | 3 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/TreeChecker.scala | 16 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Applications.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/EtaExpansion.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Implicits.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 10 |
8 files changed, 47 insertions, 11 deletions
diff --git a/src/dotty/tools/dotc/ast/TreeTypeMap.scala b/src/dotty/tools/dotc/ast/TreeTypeMap.scala index 77ed24511..a66932e7b 100644 --- a/src/dotty/tools/dotc/ast/TreeTypeMap.scala +++ b/src/dotty/tools/dotc/ast/TreeTypeMap.scala @@ -48,6 +48,8 @@ final class TreeTypeMap( cpy.Template(impl)(constr1, parents1, self1, body1).withType(tmap.mapType(impl.tpe)) case tree1 => tree1.withType(mapType(tree1.tpe)) match { + case id: Ident if tpd.needsSelect(id.tpe) => + ref(id.tpe.asInstanceOf[TermRef]).withPos(id.pos) case ddef @ DefDef(mods, name, tparams, vparamss, tpt, rhs) => val (tmap1, tparams1) = transformDefs(ddef.tparams) val (tmap2, vparamss1) = tmap1.transformVParamss(vparamss) diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 5a9198adc..db0171d55 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -35,7 +35,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { untpd.SelectFromTypeTree(qualifier, tp.name).withType(tp) def This(cls: ClassSymbol)(implicit ctx: Context): This = - ta.assignType(untpd.This(cls.name)) + untpd.This(cls.name).withType(cls.thisType) def Super(qual: Tree, mix: TypeName, inConstrCall: Boolean)(implicit ctx: Context): Super = ta.assignType(untpd.Super(qual, mix), qual, inConstrCall) @@ -252,9 +252,26 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { // ------ Making references ------------------------------------------------------ + def prefixIsElidable(tp: NamedType)(implicit ctx: Context) = tp.prefix match { + case NoPrefix => + true + case ThisType(cls) => + cls.isStaticOwner || + tp.symbol.is(ParamOrAccessor) && tp.symbol.maybeOwner.enclosingClass == cls + case pre: TermRef => + pre.symbol.is(Module) && pre.symbol.isStatic + case _ => + false + } + + def needsSelect(tp: Type)(implicit ctx: Context) = tp match { + case tp: TermRef => !prefixIsElidable(tp) + case _ => false + } + /** A tree representing the same reference as the given type */ def ref(tp: NamedType)(implicit ctx: Context): NameTree = - if (tp.symbol.isStatic || tp.prefix == NoPrefix) Ident(tp) + if (prefixIsElidable(tp)) Ident(tp) else tp.prefix match { case pre: SingletonType => singleton(pre).select(tp) case pre => SelectFromTypeTree(TypeTree(pre), tp) diff --git a/src/dotty/tools/dotc/core/Annotations.scala b/src/dotty/tools/dotc/core/Annotations.scala index c61c46858..92b28a193 100644 --- a/src/dotty/tools/dotc/core/Annotations.scala +++ b/src/dotty/tools/dotc/core/Annotations.scala @@ -68,7 +68,8 @@ object Annotations { deferred(atp.classSymbol, implicit ctx => New(atp, args)) def makeAlias(sym: TermSymbol)(implicit ctx: Context) = - apply(defn.AliasAnnot, List(Ident(TermRef.withSigAndDenot(sym.owner.thisType, sym.name, sym.signature, sym)))) + apply(defn.AliasAnnot, List( + ref(TermRef.withSigAndDenot(sym.owner.thisType, sym.name, sym.signature, sym)))) def makeChild(sym: Symbol)(implicit ctx: Context) = apply(defn.ChildAnnot.typeRef.appliedTo(sym.owner.thisType.select(sym.name, sym)), Nil) diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala index 3c5c9a0c3..87254a217 100644 --- a/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -19,8 +19,15 @@ import ast.Trees._ import ast.{tpd, untpd} import java.lang.AssertionError -/** This transform eliminates patterns. Right now it's a dummy. - * Awaiting the real pattern matcher. +/** Run by -Ycheck option after a given phase, this class retypes all syntax trees + * and verifies that the type of each tree node so obtained conforms to the type found in the tree node. + * It also performs the following checks: + * + * - The owner of each definition is the same as the owner of the current typing context. + * - Ident nodes do not refer to a denotation that would need a select to be accessible + * (see tpd.needsSelect). + * - After typer, identifiers and select nodes refer to terms only (all types should be + * represented as TypeTrees then). */ class TreeChecker { import ast.tpd._ @@ -65,12 +72,13 @@ class TreeChecker { } override def typedIdent(tree: untpd.Ident, pt: Type)(implicit ctx: Context): Tree = { - assert(tree.isTerm || ctx.phase.prev.id <= ctx.typerPhase.id, tree.show + " at " + ctx.phase) + assert(tree.isTerm || !ctx.isAfterTyper, tree.show + " at " + ctx.phase) + assert(!needsSelect(tree.tpe), i"bad type ${tree.tpe} for $tree") super.typedIdent(tree, pt) } override def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = { - assert(tree.isTerm || ctx.phase.prev.id <= ctx.typerPhase.id, tree.show + " at " + ctx.phase) + assert(tree.isTerm || !ctx.isAfterTyper, tree.show + " at " + ctx.phase) super.typedSelect(tree, pt) } diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 86327d2fc..a7c6a85cf 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -261,7 +261,7 @@ trait Applications extends Compatibility { self: Typer => findDefaultGetter(n + numArgs(normalizedFun)) match { case dref: NamedType => liftFun() - addTyped(treeToArg(spliceMeth(Ident(dref) withPos appPos, normalizedFun)), formal) + addTyped(treeToArg(spliceMeth(ref(dref) withPos appPos, normalizedFun)), formal) matchArgs(args1, formals1, n + 1) case _ => missingArg(n) diff --git a/src/dotty/tools/dotc/typer/EtaExpansion.scala b/src/dotty/tools/dotc/typer/EtaExpansion.scala index 790a848a7..7c1130b83 100644 --- a/src/dotty/tools/dotc/typer/EtaExpansion.scala +++ b/src/dotty/tools/dotc/typer/EtaExpansion.scala @@ -26,7 +26,7 @@ object EtaExpansion { val name = ctx.freshName(prefix).toTermName val sym = ctx.newSymbol(ctx.owner, name, EmptyFlags, expr.tpe.widen, coord = positionCoord(expr.pos)) defs += ValDef(sym, expr) - Ident(sym.valRef) + ref(sym.valRef) } /** Lift out common part of lhs tree taking part in an operator assignment such as diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala index 571b37eb0..cf2f3f286 100644 --- a/src/dotty/tools/dotc/typer/Implicits.scala +++ b/src/dotty/tools/dotc/typer/Implicits.scala @@ -476,7 +476,7 @@ trait Implicits { self: Typer => /** Try to typecheck an implicit reference */ def typedImplicit(ref: TermRef)(implicit ctx: Context): SearchResult = track("typedImplicit") { ctx.traceIndented(i"typed implicit $ref, pt = $pt, implicitsEnabled == ${ctx.mode is ImplicitsEnabled}", implicits, show = true) { - var generated: Tree = Ident(ref).withPos(pos) + var generated: Tree = tpd.ref(ref).withPos(pos) if (!argument.isEmpty) generated = typedUnadapted( untpd.Apply(untpd.TypedSplice(generated), untpd.TypedSplice(argument) :: Nil), diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 67c9e15af..400909da6 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -266,7 +266,15 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit error(d"not found: $kind$name", tree.pos) ErrorType } - checkValue(tree.withType(ownType), pt) + + val tree1 = ownType match { + case ownType: NamedType if !prefixIsElidable(ownType) => + ref(ownType).withPos(tree.pos) + case _ => + tree.withType(ownType) + } + + checkValue(tree1, pt) } def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = track("typedSelect") { |