diff options
-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 | ||||
-rw-r--r-- | tests/pos/sigs.scala | 1 | ||||
-rw-r--r-- | tests/pos/typers.scala | 21 |
5 files changed, 74 insertions, 33 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)) diff --git a/tests/pos/sigs.scala b/tests/pos/sigs.scala index 2051ead9a..4c1973cad 100644 --- a/tests/pos/sigs.scala +++ b/tests/pos/sigs.scala @@ -9,7 +9,6 @@ object sigs { class Base { def foo(x: Int): Any = 33 - def foo: Object = "x" } diff --git a/tests/pos/typers.scala b/tests/pos/typers.scala new file mode 100644 index 000000000..3fcd1ff29 --- /dev/null +++ b/tests/pos/typers.scala @@ -0,0 +1,21 @@ +object typers { + + class List[+T] { + def :: (x: T) = new :: (x, this) + + def len: Int = this match { + case x :: xs1 => 1 + xs1.len + case Nil => 0 + } + } + + object Nil extends List[Nothing] + + case class :: [+T] (hd: T, tl: List[T]) extends List[T] + + def len[U](xs: List[U]): Int = xs match { + case x :: xs1 => 1 + len(xs1) + case Nil => 0 + } + +}
\ No newline at end of file |