From 17356bf8a3eddb5b6652884ee5b96970d3ddb6cf Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 31 Mar 2012 12:16:30 -0700 Subject: More principled unwrapping of types. Made generic type unwrapper for use by the many methods which need various types to be transparent with respect to the operation being performed. AnnotatedType, PolyType, NullaryMethodType, and ExistentialType all commonly match this description. --- .../scala/tools/nsc/typechecker/Typers.scala | 68 ++++++++++++---------- 1 file changed, 36 insertions(+), 32 deletions(-) (limited to 'src/compiler/scala/tools/nsc/typechecker') 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 tp 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) -- cgit v1.2.3