summaryrefslogtreecommitdiff
path: root/src/reflect/scala/reflect/internal/Types.scala
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2013-08-27 11:40:28 +0200
committerJason Zaugg <jzaugg@gmail.com>2013-08-27 16:26:16 +0200
commit3eebc99432075fdffabf8859df3dc8b2ded8df9c (patch)
tree0b4f4413976a999f1cff1cbe28f0486693f74fa7 /src/reflect/scala/reflect/internal/Types.scala
parentb67fecd0f178ea70e4fa9823c408e52437426403 (diff)
downloadscala-3eebc99432075fdffabf8859df3dc8b2ded8df9c.tar.gz
scala-3eebc99432075fdffabf8859df3dc8b2ded8df9c.tar.bz2
scala-3eebc99432075fdffabf8859df3dc8b2ded8df9c.zip
SI-7785 Preserve TypeVar suspension through TypeMaps
During `findMember`, TypeVars in `this` are placed into suspended animation. This is to avoid running into recursive types when matching members to those in base classes. However, the mechanism used to do this is superficial, and doesn't work when TypeVars are copied by TypeMaps. This seems to crop up when using `AppliedTypeVar` with higher-kinded type vars. In the enclosed test case, the cyclic type led to a SOE in CommonOwnerMap. This commit allows a TypeVar to delegate its `suspended` attribute to the TypeVar from which it was copied. This is done in `TypeVar#applyArgs`, which is called by: // TypeMap#mapOver case tv@TypeVar(_, constr) => if (constr.instValid) this(constr.inst) else tv.applyArgs(mapOverArgs(tv.typeArgs, tv.params)) We should review the other places this is called to make sure that it make sense to link in this way: Types#appliedType TypeVar#normalize
Diffstat (limited to 'src/reflect/scala/reflect/internal/Types.scala')
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala15
1 files changed, 14 insertions, 1 deletions
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index b4ae384594..6305cbaea3 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -2847,6 +2847,9 @@ trait Types
// but pattern-matching returned the original constr0 (a bug)
// now, pattern-matching returns the most recent constr
object TypeVar {
+ private val ConstantTrue = ConstantType(Constant(true))
+ private val ConstantFalse = ConstantType(Constant(false))
+
@inline final def trace[T](action: String, msg: => String)(value: T): T = {
if (traceTypeVars) {
val s = msg match {
@@ -3003,6 +3006,7 @@ trait Types
this
else if (newArgs.size == params.size) {
val tv = TypeVar(origin, constr, newArgs, params)
+ tv.linkSuspended(this)
TypeVar.trace("applyArgs", "In " + originLocation + ", apply args " + newArgs.mkString(", ") + " to " + originName)(tv)
}
else
@@ -3065,7 +3069,16 @@ trait Types
// </region>
// ignore subtyping&equality checks while true -- see findMember
- private[Types] var suspended = false
+ // OPT: This could be Either[TypeVar, Boolean], but this encoding was chosen instead to save allocations.
+ private var _suspended: Type = TypeVar.ConstantFalse
+ private[Types] def suspended: Boolean = (_suspended: @unchecked) match {
+ case TypeVar.ConstantFalse => false
+ case TypeVar.ConstantTrue => true
+ case tv: TypeVar => tv.suspended
+ }
+ private[Types] def suspended_=(b: Boolean): Unit = _suspended = if (b) TypeVar.ConstantTrue else TypeVar.ConstantFalse
+ // SI-7785 Link the suspended attribute of a TypeVar created in, say, a TypeMap (e.g. AsSeenFrom) to its originator
+ private[Types] def linkSuspended(origin: TypeVar): Unit = _suspended = origin
/** Called when a TypeVar is involved in a subtyping check. Result is whether
* this TypeVar could plausibly be a [super/sub]type of argument `tp` and if so,