diff options
author | Martin Odersky <odersky@gmail.com> | 2013-12-09 18:29:51 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2013-12-09 18:29:51 +0100 |
commit | eb0813b9ef437b9c89f8b67ae5b0070b300a0fc1 (patch) | |
tree | a95eb0b9b2e37a1c4efbf6a665a85c9fba451f25 /src/dotty/tools/dotc | |
parent | 42b169a85dacb6a5f1aff9b06bd69065d5f539f2 (diff) | |
download | dotty-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')
-rw-r--r-- | src/dotty/tools/dotc/typer/Applications.scala | 7 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Inferencing.scala | 22 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 56 |
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)) |