diff options
-rw-r--r-- | src/compiler/scala/reflect/internal/Types.scala | 17 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 68 |
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) |