aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/typer
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-12-09 18:29:51 +0100
committerMartin Odersky <odersky@gmail.com>2013-12-09 18:29:51 +0100
commiteb0813b9ef437b9c89f8b67ae5b0070b300a0fc1 (patch)
treea95eb0b9b2e37a1c4efbf6a665a85c9fba451f25 /src/dotty/tools/dotc/typer
parent42b169a85dacb6a5f1aff9b06bd69065d5f539f2 (diff)
downloaddotty-eb0813b9ef437b9c89f8b67ae5b0070b300a0fc1.tar.gz
dotty-eb0813b9ef437b9c89f8b67ae5b0070b300a0fc1.tar.bz2
dotty-eb0813b9ef437b9c89f8b67ae5b0070b300a0fc1.zip
Fixes to avoid stale symbols and to avoid methods as pattern constructors.
Diffstat (limited to 'src/dotty/tools/dotc/typer')
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala7
-rw-r--r--src/dotty/tools/dotc/typer/Inferencing.scala22
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala56
3 files changed, 53 insertions, 32 deletions
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index 5e56d9eb8..64f44ee5e 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -19,7 +19,6 @@ import ErrorReporting._
import Trees._
import Names._
import StdNames._
-import Constants._
import Inferencing._
import EtaExpansion._
import collection.mutable
@@ -538,8 +537,7 @@ trait Applications extends Compatibility { self: Typer =>
errorTree(tree, s"${qual.show} cannot be used as an extractor in a pattern because it lacks an unapply or unapplySeq method")
val unapply = {
- val dummyArg = untpd.TypedSplice(dummyTreeOfType(WildcardType))
- val unappProto = FunProto(dummyArg :: Nil, WildcardType, this)
+ val unappProto = new UnapplyFunProto(this)
tryEither {
implicit ctx => typedExpr(untpd.Select(qual, nme.unapply), unappProto)
} {
@@ -755,9 +753,6 @@ trait Applications extends Compatibility { self: Typer =>
}
}
- private lazy val dummyTree = untpd.Literal(Constant(null))
- def dummyTreeOfType(tp: Type): Tree = dummyTree withTypeUnchecked tp
-
/** Resolve overloaded alternative `alts`, given expected type `pt`.
* todo: use techniques like for implicits to pick candidates quickly?
*/
diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala
index 8325549e6..3dac39854 100644
--- a/src/dotty/tools/dotc/typer/Inferencing.scala
+++ b/src/dotty/tools/dotc/typer/Inferencing.scala
@@ -6,6 +6,7 @@ import core._
import ast._
import Contexts._, Types._, Flags._, Denotations._, Names._, StdNames._, NameOps._, Symbols._
import Trees._
+import Constants._
import annotation.unchecked
import util.Positions._
import util.{Stats, SimpleMap}
@@ -61,12 +62,10 @@ object Inferencing {
*/
def selectionProto(name: Name, tp: Type) =
if (name.isConstructorName) WildcardType
- else {
- val rtp = tp match {
- case tp: ProtoType => WildcardType
- case _ => tp
- }
- new SelectionProto(name, rtp)
+ else tp match {
+ case tp: UnapplyFunProto => new UnapplySelectionProto(name)
+ case tp: ProtoType => new SelectionProto(name, WildcardType)
+ case _ => new SelectionProto(name, tp)
}
/** A prototype for expressions [] that are in some unspecified selection operation
@@ -79,6 +78,9 @@ object Inferencing {
*/
object AnySelectionProto extends SelectionProto(nme.WILDCARD, WildcardType)
+ /** A prototype for selections in pattern constructors */
+ class UnapplySelectionProto(name: Name) extends SelectionProto(name, WildcardType)
+
/** A prototype for expressions that appear in function position
*
* [](args): resultType
@@ -135,6 +137,9 @@ object Inferencing {
override def computeHash = doHash(argType, resultType)
}
+ class UnapplyFunProto(typer: Typer)(implicit ctx: Context) extends FunProto(
+ untpd.TypedSplice(dummyTreeOfType(WildcardType)) :: Nil, WildcardType, typer)
+
/** A prototype for expressions [] that are type-parameterized:
*
* [] [?_, ..., ?_nargs] resultType
@@ -334,6 +339,11 @@ object Inferencing {
}
result
}
+
+ private lazy val dummyTree = untpd.Literal(Constant(null))
+
+ /** Dummy tree to be used as an argument of a FunProto or ViewProto type */
+ def dummyTreeOfType(tp: Type): Tree = dummyTree withTypeUnchecked tp
}
/* not needed right now
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 4c44fbafe..b6c8bc9e8 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -35,8 +35,9 @@ trait TyperContextOps { ctx: Context => }
object Typer {
- import tpd.{cpy => _, _}
-
+ /** The precedence of bindings which determines which of several bindings will be
+ * accessed by an Ident.
+ */
object BindingPrec {
val definition = 4
val namedImport = 3
@@ -46,6 +47,9 @@ object Typer {
def isImportPrec(prec: Int) = prec == namedImport || prec == wildImport
}
+ /** A result value that is packed with the typer state that was used to
+ * generate it.
+ */
case class StateFul[T](value: T, state: TyperState) {
def commit()(implicit ctx: Context): T = {
state.commit()
@@ -68,11 +72,20 @@ class Typer extends Namer with Applications with Implicits {
*/
private var importedFromRoot: Set[Symbol] = Set()
+ /** A denotation exists really if it exists and does not point to a stale symbol. */
+ def reallyExists(denot: Denotation)(implicit ctx: Context): Boolean =
+ denot.exists && {
+ val sym = denot.symbol
+ (sym eq NoSymbol) || !sym.isAbsent
+ }
+
+ /** The type of a selection with `name` of a tree with type `site`.
+ */
def selectionType(site: Type, name: Name, pos: Position)(implicit ctx: Context): Type = {
val refDenot =
if (name == nme.CONSTRUCTOR) site.decl(name)
else site.member(name)
- if (refDenot.exists) site.select(name, refDenot)
+ if (reallyExists(refDenot)) site.select(name, refDenot)
else {
if (!site.isErroneous)
ctx.error(
@@ -82,18 +95,25 @@ class Typer extends Namer with Applications with Implicits {
}
}
+ /** The selection type, which is additionally checked for accessibility.
+ */
def checkedSelectionType(qual1: Tree, tree: untpd.RefTree)(implicit ctx: Context): Type = {
val ownType = selectionType(qual1.tpe.widenIfUnstable, tree.name, tree.pos)
if (!ownType.isError) checkAccessible(ownType, qual1.isInstanceOf[Super], tree.pos)
ownType
}
+ /** Check that Java statics and packages can only be used in selections.
+ */
def checkValue(tpe: Type, proto: Type, pos: Position)(implicit ctx: Context): Unit =
if (!proto.isInstanceOf[SelectionProto]) {
val sym = tpe.termSymbol
if ((sym is Package) || (sym is JavaModule)) ctx.error(i"$sym is not a value", pos)
}
+ /** If `tpe` is a named type, check that its denotation is accessible in the
+ * current context.
+ */
def checkAccessible(tpe: Type, superAccess: Boolean, pos: Position)(implicit ctx: Context): Type = tpe match {
case tpe: NamedType =>
val pre = tpe.prefix
@@ -124,9 +144,8 @@ class Typer extends Namer with Applications with Implicits {
tpe
}
- /** The qualifying class
- * of a this or super with prefix `qual`.
- * packageOk is equal false when qualifying class symbol
+ /** The qualifying class of a this or super with prefix `qual` (which might be empty).
+ * @param packageOk The qualifier may refer to a package.
*/
def qualifyingClass(tree: untpd.Tree, qual: Name, packageOK: Boolean)(implicit ctx: Context): Symbol =
ctx.owner.enclosingClass.ownersIterator.find(o => qual.isEmpty || o.isClass && o.name == qual) match {
@@ -139,12 +158,11 @@ class Typer extends Namer with Applications with Implicits {
NoSymbol
}
- /** Attribute an identifier consisting of a simple name or an outer reference.
+ /** Attribute an identifier consisting of a simple name.
*
* @param tree The tree representing the identifier.
* Transformations: (1) Prefix class members with this.
- * (2) Change imported symbols to selections
- *
+ * (2) Change imported symbols to selections.
*/
def typedIdent(tree: untpd.Ident, pt: Type)(implicit ctx: Context): Tree = track("typedIdent") {
val name = tree.name
@@ -175,17 +193,15 @@ class Typer extends Namer with Applications with Implicits {
}
else false
- /** A symbol qualifies if it exists and is not stale. Stale symbols
- * are made to disappear here. In addition,
+ /** A symbol qualifies if it really exists. In addition,
* if we are in a constructor of a pattern, we ignore all definitions
- * which are methods (note: if we don't do that
- * case x :: xs in class List would return the :: method)
- * unless they are stable or are accessors (the latter exception is for better error messages)
+ * which are methods and not accessors (note: if we don't do that
+ * case x :: xs in class List would return the :: method).
*/
- def qualifies(sym: Symbol): Boolean = !(
- sym.isAbsent
- || isPatternConstr && (sym is (Method, butNot = Accessor))
- )
+ def qualifies(denot: Denotation): Boolean =
+ reallyExists(denot) && !(
+ pt.isInstanceOf[UnapplySelectionProto] &&
+ (denot.symbol is (Method, butNot = Accessor)))
/** Find the denotation of enclosing `name` in given context `ctx`.
* @param previous A denotation that was found in a more deeply nested scope,
@@ -254,7 +270,7 @@ class Typer extends Namer with Applications with Implicits {
val pre = imp.site
if (!isDisabled(imp, pre)) {
val denot = pre.member(name)
- if (denot.exists) return pre.select(name, denot)
+ if (reallyExists(denot)) return pre.select(name, denot)
}
}
NoType
@@ -274,7 +290,7 @@ class Typer extends Namer with Applications with Implicits {
val outer = ctx.outer
if ((ctx.scope ne outer.scope) || (ctx.owner ne outer.owner)) {
val defDenot = ctx.denotNamed(name)
- if (defDenot.exists) {
+ if (qualifies(defDenot)) {
val curOwner = ctx.owner
val found = curOwner.thisType.select(name, defDenot)
if (!(curOwner is Package) || (defDenot.symbol is Package) || isDefinedInCurrentUnit(defDenot))