aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-07-07 18:33:58 +0200
committerMartin Odersky <odersky@gmail.com>2016-07-11 13:35:08 +0200
commit223705d88fdeee1ef337f8c1c8b3144a643a6268 (patch)
treeaaf0a11d3d5e6246d27d8fc959866d82600a6079 /src/dotty/tools/dotc/core
parent78b2672d7440979c36800cbd4f1d7dbf867a4a16 (diff)
downloaddotty-223705d88fdeee1ef337f8c1c8b3144a643a6268.tar.gz
dotty-223705d88fdeee1ef337f8c1c8b3144a643a6268.tar.bz2
dotty-223705d88fdeee1ef337f8c1c8b3144a643a6268.zip
Refactor Typevar instantiation
It seemed more cohesive to keep the concepts of "instanceType" and "approximation" side-by-side.
Diffstat (limited to 'src/dotty/tools/dotc/core')
-rw-r--r--src/dotty/tools/dotc/core/ConstraintHandling.scala51
-rw-r--r--src/dotty/tools/dotc/core/Types.scala44
2 files changed, 52 insertions, 43 deletions
diff --git a/src/dotty/tools/dotc/core/ConstraintHandling.scala b/src/dotty/tools/dotc/core/ConstraintHandling.scala
index dfce9317b..d21f62440 100644
--- a/src/dotty/tools/dotc/core/ConstraintHandling.scala
+++ b/src/dotty/tools/dotc/core/ConstraintHandling.scala
@@ -171,6 +171,57 @@ trait ConstraintHandling {
inst
}
+ /** The instance type of `param` in the current constraint (which contains `param`).
+ * If `fromBelow` is true, the instance type is the lub of the parameter's
+ * lower bounds; otherwise it is the glb of its upper bounds. However,
+ * a lower bound instantiation can be a singleton type only if the upper bound
+ * is also a singleton type.
+ */
+ def instanceType(param: PolyParam, fromBelow: Boolean): Type = {
+ def upperBound = constraint.fullUpperBound(param)
+ def isSingleton(tp: Type): Boolean = tp match {
+ case tp: SingletonType => true
+ case AndType(tp1, tp2) => isSingleton(tp1) | isSingleton(tp2)
+ case OrType(tp1, tp2) => isSingleton(tp1) & isSingleton(tp2)
+ case _ => false
+ }
+ def isFullyDefined(tp: Type): Boolean = tp match {
+ case tp: TypeVar => tp.isInstantiated && isFullyDefined(tp.instanceOpt)
+ case tp: TypeProxy => isFullyDefined(tp.underlying)
+ case tp: AndOrType => isFullyDefined(tp.tp1) && isFullyDefined(tp.tp2)
+ case _ => true
+ }
+ def isOrType(tp: Type): Boolean = tp.stripTypeVar.dealias match {
+ case tp: OrType => true
+ case tp: RefinedOrRecType => isOrType(tp.parent)
+ case AndType(tp1, tp2) => isOrType(tp1) | isOrType(tp2)
+ case WildcardType(bounds: TypeBounds) => isOrType(bounds.hi)
+ case _ => false
+ }
+
+ // First, solve the constraint.
+ var inst = approximation(param, fromBelow)
+
+ // Then, approximate by (1.) - (3.) and simplify as follows.
+ // 1. If instance is from below and is a singleton type, yet
+ // upper bound is not a singleton type, widen the instance.
+ if (fromBelow && isSingleton(inst) && !isSingleton(upperBound))
+ inst = inst.widen
+
+ inst = inst.simplified
+
+ // 2. If instance is from below and is a fully-defined union type, yet upper bound
+ // is not a union type, approximate the union type from above by an intersection
+ // of all common base types.
+ if (fromBelow && isOrType(inst) && isFullyDefined(inst) && !isOrType(upperBound))
+ inst = inst.approximateUnion
+
+ // 3. If instance is from below, and upper bound has open named parameters
+ // make sure the instance has all named parameters of the bound.
+ if (fromBelow) inst = inst.widenToNamedTypeParams(param.namedTypeParams)
+ inst
+ }
+
/** Constraint `c1` subsumes constraint `c2`, if under `c2` as constraint we have
* for all poly params `p` defined in `c2` as `p >: L2 <: U2`:
*
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 786c74069..03fdcb957 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -2878,53 +2878,11 @@ object Types {
* is also a singleton type.
*/
def instantiate(fromBelow: Boolean)(implicit ctx: Context): Type = {
- def upperBound = ctx.typerState.constraint.fullUpperBound(origin)
- def isSingleton(tp: Type): Boolean = tp match {
- case tp: SingletonType => true
- case AndType(tp1, tp2) => isSingleton(tp1) | isSingleton(tp2)
- case OrType(tp1, tp2) => isSingleton(tp1) & isSingleton(tp2)
- case _ => false
- }
- def isFullyDefined(tp: Type): Boolean = tp match {
- case tp: TypeVar => tp.isInstantiated && isFullyDefined(tp.instanceOpt)
- case tp: TypeProxy => isFullyDefined(tp.underlying)
- case tp: AndOrType => isFullyDefined(tp.tp1) && isFullyDefined(tp.tp2)
- case _ => true
- }
- def isOrType(tp: Type): Boolean = tp.stripTypeVar.dealias match {
- case tp: OrType => true
- case tp: RefinedOrRecType => isOrType(tp.parent)
- case AndType(tp1, tp2) => isOrType(tp1) | isOrType(tp2)
- case WildcardType(bounds: TypeBounds) => isOrType(bounds.hi)
- case _ => false
- }
-
- // First, solve the constraint.
- var inst = ctx.typeComparer.approximation(origin, fromBelow)
-
- // Then, approximate by (1.) - (3.) and simplify as follows.
- // 1. If instance is from below and is a singleton type, yet
- // upper bound is not a singleton type, widen the instance.
- if (fromBelow && isSingleton(inst) && !isSingleton(upperBound))
- inst = inst.widen
-
- inst = inst.simplified
-
- // 2. If instance is from below and is a fully-defined union type, yet upper bound
- // is not a union type, approximate the union type from above by an intersection
- // of all common base types.
- if (fromBelow && isOrType(inst) && isFullyDefined(inst) && !isOrType(upperBound))
- inst = inst.approximateUnion
-
- // 3. If instance is from below, and upper bound has open named parameters
- // make sure the instance has all named parameters of the bound.
- if (fromBelow) inst = inst.widenToNamedTypeParams(this.namedTypeParams)
-
+ val inst = ctx.typeComparer.instanceType(origin, fromBelow)
if (ctx.typerState.isGlobalCommittable)
assert(!inst.isInstanceOf[PolyParam], i"bad inst $this := $inst, constr = ${ctx.typerState.constraint}")
// If this fails, you might want to turn on Config.debugCheckConstraintsClosed
// to help find the root of the problem.
-
instantiateWith(inst)
}