1use rustc_infer::infer::relate::{
2self, 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;
78/// 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}
2728impl<'tcx> MatchAgainstFreshVars<'tcx> {
29pub(crate) fn new(tcx: TyCtxt<'tcx>) -> MatchAgainstFreshVars<'tcx> {
30MatchAgainstFreshVars { tcx }
31 }
32}
3334impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstFreshVars<'tcx> {
35fn cx(&self) -> TyCtxt<'tcx> {
36self.tcx
37 }
3839fn 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> {
46self.relate(a, b)
47 }
4849#[instrument(skip(self), level = "trace")]
50fn regions(
51&mut self,
52 a: ty::Region<'tcx>,
53 _b: ty::Region<'tcx>,
54 ) -> RelateResult<'tcx, ty::Region<'tcx>> {
55Ok(a)
56 }
5758#[instrument(skip(self), level = "trace")]
59fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
60if a == b {
61return Ok(a);
62 }
6364match (a.kind(), b.kind()) {
65 (
66_,
67&ty::Infer(ty::FreshTy(_))
68 | &ty::Infer(ty::FreshIntTy(_))
69 | &ty::Infer(ty::FreshFloatTy(_)),
70 ) => Ok(a),
7172 (&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
73Err(TypeError::Sorts(ExpectedFound::new(a, b)))
74 }
7576 (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(self.cx(), guar)),
7778_ => structurally_relate_tys(self, a, b),
79 }
80 }
8182#[instrument(skip(self), level = "trace")]
83fn consts(
84&mut self,
85 a: ty::Const<'tcx>,
86 b: ty::Const<'tcx>,
87 ) -> RelateResult<'tcx, ty::Const<'tcx>> {
88if a == b {
89return Ok(a);
90 }
9192match (a.kind(), b.kind()) {
93 (_, ty::ConstKind::Infer(InferConst::Fresh(_))) => {
94return Ok(a);
95 }
9697 (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => {
98return Err(TypeError::ConstMismatch(ExpectedFound::new(a, b)));
99 }
100101_ => {}
102 }
103104 relate::structurally_relate_consts(self, a, b)
105 }
106107fn binders<T>(
108&mut self,
109 a: ty::Binder<'tcx, T>,
110 b: ty::Binder<'tcx, T>,
111 ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
112where
113T: Relate<TyCtxt<'tcx>>,
114 {
115Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
116 }
117}