rustc_trait_selection/traits/select/
_match.rs

1use rustc_infer::infer::relate::{
2    self, Relate, RelateResult, TypeRelation, structurally_relate_tys,
3};
4use rustc_middle::ty::error::{ExpectedFound, TypeError};
5use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
6use tracing::instrument;
7
8/// A type "A" *matches* "B" if the fresh types in B could be
9/// instantiated with values so as to make it equal to A. Matching is
10/// intended to be used only on freshened types, and it basically
11/// indicates if the non-freshened versions of A and B could have been
12/// unified.
13///
14/// It is only an approximation. If it yields false, unification would
15/// definitely fail, but a true result doesn't mean unification would
16/// succeed. This is because we don't track the "side-constraints" on
17/// type variables, nor do we track if the same freshened type appears
18/// more than once. To some extent these approximations could be
19/// fixed, given effort.
20///
21/// Like subtyping, matching is really a binary relation, so the only
22/// important thing about the result is Ok/Err. Also, matching never
23/// affects any type variables or unification state.
24pub(crate) struct MatchAgainstFreshVars<'tcx> {
25    tcx: TyCtxt<'tcx>,
26}
27
28impl<'tcx> MatchAgainstFreshVars<'tcx> {
29    pub(crate) fn new(tcx: TyCtxt<'tcx>) -> MatchAgainstFreshVars<'tcx> {
30        MatchAgainstFreshVars { tcx }
31    }
32}
33
34impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstFreshVars<'tcx> {
35    fn cx(&self) -> TyCtxt<'tcx> {
36        self.tcx
37    }
38
39    fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
40        &mut self,
41        _: ty::Variance,
42        _: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
43        a: T,
44        b: T,
45    ) -> RelateResult<'tcx, T> {
46        self.relate(a, b)
47    }
48
49    #[instrument(skip(self), level = "trace")]
50    fn regions(
51        &mut self,
52        a: ty::Region<'tcx>,
53        _b: ty::Region<'tcx>,
54    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
55        Ok(a)
56    }
57
58    #[instrument(skip(self), level = "trace")]
59    fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
60        if a == b {
61            return Ok(a);
62        }
63
64        match (a.kind(), b.kind()) {
65            (
66                _,
67                &ty::Infer(ty::FreshTy(_))
68                | &ty::Infer(ty::FreshIntTy(_))
69                | &ty::Infer(ty::FreshFloatTy(_)),
70            ) => Ok(a),
71
72            (&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
73                Err(TypeError::Sorts(ExpectedFound::new(a, b)))
74            }
75
76            (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(self.cx(), guar)),
77
78            _ => structurally_relate_tys(self, a, b),
79        }
80    }
81
82    #[instrument(skip(self), level = "trace")]
83    fn consts(
84        &mut self,
85        a: ty::Const<'tcx>,
86        b: ty::Const<'tcx>,
87    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
88        if a == b {
89            return Ok(a);
90        }
91
92        match (a.kind(), b.kind()) {
93            (_, ty::ConstKind::Infer(InferConst::Fresh(_))) => {
94                return Ok(a);
95            }
96
97            (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => {
98                return Err(TypeError::ConstMismatch(ExpectedFound::new(a, b)));
99            }
100
101            _ => {}
102        }
103
104        relate::structurally_relate_consts(self, a, b)
105    }
106
107    fn binders<T>(
108        &mut self,
109        a: ty::Binder<'tcx, T>,
110        b: ty::Binder<'tcx, T>,
111    ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
112    where
113        T: Relate<TyCtxt<'tcx>>,
114    {
115        Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
116    }
117}