Provides methods to compare types.
Attributes
- Companion:
- object
- Graph
- Supertypes
- Known subtypes
- class ExplainingTypeComparerclass TrackingTypeComparer
Members list
Type members
Inherited classlikes
An approximating map that prevents types nested deeper than maxLevel as well as WildcardTypes from leaking into the constraint.
An approximating map that prevents types nested deeper than maxLevel as well as WildcardTypes from leaking into the constraint.
Attributes
- Inherited from:
- ConstraintHandling
- Graph
- Supertypes
- class AvoidMaptrait IdempotentCaptRefMapclass AvoidWildcardsMapclass ApproximatingTypeMapclass TypeMapclass VariantTraversalclass Objecttrait Matchableclass Any
Value members
Concrete methods
Form a normalized conjunction of two types.
Note: For certain types, &
is distributed inside the type. This holds for
all types which are not value types (e.g. TypeBounds, ClassInfo,
ExprType, LambdaType). Also, when forming an &
,
instantiated TypeVars are dereferenced and annotations are stripped.
Finally, refined types with the same refined name are
opportunistically merged.
Form a normalized conjunction of two types.
Note: For certain types, &
is distributed inside the type. This holds for
all types which are not value types (e.g. TypeBounds, ClassInfo,
ExprType, LambdaType). Also, when forming an &
,
instantiated TypeVars are dereferenced and annotations are stripped.
Finally, refined types with the same refined name are
opportunistically merged.
Attributes
Attributes
- Definition Classes
If both tp1
and tp2
have atoms information, compare the atoms
in a Some, otherwise None.
If both tp1
and tp2
have atoms information, compare the atoms
in a Some, otherwise None.
Attributes
- knownSingletons
If true, we are coming from a comparison of two singleton types This influences the comparison as shown below: Say you have singleton types p.type and q.type the atoms of p.type are
{p.type}..{p.type}
, and the atoms ofq.type
are{}..{p.type}
. Normally the atom comparison between p's atoms and q's atoms gives false. But in this case we know thatq.type
is an alias ofp.type
so we are still allowed to conclude thatp.type <:< q.type
. A situation where this happens is in i6635.scala. Here, p: A, q: B & p.type and we want to conclude that p.type <: q.type.
Optionally, the constant c
such that tp <:< ConstantType(c)
Optionally, the constant c
such that tp <:< ConstantType(c)
Attributes
Can comparing this type on the left lead to an either? This is the case if the type is and AndType or contains embedded occurrences of AndTypes
Can comparing this type on the left lead to an either? This is the case if the type is and AndType or contains embedded occurrences of AndTypes
Attributes
Decompose into conjunction of types each of which has only a single refinement
Decompose into conjunction of types each of which has only a single refinement
Attributes
The trace of comparison operations when performing op
The trace of comparison operations when performing op
Attributes
The greatest lower bound of two types
The greatest lower bound of two types
Attributes
Try to produce joint arguments for a glb A[T_1, ..., T_n] & A[T_1', ..., T_n']
using
the following strategies:
Try to produce joint arguments for a glb A[T_1, ..., T_n] & A[T_1', ..., T_n']
using
the following strategies:
- if arguments are the same, that argument.
- if corresponding parameter variance is co/contra-variant, the glb/lub.
- if at least one of the arguments if a TypeBounds, the union of the bounds.
- if homogenizeArgs is set, and arguments can be unified by instantiating type parameters, the unified argument.
- otherwise NoType
The unification rule is contentious because it cuts the constraint set.
Therefore it is subject to Config option alignArgsInAnd
.
Attributes
Does type tp1
have a member with name name
whose normalized type is a subtype of
the normalized type of the refinement of tp2
?
Normalization is as follows: If tp2
contains a skolem to its refinement type,
rebase both itself and the member info of tp
on a freshly created skolem type.
Does type tp1
have a member with name name
whose normalized type is a subtype of
the normalized type of the refinement of tp2
?
Normalization is as follows: If tp2
contains a skolem to its refinement type,
rebase both itself and the member info of tp
on a freshly created skolem type.
Attributes
Defer constraining type variables when compared against prototypes
Defer constraining type variables when compared against prototypes
Attributes
Same as isSameType
but also can be applied to overloaded TermRefs, where
two overloaded refs are the same if they have pairwise equal alternatives
Same as isSameType
but also can be applied to overloaded TermRefs, where
two overloaded refs are the same if they have pairwise equal alternatives
Attributes
Two types are the same if they are mutual subtypes of each other.
To avoid exponential blowup for deeply nested invariant applied types,
we cache successes once the stack of outstanding isSameTypes reaches
depth startSameTypeTrackingLevel
. See pos/i15525.scala, where this matters.
Two types are the same if they are mutual subtypes of each other.
To avoid exponential blowup for deeply nested invariant applied types,
we cache successes once the stack of outstanding isSameTypes reaches
depth startSameTypeTrackingLevel
. See pos/i15525.scala, where this matters.
Attributes
Subtype test for corresponding arguments in args1
, args2
according to
variances in type parameters tparams2
.
Subtype test for corresponding arguments in args1
, args2
according to
variances in type parameters tparams2
.
Attributes
- tp1
The applied type containing
args1
- tparams2
The type parameters of the type constructor applied to
args2
op(tp1, tp2)
unless tp1
and tp2
are type-constructors.
In the latter case, combine tp1
and tp2
under a type lambda like this:
op(tp1, tp2)
unless tp1
and tp2
are type-constructors.
In the latter case, combine tp1
and tp2
under a type lambda like this:
[X1, ..., Xn] -> op(tp1[X1, ..., Xn], tp2[X1, ..., Xn])
Attributes
The least upper bound of two types
The least upper bound of two types
Attributes
- canConstrain
If true, new constraints might be added to simplify the lub.
- isSoft
If the lub is a union, this determines whether it's a soft union.
- Note:
We do not admit singleton types in or-types as lubs.
Try to produce joint arguments for a lub A[T_1, ..., T_n] | A[T_1', ..., T_n']
using
the following strategies:
Try to produce joint arguments for a lub A[T_1, ..., T_n] | A[T_1', ..., T_n']
using
the following strategies:
- if arguments are the same, that argument.
- if corresponding parameter variance is co/contra-variant, the lub/glb.
- otherwise a TypeBounds containing both arguments
Attributes
A function implementing tp1
matches tp2
.
A function implementing tp1
matches tp2
.
Attributes
Do the parameter types of tp1
and tp2
match in a way that allows tp1
to override tp2
? Two modes: precise or not.
If precise
is set (which is the default) this is the case if they're pairwise =:=
.
Otherwise parameters in tp2
must be subtypes of corresponding parameters in tp1
.
Do the parameter types of tp1
and tp2
match in a way that allows tp1
to override tp2
? Two modes: precise or not.
If precise
is set (which is the default) this is the case if they're pairwise =:=
.
Otherwise parameters in tp2
must be subtypes of corresponding parameters in tp1
.
Attributes
Do the parameter types of tp1
and tp2
match in a way that allows tp1
to override tp2
? This is the case if they're pairwise >:>.
Do the parameter types of tp1
and tp2
match in a way that allows tp1
to override tp2
? This is the case if they're pairwise >:>.
Attributes
Optionally, the n
such that tp <:< ConstantType(Constant(n: Int))
Optionally, the n
such that tp <:< ConstantType(Constant(n: Int))
Attributes
Form a normalized conjunction of two types.
Note: For certain types, |
is distributed inside the type. This holds for
all types which are not value types (e.g. TypeBounds, ClassInfo,
ExprType, LambdaType). Also, when forming an |
,
instantiated TypeVars are dereferenced and annotations are stripped.
Form a normalized conjunction of two types.
Note: For certain types, |
is distributed inside the type. This holds for
all types which are not value types (e.g. TypeBounds, ClassInfo,
ExprType, LambdaType). Also, when forming an |
,
instantiated TypeVars are dereferenced and annotations are stripped.
Attributes
- isErased
Apply erasure semantics. If erased is true, instead of creating an OrType, the lub will be computed using TypeCreator#erasedLub.
- isSoft
If the result is a union, this determines whether it's a soft union.
Are tp1
and tp2
provablyDisjoint types?
Are tp1
and tp2
provablyDisjoint types?
true
implies that we found a proof; uncertainty defaults to false
.
Proofs rely on the following properties of Scala types:
- Single inheritance of classes
- Final classes cannot be extended
- ConstantTypes with distinct values are non intersecting
- TermRefs with distinct values are non intersecting
- There is no value of type Nothing
Note on soundness: the correctness of match types relies on on the property that in all possible contexts, the same match type expression is either stuck or reduces to the same case.
Attributes
Is tp
an empty type?
Is tp
an empty type?
true
implies that we found a proof; uncertainty defaults to false
.
Attributes
Record statistics about the total number of subtype checks and the number of "successful" subtype checks, i.e. checks that form part of a subtype derivation tree that's ultimately successful.
Record statistics about the total number of subtype checks and the number of "successful" subtype checks, i.e. checks that form part of a subtype derivation tree that's ultimately successful.
Attributes
Show subtype goal that led to an assertion failure
Show subtype goal that led to an assertion failure
Attributes
If the range tp1..tp2
consist of a single type, that type, otherwise NoType. This is the case if
tp1 =:= tp2, but also if
tp1 <:< tp2,
tp1is a singleton type, and
tp2derives from
scala.Singleton` (or vice-versa). Examples of the latter case:
If the range tp1..tp2
consist of a single type, that type, otherwise NoType. This is the case if
tp1 =:= tp2, but also if
tp1 <:< tp2,
tp1is a singleton type, and
tp2derives from
scala.Singleton` (or vice-versa). Examples of the latter case:
"name".type .. Singleton "name".type .. String & Singleton Singleton .. "name".type String & Singleton .. "name".type
All consist of the single type "name".type
.
Attributes
Is a subtype check in progress? In that case we may not permanently instantiate type variables, because the corresponding constraint might still be retracted and the instantiation should then be reversed.
Is a subtype check in progress? In that case we may not permanently instantiate type variables, because the corresponding constraint might still be retracted and the instantiation should then be reversed.
Attributes
A hook for showing subtype traces. Overridden in ExplainingTypeComparer
A hook for showing subtype traces. Overridden in ExplainingTypeComparer
Attributes
Inherited methods
Attributes
- Inherited from:
- ConstraintHandling
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.
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.
Attributes
- Inherited from:
- ConstraintHandling
Attributes
- Inherited from:
- ConstraintHandling
Attributes
- Inherited from:
- ConstraintHandling
Add type lambda tl
, possibly with type variables tvars
, to current constraint
and propagate all bounds.
Add type lambda tl
, possibly with type variables tvars
, to current constraint
and propagate all bounds.
Attributes
- tvars
See Constraint#add
- Inherited from:
- ConstraintHandling
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, unless the upper bound
contains a reference to the parameter itself (such occurrences can arise
for F-bounded types, addOneBound
ensures that they never occur in the
lower bound).
The solved type is not allowed to contain references to types nested deeper
than maxLevel
.
Wildcard types in bounds are approximated by their upper or lower bounds.
The constraint is left unchanged.
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, unless the upper bound
contains a reference to the parameter itself (such occurrences can arise
for F-bounded types, addOneBound
ensures that they never occur in the
lower bound).
The solved type is not allowed to contain references to types nested deeper
than maxLevel
.
Wildcard types in bounds are approximated by their upper or lower bounds.
The constraint is left unchanged.
Attributes
- Returns:
the instantiating type
- Inherited from:
- ConstraintHandling
Is param
assumed to be a sub- and super-type of any other type?
This holds if TypeVarsMissContext
is set unless param
is a part
of a MatchType that is currently normalized.
Is param
assumed to be a sub- and super-type of any other type?
This holds if TypeVarsMissContext
is set unless param
is a part
of a MatchType that is currently normalized.
Attributes
- Inherited from:
- ConstraintHandling
If param
is nested deeper than maxLevel
, try to instantiate it to a
fresh type variable of level maxLevel
and return the new variable.
If this isn't possible, throw a TypeError.
If param
is nested deeper than maxLevel
, try to instantiate it to a
fresh type variable of level maxLevel
and return the new variable.
If this isn't possible, throw a TypeError.
Attributes
- Inherited from:
- ConstraintHandling
The current bounds of type parameter param
Can param
be constrained with new bounds?
Check that constraint is fully propagated. See comment in Config.checkConstraintsPropagated
Check that constraint is fully propagated. See comment in Config.checkConstraintsPropagated
Attributes
- Inherited from:
- ConstraintHandling
Attributes
- Inherited from:
- ConstraintHandling
Derive type and GADT constraints that necessarily follow from a pattern with the given type matching a scrutinee of the given type.
Derive type and GADT constraints that necessarily follow from a pattern with the given type matching a scrutinee of the given type.
This function breaks down scrutinee and pattern types into subcomponents between which there must be a subtyping relationship, and derives constraints from those relationships. We have the following situation in case of a (dynamic) pattern match:
StaticScrutineeType PatternType
\ /
DynamicScrutineeType
In simple cases, it must hold that PatternType <: StaticScrutineeType
:
StaticScrutineeType
| \
| PatternType
| /
DynamicScrutineeType
A good example of a situation where the above must hold is when static scrutinee type is the root of an enum, and the pattern is an unapply of a case class, or a case object literal (of that enum).
In slightly more complex cases, we may need to upcast StaticScrutineeType
:
SharedPatternScrutineeSuperType
/ \
StaticScrutineeType PatternType \ / DynamicScrutineeType
This may be the case if the scrutinee is a singleton type or a path-dependent type. It is also the case for the following definitions:
trait Expr[T] trait IntExpr extends Expr[T] trait Const[T] extends Expr[T]
StaticScrutineeType = Const[T] PatternType = IntExpr
Union and intersection types are an additional complication - if either scrutinee or pattern are a union type, then the above relationships only need to hold for the "leaves" of the types.
Finally, if pattern type contains hk-types applied to concrete types (as opposed to type variables),
or either scrutinee or pattern type contain type member refinements, the above relationships do not need
to hold at all. Consider (where T1
, T2
are unrelated traits):
StaticScrutineeType = { type T <: T1 } PatternType = { type T <: T2 }
In the above situation, DynamicScrutineeType can equal { type T = T1 & T2 }, but there is no useful relationship between StaticScrutineeType and PatternType (nor any of their subcomponents). Similarly:
StaticScrutineeType = Option[T1] PatternType = Some[T2]
Again, DynamicScrutineeType may equal Some[T1 & T2], and there's no useful relationship between the static scrutinee and pattern types. This does not apply if the pattern type is only applied to type variables, in which case the subtyping relationship "heals" the type.
Attributes
- Inherited from:
- PatternTypeConstrainer
Constrain "simple" patterns (see constrainPatternType
).
Constrain "simple" patterns (see constrainPatternType
).
This function expects to receive two types (scrutinee and pattern), both of which have class symbols, one of which is derived from another. If the type "being derived from" is an applied type, it will 1) "upcast" the deriving type to an applied type with the same constructor and 2) infer constraints for the applied types' arguments that follow from both types being inhabited by one value (the scrutinee).
Importantly, note that the pattern type may contain type variables, which are used to infer type arguments to Unapply trees.
Invariant refinement
Essentially, we say that D[B] extends C[B]
s.t. refines parameter A
of trait C[A]
invariantly if
when c: C[T]
and c
is instance of D
, then necessarily c: D[T]
. This is violated if A
is variant:
trait C[+A] trait D[+B](val b: B) extends C[B] trait E extends DAny with C[String]
E
is a counter-example to the above - if e: E
, then e: C[String]
and e
is instance of D
, but
it is false that e: D[String]
! This is a problem if we're constraining a pattern like the below:
def foo[T](c: C[T]): T = c match { case d: D[t] => d.b }
It'd be unsound for us to say that t <: T
, even though that follows from D[t] <: C[T]
.
Note, however, that if D
was a final class, we could rely on that relationship.
To support typical case classes, we also assume that this relationship holds for them and their parent traits.
This is enforced by checking that classes inheriting from case classes do not extend the parent traits of those
case classes without also appropriately extending the relevant case class
(see RefChecks#checkCaseClassInheritanceInvariant
).
Attributes
- Inherited from:
- PatternTypeConstrainer
If tp
is an intersection such that some operands are transparent trait instances
and others are not, replace as many transparent trait instances as possible with Any
as long as the result is still a subtype of bound
. But fall back to the
original type if the resulting widened type is a supertype of all dropped
types (since in this case the type was not a true intersection of transparent traits
and other types to start with).
If tp
is an intersection such that some operands are transparent trait instances
and others are not, replace as many transparent trait instances as possible with Any
as long as the result is still a subtype of bound
. But fall back to the
original type if the resulting widened type is a supertype of all dropped
types (since in this case the type was not a true intersection of transparent traits
and other types to start with).
Attributes
- Inherited from:
- ConstraintHandling
Full bounds of param
, including other lower/upper params.
Full bounds of param
, including other lower/upper params.
Note that underlying operations perform subtype checks - for this reason, recursing on fullBounds
of some param when comparing types might lead to infinite recursion. Consider bounds
instead.
Attributes
- Inherited from:
- ConstraintHandling
The full lower bound of param
includes both the nonParamBounds
and the
params in the constraint known to be <: param
, except that
params with a nestingLevel
higher than param
will be instantiated
to a fresh param at a legal level. See the documentation of TypeVar
for details.
The full lower bound of param
includes both the nonParamBounds
and the
params in the constraint known to be <: param
, except that
params with a nestingLevel
higher than param
will be instantiated
to a fresh param at a legal level. See the documentation of TypeVar
for details.
Attributes
- Inherited from:
- ConstraintHandling
The full upper bound of param
, see the documentation of fullLowerBounds
above.
The full upper bound of param
, see the documentation of fullLowerBounds
above.
Attributes
- Inherited from:
- ConstraintHandling
Attributes
- Inherited from:
- ConstraintHandling
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.
The instance type is not allowed to contain references to types nested deeper
than maxLevel
.
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.
The instance type is not allowed to contain references to types nested deeper
than maxLevel
.
Attributes
- Inherited from:
- ConstraintHandling
Attributes
- Inherited from:
- ConstraintHandling
Test whether the lower bounds of all parameters in this constraint are a solution to the constraint.
Test whether the lower bounds of all parameters in this constraint are a solution to the constraint.
Attributes
- Inherited from:
- ConstraintHandling
Attributes
- Inherited from:
- ConstraintHandling
Attributes
- Inherited from:
- ConstraintHandling
Approximate rawBound
if needed to make it a legal bound of param
by
avoiding wildcards and types with a level strictly greater than its
nestingLevel
.
Approximate rawBound
if needed to make it a legal bound of param
by
avoiding wildcards and types with a level strictly greater than its
nestingLevel
.
Note that level-checking must be performed here and cannot be delayed until instantiation because if we allow level-incorrect bounds, then we might end up reasoning with bad bounds outside of the scope where they are defined. This can lead to level-correct but unsound instantiations as demonstrated by tests/neg/i8900.scala.
Attributes
- Inherited from:
- ConstraintHandling
Is level
<= maxLevel
or legal in the current context?
Attributes
- Inherited from:
- ConstraintHandling
When collecting the constraints needed for a particular subtyping
judgment to be true, we sometimes need to approximate the constraint
set (see TypeComparer#either
for example).
When collecting the constraints needed for a particular subtyping
judgment to be true, we sometimes need to approximate the constraint
set (see TypeComparer#either
for example).
Normally, this means adding extra constraints which may not be necessary for the subtyping judgment to be true, but if this variable is set to true we will instead under-approximate and keep only the constraints that must always be present for the subtyping judgment to hold.
This is needed for GADT bounds inference to be sound, but it is also used when constraining a method call based on its expected type to avoid adding constraints that would later prevent us from typechecking method arguments, see or-inf.scala and and-inf.scala for examples.
Attributes
- Inherited from:
- ConstraintHandling
Attributes
- Inherited from:
- ConstraintHandling
Attributes
- Inherited from:
- ConstraintHandling
Constraint c1
subsumes constraint c2
, if under c2
as constraint we have
for all poly params p
defined in c2
as p >: L2 <: U2
:
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
, without adding
any new type variables but possibly narrowing already registered ones with further bounds.
Attributes
- Inherited from:
- ConstraintHandling
Attributes
- Inherited from:
- ConstraintHandling
Widen inferred type inst
with upper bound
, according to the following rules:
Widen inferred type inst
with upper bound
, according to the following rules:
- If
inst
is a singleton type, or a union containing some singleton types, widen (all) the singleton type(s), provided the result is a subtype ofbound
. (i.e.inst.widenSingletons <:< bound
succeeds with satisfiable constraint) 2a. Ifinst
is a union type andwidenUnions
is true, approximate the union type from above by an intersection of all common base types, provided the result is a subtype ofbound
. 2b. Ifinst
is a union type andwidenUnions
is false, turn it into a hard union type (except for unions | Null, which are kept in the state they were). - Widen some irreducible applications of higher-kinded types to wildcard arguments (see @widenIrreducible).
- Drop transparent traits from intersections (see @dropTransparentTraits).
Don't do these widenings if bound
is a subtype of scala.Singleton
.
Also, if the result of these widenings is a TypeRef to a module class,
and this type ref is different from inst
, replace by a TermRef to
its source module instead.
At this point we also drop the @Repeated annotation to avoid inferring type arguments with it, as those could leak the annotation to users (see run/inferred-repeated-result).
Attributes
- Inherited from:
- ConstraintHandling
If tp
is an applied match type alias which is also an unreducible application
of a higher-kinded type to a wildcard argument, widen to the match type's bound,
in order to avoid an unreducible application of higher-kinded type ... in inferred type"
error in PostTyper. Fixes #11246.
If tp
is an applied match type alias which is also an unreducible application
of a higher-kinded type to a wildcard argument, widen to the match type's bound,
in order to avoid an unreducible application of higher-kinded type ... in inferred type"
error in PostTyper. Fixes #11246.
Attributes
- Inherited from:
- ConstraintHandling
Attributes
- Inherited from:
- ConstraintHandling
Concrete fields
The sameLevel
nesting depth from which on we want to keep track
of isSameTypes suucesses using sames
The sameLevel
nesting depth from which on we want to keep track
of isSameTypes suucesses using sames
Attributes
Inherited fields
Potentially a type lambda that is still instantiatable, even though the constraint is generally frozen.
Potentially a type lambda that is still instantiatable, even though the constraint is generally frozen.
Attributes
- Inherited from:
- ConstraintHandling
We are currently comparing type lambdas. Used as a flag for
optimization: when false
, no need to do an expensive pruneLambdaParams
We are currently comparing type lambdas. Used as a flag for
optimization: when false
, no need to do an expensive pruneLambdaParams
Attributes
- Inherited from:
- ConstraintHandling
If the constraint is frozen we cannot add new bounds to the constraint.
If the constraint is frozen we cannot add new bounds to the constraint.
Attributes
- Inherited from:
- ConstraintHandling
If set, align arguments S1
, S2
when 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.
If set, align arguments S1
, S2
when 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.
Attributes
- Inherited from:
- ConstraintHandling
Attributes
- Inherited from:
- ConstraintHandling