summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/reflect/internal/Types.scala17
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala68
2 files changed, 53 insertions, 32 deletions
diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala
index f70e9760f7..e062e875cd 100644
--- a/src/compiler/scala/reflect/internal/Types.scala
+++ b/src/compiler/scala/reflect/internal/Types.scala
@@ -3616,6 +3616,23 @@ trait Types extends api.Types { self: SymbolTable =>
}
}
+ class TypeUnwrapper(poly: Boolean, existential: Boolean, annotated: Boolean, nullary: Boolean) extends (Type => Type) {
+ def apply(tp: Type): Type = tp match {
+ case AnnotatedType(_, underlying, _) if annotated => apply(underlying)
+ case ExistentialType(_, underlying) if existential => apply(underlying)
+ case PolyType(_, underlying) if poly => apply(underlying)
+ case NullaryMethodType(underlying) if nullary => apply(underlying)
+ case tp => tp
+ }
+ }
+ class ClassUnwrapper(existential: Boolean) extends TypeUnwrapper(poly = true, existential, annotated = true, nullary = false) {
+ override def apply(tp: Type) = super.apply(tp.normalize)
+ }
+
+ object unwrapToClass extends ClassUnwrapper(existential = true) { }
+ object unwrapToStableClass extends ClassUnwrapper(existential = false) { }
+ object unwrapWrapperTypes extends TypeUnwrapper(true, true, true, true) { }
+
trait AnnotationFilter extends TypeMap {
def keepAnnotation(annot: AnnotationInfo): Boolean
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 7d2e587b3f..ae184d2677 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -235,32 +235,40 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
result
}
}
+ def isNonRefinementClassType(tpe: Type) = tpe match {
+ case SingleType(_, sym) => sym.isModuleClass
+ case TypeRef(_, sym, _) => sym.isClass && !sym.isRefinementClass
+ case ErrorType => true
+ case _ => false
+ }
+ private def errorNotClass(tpt: Tree, found: Type) = { ClassTypeRequiredError(tpt, found); false }
+ private def errorNotStable(tpt: Tree, found: Type) = { TypeNotAStablePrefixError(tpt, found); false }
/** Check that `tpt` refers to a non-refinement class type */
- def checkClassType(tpt: Tree, existentialOK: Boolean, stablePrefix: Boolean): Boolean = {
- def errorNotClass(found: AnyRef) = { ClassTypeRequiredError(tpt, found); false }
- def check(tpe: Type): Boolean = tpe.normalize match {
- case TypeRef(pre, sym, _) if sym.isClass && !sym.isRefinementClass =>
- if (stablePrefix && !isPastTyper)
- if (!pre.isStable) {
- TypeNotAStablePrefixError(tpt, pre)
- false
- } else
- // A type projection like X#Y can get by the stable check if the
- // prefix is singleton-bounded, so peek at the tree too.
- tpt match {
- case SelectFromTypeTree(qual, _) if !isSingleType(qual.tpe) => errorNotClass(tpt)
- case _ => true
- }
- else
- true
- case ErrorType => true
- case PolyType(_, restpe) => check(restpe)
- case ExistentialType(_, restpe) if existentialOK => check(restpe)
- case AnnotatedType(_, underlying, _) => check(underlying)
- case t => errorNotClass(t)
+ def checkClassType(tpt: Tree): Boolean = {
+ val tpe = unwrapToClass(tpt.tpe)
+ isNonRefinementClassType(tpe) || errorNotClass(tpt, tpe)
+ }
+
+ /** Check that `tpt` refers to a class type with a stable prefix. */
+ def checkStablePrefixClassType(tpt: Tree): Boolean = {
+ val tpe = unwrapToStableClass(tpt.tpe)
+
+ def prefixIsStable = {
+ def checkPre = tpe match {
+ case TypeRef(pre, _, _) => pre.isStable || errorNotStable(tpt, pre)
+ case _ => true
+ }
+ // A type projection like X#Y can get by the stable check if the
+ // prefix is singleton-bounded, so peek at the tree too.
+ def checkTree = tpt match {
+ case SelectFromTypeTree(qual, _) => isSingleType(qual.tpe) || errorNotStable(tpt, qual.tpe)
+ case _ => true
+ }
+ checkPre && checkTree
}
- check(tpt.tpe)
+
+ isNonRefinementClassType(tpe) && (isPastTyper || prefixIsStable)
}
/** Check that type <code>tp</code> is not a subtype of itself.
@@ -643,13 +651,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
}
- private def isNarrowable(tpe: Type): Boolean = tpe match {
+ private def isNarrowable(tpe: Type): Boolean = unwrapWrapperTypes(tpe) match {
case TypeRef(_, _, _) | RefinedType(_, _) => true
- case ExistentialType(_, tpe1) => isNarrowable(tpe1)
- case AnnotatedType(_, tpe1, _) => isNarrowable(tpe1)
- case PolyType(_, tpe1) => isNarrowable(tpe1)
- case NullaryMethodType(tpe1) => isNarrowable(tpe1)
- case _ => !phase.erasedTypes
+ case _ => !phase.erasedTypes
}
/**
@@ -1438,7 +1442,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def validateParentClass(parent: Tree, superclazz: Symbol) {
if (!parent.isErrorTyped) {
val psym = parent.tpe.typeSymbol.initialize
- checkClassType(parent, false, true)
+ checkStablePrefixClassType(parent)
if (psym != superclazz) {
if (psym.isTrait) {
val ps = psym.info.parents
@@ -3353,7 +3357,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
def typedClassOf(tree: Tree, tpt: Tree, noGen: Boolean = false) =
- if (!checkClassType(tpt, true, false) && noGen) tpt
+ if (!checkClassType(tpt) && noGen) tpt
else atPos(tree.pos)(gen.mkClassOf(tpt.tpe))
protected def typedExistentialTypeTree(tree: ExistentialTypeTree, mode: Int): Tree = {
@@ -3665,7 +3669,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def typedNew(tpt: Tree) = {
val tpt1 = {
val tpt0 = typedTypeConstructor(tpt)
- if (checkClassType(tpt0, false, true))
+ if (checkStablePrefixClassType(tpt0))
if (tpt0.hasSymbol && !tpt0.symbol.typeParams.isEmpty) {
context.undetparams = cloneSymbols(tpt0.symbol.typeParams)
TypeTree().setOriginal(tpt0)