summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2012-04-13 12:14:26 +0100
committerPaul Phillips <paulp@improving.org>2012-04-13 12:36:04 +0100
commit5d42159cec3ac04310c35500cd9e01419b0fb587 (patch)
tree2690b93de3e620b341899b6971c42285ff9665d9 /src
parentf7ea088d4f1e682a68d236973d73aff6dd87e5c8 (diff)
downloadscala-5d42159cec3ac04310c35500cd9e01419b0fb587.tar.gz
scala-5d42159cec3ac04310c35500cd9e01419b0fb587.tar.bz2
scala-5d42159cec3ac04310c35500cd9e01419b0fb587.zip
Touching the untouchable.
extempore thinks polymorphism beats boolean constructor parameters any day of the week.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/reflect/internal/Types.scala77
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala2
2 files changed, 54 insertions, 25 deletions
diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala
index 8bb1d5e2fa..3f0d5c9c67 100644
--- a/src/compiler/scala/reflect/internal/Types.scala
+++ b/src/compiler/scala/reflect/internal/Types.scala
@@ -915,14 +915,10 @@ trait Types extends api.Types { self: SymbolTable =>
*/
def directObjectString = safeToString
- /** A test whether a type contains any unification type variables. */
+ /** A test whether a type contains any unification type variables.
+ * Overridden with custom logic except where trivially true.
+ */
def isGround: Boolean = this match {
- case tv@TypeVar(_, _) =>
- tv.untouchable || (tv.instValid && tv.constr.inst.isGround)
- case TypeRef(pre, sym, args) =>
- sym.isPackageClass || pre.isGround && (args forall (_.isGround))
- case SingleType(pre, sym) =>
- sym.isPackageClass || pre.isGround
case ThisType(_) | NoPrefix | WildcardType | NoType | ErrorType | ConstantType(_) =>
true
case _ =>
@@ -1258,6 +1254,8 @@ trait Types extends api.Types { self: SymbolTable =>
*/
abstract case class SingleType(pre: Type, sym: Symbol) extends SingletonType {
override val isTrivial: Boolean = pre.isTrivial
+ override def isGround = sym.isPackageClass || pre.isGround
+
// override def isNullable = underlying.isNullable
override def isNotNull = underlying.isNotNull
private[reflect] var underlyingCache: Type = NoType
@@ -2143,6 +2141,11 @@ trait Types extends api.Types { self: SymbolTable =>
}
}
+ override def isGround = (
+ sym.isPackageClass
+ || pre.isGround && args.forall(_.isGround)
+ )
+
def etaExpand: Type = {
// must initialise symbol, see test/files/pos/ticket0137.scala
val tpars = initializedTypeParams
@@ -2675,22 +2678,35 @@ trait Types extends api.Types { self: SymbolTable =>
else new TypeConstraint
}
def unapply(tv: TypeVar): Some[(Type, TypeConstraint)] = Some((tv.origin, tv.constr))
+ def untouchable(tparam: Symbol): TypeVar = createTypeVar(tparam, untouchable = true)
+ def apply(tparam: Symbol): TypeVar = createTypeVar(tparam, untouchable = false)
def apply(origin: Type, constr: TypeConstraint): TypeVar = apply(origin, constr, Nil, Nil)
- def apply(tparam: Symbol): TypeVar = apply(tparam.tpeHK, deriveConstraint(tparam), Nil, tparam.typeParams)
- def apply(tparam: Symbol, untouchable: Boolean): TypeVar = apply(tparam.tpeHK, deriveConstraint(tparam), Nil, tparam.typeParams, untouchable)
+ def apply(origin: Type, constr: TypeConstraint, args: List[Type], params: List[Symbol]): TypeVar =
+ createTypeVar(origin, constr, args, params, untouchable = false)
/** This is the only place TypeVars should be instantiated.
*/
- def apply(origin: Type, constr: TypeConstraint, args: List[Type], params: List[Symbol], untouchable: Boolean = false): TypeVar = {
+ private def createTypeVar(origin: Type, constr: TypeConstraint, args: List[Type], params: List[Symbol], untouchable: Boolean): TypeVar = {
val tv = (
- if (args.isEmpty && params.isEmpty) new TypeVar(origin, constr, untouchable)
- else if (args.size == params.size) new AppliedTypeVar(origin, constr, untouchable, params zip args)
- else if (args.isEmpty) new HKTypeVar(origin, constr, untouchable, params)
+ if (args.isEmpty && params.isEmpty) {
+ if (untouchable) new TypeVar(origin, constr) with UntouchableTypeVar
+ else new TypeVar(origin, constr)
+ }
+ else if (args.size == params.size) {
+ if (untouchable) new AppliedTypeVar(origin, constr, params zip args) with UntouchableTypeVar
+ else new AppliedTypeVar(origin, constr, params zip args)
+ }
+ else if (args.isEmpty) {
+ if (untouchable) new HKTypeVar(origin, constr, params) with UntouchableTypeVar
+ else new HKTypeVar(origin, constr, params)
+ }
else throw new Error("Invalid TypeVar construction: " + ((origin, constr, args, params)))
)
trace("create", "In " + tv.originLocation)(tv)
}
+ private def createTypeVar(tparam: Symbol, untouchable: Boolean): TypeVar =
+ createTypeVar(tparam.tpeHK, deriveConstraint(tparam), Nil, tparam.typeParams, untouchable)
}
/** Repack existential types, otherwise they sometimes get unpacked in the
@@ -2713,9 +2729,8 @@ trait Types extends api.Types { self: SymbolTable =>
class HKTypeVar(
_origin: Type,
_constr: TypeConstraint,
- _untouchable: Boolean,
override val params: List[Symbol]
- ) extends TypeVar(_origin, _constr, _untouchable) {
+ ) extends TypeVar(_origin, _constr) {
require(params.nonEmpty, this)
override def isHigherKinded = true
@@ -2727,9 +2742,8 @@ trait Types extends api.Types { self: SymbolTable =>
class AppliedTypeVar(
_origin: Type,
_constr: TypeConstraint,
- _untouchable: Boolean,
zippedArgs: List[(Symbol, Type)]
- ) extends TypeVar(_origin, _constr, _untouchable) {
+ ) extends TypeVar(_origin, _constr) {
require(zippedArgs.nonEmpty, this)
@@ -2740,6 +2754,23 @@ trait Types extends api.Types { self: SymbolTable =>
zippedArgs map { case (p, a) => p.name + "=" + a } mkString (origin + "[", ", ", "]")
)
}
+
+ trait UntouchableTypeVar extends TypeVar {
+ override def untouchable = true
+ override def isGround = true
+ override def registerTypeEquality(tp: Type, typeVarLHS: Boolean) = tp match {
+ case t: TypeVar if !t.untouchable =>
+ t.registerTypeEquality(this, !typeVarLHS)
+ case _ =>
+ super.registerTypeEquality(tp, typeVarLHS)
+ }
+ override def registerBound(tp: Type, isLowerBound: Boolean, isNumericBound: Boolean = false): Boolean = tp match {
+ case t: TypeVar if !t.untouchable =>
+ t.registerBound(this, !isLowerBound, isNumericBound)
+ case _ =>
+ super.registerBound(tp, isLowerBound, isNumericBound)
+ }
+ }
/** A class representing a type variable: not used after phase `typer`.
*
@@ -2752,9 +2783,9 @@ trait Types extends api.Types { self: SymbolTable =>
*/
class TypeVar(
val origin: Type,
- val constr0: TypeConstraint,
- val untouchable: Boolean = false // by other typevars
+ val constr0: TypeConstraint
) extends Type {
+ def untouchable = false // by other typevars
override def params: List[Symbol] = Nil
override def typeArgs: List[Type] = Nil
override def isHigherKinded = false
@@ -2767,6 +2798,7 @@ trait Types extends api.Types { self: SymbolTable =>
*/
var constr = constr0
def instValid = constr.instValid
+ override def isGround = instValid && constr.inst.isGround
/** The variable's skolemization level */
val level = skolemizationLevel
@@ -2941,9 +2973,7 @@ trait Types extends api.Types { self: SymbolTable =>
// to fall back on the individual base types. This warrants eventual re-examination.
// AM: I think we could use the `suspended` flag to avoid side-effecting during unification
-
- if (tp.isInstanceOf[TypeVar] && untouchable && !tp.asInstanceOf[TypeVar].untouchable) tp.asInstanceOf[TypeVar].registerBound(this, !isLowerBound, isNumericBound)
- else if (suspended) // constraint accumulation is disabled
+ if (suspended) // constraint accumulation is disabled
checkSubtype(tp, origin)
else if (constr.instValid) // type var is already set
checkSubtype(tp, constr.inst)
@@ -2967,8 +2997,7 @@ trait Types extends api.Types { self: SymbolTable =>
if(typeVarLHS) constr.inst =:= tp
else tp =:= constr.inst
- if (tp.isInstanceOf[TypeVar] && untouchable && !tp.asInstanceOf[TypeVar].untouchable) tp.asInstanceOf[TypeVar].registerTypeEquality(this, !typeVarLHS)
- else if (suspended) tp =:= origin
+ if (suspended) tp =:= origin
else if (constr.instValid) checkIsSameType(tp)
else isRelatable(tp) && {
val newInst = wildcardToTypeVarMap(tp)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 2de86c67bf..eb8bef3b58 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -107,7 +107,7 @@ trait Implicits {
*/
def allViewsFrom(tp: Type, context: Context, tpars: List[Symbol]): List[(SearchResult, List[TypeConstraint])] = {
// my untouchable typevars are better than yours (they can't be constrained by them)
- val tvars = tpars map (TypeVar.apply(_, untouchable = true))
+ val tvars = tpars map (TypeVar untouchable _)
val tpSubsted = tp.subst(tpars, tvars)
val search = new ImplicitSearch(EmptyTree, functionType(List(tpSubsted), AnyClass.tpe), true, context.makeImplicit(false))