aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-08-24 18:04:22 +0200
committerMartin Odersky <odersky@gmail.com>2014-08-24 18:09:01 +0200
commitaa7a0399ad5424dd5292f2f1941c7293c16d6b79 (patch)
treefcc3efccc01f6d5160774c0b3998481f2d492500 /src
parent70abd73e9306eca3ec4de1d98b877e4fafe66ad0 (diff)
downloaddotty-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.scala2
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala21
-rw-r--r--src/dotty/tools/dotc/core/Annotations.scala3
-rw-r--r--src/dotty/tools/dotc/transform/TreeChecker.scala16
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala2
-rw-r--r--src/dotty/tools/dotc/typer/EtaExpansion.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Implicits.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala10
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") {