rustc_trait_selection/traits/select/
_match.rs

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