1 //! # Lattice Variables
3 //! This file contains generic code for operating on inference variables
4 //! that are characterized by an upper- and lower-bound. The logic and
5 //! reasoning is explained in detail in the large comment in `infer.rs`.
7 //! The code in here is defined quite generically so that it can be
8 //! applied both to type variables, which represent types being inferred,
9 //! and fn variables, which represent function types being inferred.
10 //! It may eventually be applied to their types as well, who knows.
11 //! In some cases, the functions are also generic with respect to the
12 //! operation on the lattice (GLB vs LUB).
14 //! Although all the functions are generic, we generally write the
15 //! comments in a way that is specific to type variables and the LUB
16 //! operation. It's just easier that way.
18 //! In general all of the functions are defined parametrically
19 //! over a `LatticeValue`, which is a value defined with respect to
22 use super::type_variable
::{TypeVariableOrigin, TypeVariableOriginKind}
;
25 use crate::traits
::ObligationCause
;
26 use rustc_middle
::ty
::relate
::{RelateResult, TypeRelation}
;
27 use rustc_middle
::ty
::TyVar
;
28 use rustc_middle
::ty
::{self, Ty}
;
30 pub trait LatticeDir
<'f
, 'tcx
>: TypeRelation
<'tcx
> {
31 fn infcx(&self) -> &'f InferCtxt
<'f
, 'tcx
>;
33 fn cause(&self) -> &ObligationCause
<'tcx
>;
35 // Relates the type `v` to `a` and `b` such that `v` represents
36 // the LUB/GLB of `a` and `b` as appropriate.
38 // Subtle hack: ordering *may* be significant here. This method
39 // relates `v` to `a` first, which may help us to avoid unnecessary
40 // type variable obligations. See caller for details.
41 fn relate_bound(&mut self, v
: Ty
<'tcx
>, a
: Ty
<'tcx
>, b
: Ty
<'tcx
>) -> RelateResult
<'tcx
, ()>;
44 pub fn super_lattice_tys
<'a
, 'tcx
: 'a
, L
>(
48 ) -> RelateResult
<'tcx
, Ty
<'tcx
>>
50 L
: LatticeDir
<'a
, 'tcx
>,
52 debug
!("{}.lattice_tys({:?}, {:?})", this
.tag(), a
, b
);
58 let infcx
= this
.infcx();
59 let a
= infcx
.inner
.borrow_mut().type_variables().replace_if_possible(a
);
60 let b
= infcx
.inner
.borrow_mut().type_variables().replace_if_possible(b
);
61 match (a
.kind(), b
.kind()) {
62 // If one side is known to be a variable and one is not,
63 // create a variable (`v`) to represent the LUB. Make sure to
64 // relate `v` to the non-type-variable first (by passing it
65 // first to `relate_bound`). Otherwise, we would produce a
66 // subtype obligation that must then be processed.
68 // Example: if the LHS is a type variable, and RHS is
69 // `Box<i32>`, then we current compare `v` to the RHS first,
70 // which will instantiate `v` with `Box<i32>`. Then when `v`
71 // is compared to the LHS, we instantiate LHS with `Box<i32>`.
72 // But if we did in reverse order, we would create a `v <:
73 // LHS` (or vice versa) constraint and then instantiate
74 // `v`. This would require further processing to achieve same
75 // end-result; in partiular, this screws up some of the logic
76 // in coercion, which expects LUB to figure out that the LHS
77 // is (e.g.) `Box<i32>`. A more obvious solution might be to
78 // iterate on the subtype obligations that are returned, but I
79 // think this suffices. -nmatsakis
80 (&ty
::Infer(TyVar(..)), _
) => {
81 let v
= infcx
.next_ty_var(TypeVariableOrigin
{
82 kind
: TypeVariableOriginKind
::LatticeVariable
,
83 span
: this
.cause().span
,
85 this
.relate_bound(v
, b
, a
)?
;
88 (_
, &ty
::Infer(TyVar(..))) => {
89 let v
= infcx
.next_ty_var(TypeVariableOrigin
{
90 kind
: TypeVariableOriginKind
::LatticeVariable
,
91 span
: this
.cause().span
,
93 this
.relate_bound(v
, a
, b
)?
;
97 _
=> infcx
.super_combine_tys(this
, a
, b
),