Dotty Documentation


object Inferencing
extends Object with Serializable

[-] Constructors

[-] Members

[+] private class IsFullyDefinedAccumulator

The accumulator which forces type variables using the policy encoded in force and returns whether the type is fully defined. The direction in which a type variable is instantiated is determined as follows: 1. T is minimized if the constraint over T is only from below (i.e. constrained lower bound != given lower bound and constrained upper bound == given upper bound). 2. T is maximized if the constraint over T is only from above (i.e. constrained upper bound != given upper bound and constrained lower bound == given lower bound). If (1) and (2) do not apply: 3. T is maximized if it appears only contravariantly in the given type. 4. T is minimized in all other cases.

The instantiation is done in two phases: 1st Phase: Try to instantiate minimizable type variables to their lower bound. Record whether successful. 2nd Phase: If first phase was successful, instantiate all remaining type variables to their upper bound.

[+] type VarianceMap = SimpleIdentityMap [ TypeVar, Integer ]
[+] def companionRef ( tp: Type ) ( implicit ctx: Context ) : Type

Following type aliases and stripping refinements and annotations, if one arrives at a class type reference where the class has a companion module, a reference to that companion module. Otherwise NoType

[+] def constrainPatternType ( tp: Type , pt: Type ) ( implicit ctx: Context ) : Boolean

Derive information about a pattern type by comparing it with some variant of the static scrutinee type. We have the following situation in case of a (dynamic) pattern match:

 StaticScrutineeType           PatternType
                   \            /

If PatternType is not a subtype of StaticScrutineeType, there's no information to be gained. Now let's say we can prove thatPatternType <: StaticScrutineeType`.

            |         \
            |          \
            |           \
            |            PatternType
            |          /

What can we say about the relationship of parameter types between PatternType and DynamicScrutineeType?

  • If DynamicScrutineeType refines the type parameters of StaticScrutineeType in the same way as PatternType ("invariant refinement"), the subtype test PatternType <:< StaticScrutineeType tells us all we need to know.
  • Otherwise, if variant refinement is a possibility we can only make predictions about invariant parameters of StaticScrutineeType. Hence we do a subtype test where PatternType <: widenVariantParams(StaticScrutineeType), where widenVariantParams replaces all type argument of variant parameters with empty bounds.

Invariant refinement can be assumed if PatternType's class(es) are final or case classes (because of RefChecks#checkCaseClassInheritanceInvariant).

TODO: Update so that GADT symbols can be variant, and we special case final class types in patterns

[+] def fullyDefinedType ( tp: Type , what: String , span: Span ) ( implicit ctx: Context ) : Type

The fully defined type, where all type variables are forced. Throws an error if type contains wildcards.

[+] def inferTypeParams ( tree: Tree , pt: Type ) ( implicit ctx: Context ) : Tree

If tree has a type lambda type, infer its type parameters by comparing with expected type pt

[+] private def instDirection ( param: TypeParamRef ) ( implicit ctx: Context ) : Int

The instantiation direction for given poly param computed from the constraint:

[+] def instantiateDependent ( tp: Type , tparams: List [ Symbol ] , vparamss: List [ List [ Symbol ] ] ) ( implicit ctx: Context ) : Unit

Instantiate any type variables in tp whose bounds contain a reference to one of the parameters in tparams or vparamss.

[+] def instantiateSelected ( tp: Type , tvars: List [ Type ] ) ( implicit ctx: Context ) : Unit

Instantiate selected type variables tvars in type tp

[+] def isFullyDefined ( tp: Type , force: Value ) ( implicit ctx: Context ) : Boolean

Is type fully defined, meaning the type does not contain wildcard types or uninstantiated type variables. As a side effect, this will minimize any uninstantiated type variables, according to the given force degree, but only if the overall result of isFullyDefined is true. Variables that are successfully minimized do not count as uninstantiated.

[+] def isSkolemFree ( tp: Type ) ( implicit ctx: Context ) : Boolean
[+] def maximizeType ( tp: Type , span: Span , fromScala2x: Boolean ) ( implicit ctx: Context ) : List [ Symbol ]

Instantiate undetermined type variables so that type tp is maximized.

[+] def tvarsInParams ( tree: Tree , locked: TypeVars ) ( implicit ctx: Context ) : List [ TypeVar ]

The list of uninstantiated type variables bound by some prefix of type T which occur in at least one formal parameter type of a prefix application. Considered prefixes are: - The function f of an application node f(e1, .., en) - The function f of a type application node f[T1, ..., Tn] - The prefix p of a selection p.f. - The result expression e of a block {s1; .. sn; e}.

[+] private def variances ( tp: Type ) ( implicit ctx: Context ) : VarianceMap

All occurrences of type vars in this type that satisfy predicate include mapped to their variances (-1/0/1) in this type, where -1 means: only covariant occurrences +1 means: only covariant occurrences 0 means: mixed or non-variant occurrences

Note: We intentionally use a relaxed version of variance here, where the variance does not change under a prefix of a named type (the strict version makes prefixes invariant). This turns out to be better for type inference. In a nutshell, if a type variable occurs like this:

(U? >: x.type) # T

we want to instantiate U to x.type right away. No need to wait further.