diff options
author | Martin Odersky <odersky@gmail.com> | 2016-07-07 18:33:58 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2016-07-11 13:35:08 +0200 |
commit | 223705d88fdeee1ef337f8c1c8b3144a643a6268 (patch) | |
tree | aaf0a11d3d5e6246d27d8fc959866d82600a6079 /src/dotty/tools/dotc/core/ConstraintHandling.scala | |
parent | 78b2672d7440979c36800cbd4f1d7dbf867a4a16 (diff) | |
download | dotty-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/ConstraintHandling.scala')
-rw-r--r-- | src/dotty/tools/dotc/core/ConstraintHandling.scala | 51 |
1 files changed, 51 insertions, 0 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`: * |