Skip to main content

hir_ty/next_solver/infer/
unify_key.rs

1//! Unification keyes for the infer context the next-trait-solver.
2
3use std::cmp;
4use std::marker::PhantomData;
5
6use ena::unify::{NoError, UnifyKey, UnifyValue};
7use rustc_type_ir::{ConstVid, RegionKind, RegionVid, UniverseIndex, inherent::IntoKind};
8
9use crate::{
10    Span,
11    next_solver::{Const, Region},
12};
13
14#[derive(Clone, Copy, Debug)]
15pub(crate) enum RegionVariableValue<'db> {
16    Known { value: Region<'db>, span: Option<Span> },
17    Unknown { universe: UniverseIndex, span: Span },
18}
19
20#[derive(PartialEq, Copy, Clone, Debug)]
21pub(crate) struct RegionVidKey<'db> {
22    pub(crate) vid: RegionVid,
23    pub(crate) phantom: PhantomData<RegionVariableValue<'db>>,
24}
25
26impl<'db> From<RegionVid> for RegionVidKey<'db> {
27    fn from(vid: RegionVid) -> Self {
28        RegionVidKey { vid, phantom: PhantomData }
29    }
30}
31
32impl<'db> UnifyKey for RegionVidKey<'db> {
33    type Value = RegionVariableValue<'db>;
34    #[inline]
35    fn index(&self) -> u32 {
36        self.vid.as_u32()
37    }
38    #[inline]
39    fn from_index(i: u32) -> Self {
40        RegionVidKey::from(RegionVid::from_u32(i))
41    }
42    fn tag() -> &'static str {
43        "RegionVidKey"
44    }
45}
46
47pub(crate) struct RegionUnificationError;
48impl<'db> UnifyValue for RegionVariableValue<'db> {
49    type Error = RegionUnificationError;
50
51    fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
52        match (value1, value2) {
53            (RegionVariableValue::Known { .. }, RegionVariableValue::Known { .. }) => {
54                Err(RegionUnificationError)
55            }
56
57            (
58                &RegionVariableValue::Known { value, span: span_known },
59                &RegionVariableValue::Unknown { universe, span: span_unknown },
60            )
61            | (
62                &RegionVariableValue::Unknown { universe, span: span_unknown },
63                &RegionVariableValue::Known { value, span: span_known },
64            ) => {
65                let universe_of_value = match value.kind() {
66                    RegionKind::ReStatic
67                    | RegionKind::ReErased
68                    | RegionKind::ReLateParam(..)
69                    | RegionKind::ReEarlyParam(..)
70                    | RegionKind::ReError(_) => UniverseIndex::ROOT,
71                    RegionKind::RePlaceholder(placeholder) => placeholder.universe,
72                    RegionKind::ReVar(..) | RegionKind::ReBound(..) => {
73                        panic!("not a universal region")
74                    }
75                };
76
77                let span = match span_known {
78                    Some(span_known) => Span::pick_best(span_known, span_unknown),
79                    None => span_unknown,
80                };
81                if universe.can_name(universe_of_value) {
82                    Ok(RegionVariableValue::Known { value, span: Some(span) })
83                } else {
84                    Err(RegionUnificationError)
85                }
86            }
87
88            (
89                &RegionVariableValue::Unknown { universe: a, span: span1 },
90                &RegionVariableValue::Unknown { universe: b, span: span2 },
91            ) => {
92                // If we unify two unconstrained regions then whatever
93                // value they wind up taking (which must be the same value) must
94                // be nameable by both universes. Therefore, the resulting
95                // universe is the minimum of the two universes, because that is
96                // the one which contains the fewest names in scope.
97                let span = Span::pick_best(span1, span2);
98                Ok(RegionVariableValue::Unknown { universe: a.min(b), span })
99            }
100        }
101    }
102}
103
104// Generic consts.
105
106#[derive(Clone, Copy, Debug)]
107pub(crate) enum ConstVariableValue<'db> {
108    Known { value: Const<'db> },
109    Unknown { span: Span, universe: UniverseIndex },
110}
111
112impl<'db> ConstVariableValue<'db> {
113    /// If this value is known, returns the const it is known to be.
114    /// Otherwise, `None`.
115    pub(crate) fn known(&self) -> Option<Const<'db>> {
116        match self {
117            ConstVariableValue::Unknown { .. } => None,
118            ConstVariableValue::Known { value } => Some(*value),
119        }
120    }
121}
122
123#[derive(PartialEq, Copy, Clone, Debug)]
124pub(crate) struct ConstVidKey<'db> {
125    pub(crate) vid: ConstVid,
126    pub(crate) phantom: PhantomData<Const<'db>>,
127}
128
129impl<'db> From<ConstVid> for ConstVidKey<'db> {
130    fn from(vid: ConstVid) -> Self {
131        ConstVidKey { vid, phantom: PhantomData }
132    }
133}
134
135impl<'db> UnifyKey for ConstVidKey<'db> {
136    type Value = ConstVariableValue<'db>;
137    #[inline]
138    fn index(&self) -> u32 {
139        self.vid.as_u32()
140    }
141    #[inline]
142    fn from_index(i: u32) -> Self {
143        ConstVidKey::from(ConstVid::from_u32(i))
144    }
145    fn tag() -> &'static str {
146        "ConstVidKey"
147    }
148}
149
150impl<'db> UnifyValue for ConstVariableValue<'db> {
151    type Error = NoError;
152
153    fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
154        match (value1, value2) {
155            (ConstVariableValue::Known { .. }, ConstVariableValue::Known { .. }) => {
156                panic!("equating two const variables, both of which have known values")
157            }
158
159            // If one side is known, prefer that one.
160            (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => Ok(*value1),
161            (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => Ok(*value2),
162
163            // If both sides are *unknown*, it hardly matters, does it?
164            (
165                &ConstVariableValue::Unknown { span: span1, universe: universe1 },
166                &ConstVariableValue::Unknown { span: span2, universe: universe2 },
167            ) => {
168                // If we unify two unbound variables, ?T and ?U, then whatever
169                // value they wind up taking (which must be the same value) must
170                // be nameable by both universes. Therefore, the resulting
171                // universe is the minimum of the two universes, because that is
172                // the one which contains the fewest names in scope.
173                let universe = cmp::min(universe1, universe2);
174                let span = Span::pick_best(span1, span2);
175                Ok(ConstVariableValue::Unknown { span, universe })
176            }
177        }
178    }
179}