Dotty Documentation

0.4.0-bin-SNAPSHOT

trait ConstraintHandling

Methods for adding constraints and solving them.

What goes into a Constraint as opposed to a ConstrainHandler?

Constraint code is purely functional: Operations get constraints and produce new ones. Constraint code does not have access to a type-comparer. Anything regarding lubs and glbs has to be done elsewhere.

By comparison: Constraint handlers are parts of type comparers and can use their functionality. Constraint handlers update the current constraint as a side effect.

[-] Constructors

[-] Members

[+] private var addConstraintInvocations : Int
[+] protected var comparedTypeLambdas : Set [ TypeLambda ]

We are currently comparing type lambdas. Used as a flag for optimization: when false, no need to do an expensive pruneLambdaParams

[+] implicit val ctx : Context
[+] protected var frozenConstraint : Boolean

If the constraint is frozen we cannot add new bounds to the constraint.

[+] protected var homogenizeArgs : Boolean

If set, align arguments S1, S2when taking the glb T1 { X = S1 } & T2 { X = S2 } of a constraint upper bound for some type parameter. Aligning means computing S1 =:= S2 which may change the current constraint. See note in TypeComparer#distributeAnd.

[+] val state : TyperState
[+] protected def addConstraint ( param: TypeParamRef , bound: Type , fromBelow: Boolean ) : Boolean

Add constraint param <: bound if fromBelow is false, param >: bound otherwise. bound is assumed to be in normalized form, as specified in firstTry and secondTry of TypeComparer. In particular, it should not be an alias type, lazy ref, typevar, wildcard type, error type. In addition, upper bounds may not be AndTypes and lower bounds may not be OrTypes. This is assured by the way isSubType is organized.

[+] private def addConstraintInvocations_= ( x$1: Int ) : Unit
[+] protected def addLess ( p1: TypeParamRef , p2: TypeParamRef ) : Boolean
[+] protected def addLowerBound ( param: TypeParamRef , bound: Type ) : Boolean
[+] private def addOneBound ( param: TypeParamRef , bound: Type , isUpper: Boolean ) : Boolean
[+] def addToConstraint ( tl: TypeLambda , tvars: List [ TypeVar ] ) : Unit

Add type lambda tl, possibly with type variables tvars, to current constraint and propagate all bounds.

[+] protected def addUpperBound ( param: TypeParamRef , bound: Type ) : Boolean
[+] final def approximation ( param: TypeParamRef , fromBelow: Boolean ) : Type

Solve constraint set for given type parameter param. If fromBelow is true the parameter is approximated by its lower bound, otherwise it is approximated by its upper bound. However, any occurrences of the parameter in a refinement somewhere in the bound are removed. Also wildcard types in bounds are approximated by their upper or lower bounds. (Such occurrences can arise for F-bounded types). The constraint is left unchanged.

[+] final def bounds ( param: TypeParamRef ) : TypeBounds

The current bounds of type parameter param

[+] final def canConstrain ( param: TypeParamRef ) : Boolean

Can param be constrained with new bounds?

[+] def checkPropagated ( msg: => String ) ( result: Boolean ) : Boolean

Check that constraint is fully propagated. See comment in Config.checkConstraintsPropagated

[+] protected def comparedTypeLambdas_= ( x$1: Set [ TypeLambda ] ) : Unit

We are currently comparing type lambdas. Used as a flag for optimization: when false, no need to do an expensive pruneLambdaParams

[+] protected def frozenConstraint_= ( x$1: Boolean ) : Unit

If the constraint is frozen we cannot add new bounds to the constraint.

[+] protected def homogenizeArgs_= ( x$1: Boolean ) : Unit

If set, align arguments S1, S2when taking the glb T1 { X = S1 } & T2 { X = S2 } of a constraint upper bound for some type parameter. Aligning means computing S1 =:= S2 which may change the current constraint. See note in TypeComparer#distributeAnd.

[+] def instanceType ( param: TypeParamRef , fromBelow: Boolean ) : Type

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.

[+] protected def isSameType ( tp1: Type , tp2: Type ) : Boolean
[+] final def isSameTypeWhenFrozen ( tp1: Type , tp2: Type ) : Boolean
[+] protected final def isSatisfiable : Boolean

Test whether the lower bounds of all parameters in this constraint are a solution to the constraint.

[+] protected def isSubType ( tp1: Type , tp2: Type ) : Boolean
[+] protected def isSubType ( tp1: Type , tp2: Type , whenFrozen: Boolean ) : Boolean
[+] final def isSubTypeWhenFrozen ( tp1: Type , tp2: Type ) : Boolean
[+] def narrowedBound ( param: TypeParamRef , bound: Type , isUpper: Boolean ) ( implicit ctx: Context ) : TypeBounds

Narrow one of the bounds of type parameter param If isUpper is true, ensure that param <:bound, otherwise ensure thatparam >: bound`.

[+] protected final def subsumes ( c1: Constraint , c2: Constraint , pre: Constraint ) : Boolean

Constraint c1 subsumes constraint c2, if under c2 as constraint we have for all poly params p defined in c2 as p >: L2 <: U2:

c1 defines p with bounds p >: L1 <: U1, and L2 <: L1, and U1 <: U2

Both c1 and c2 are required to derive from constraint pre, possibly narrowing it with further bounds.

[+] protected def tryInstantiate ( param: TypeParamRef , tp: Type ) : Boolean

Instantiate param to tp if the constraint stays satisfiable

[+] private def unify ( p1: TypeParamRef , p2: TypeParamRef ) : Boolean

Make p2 = p1, transfer all bounds of p2 to p1