]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_trait_selection/src/infer.rs
Rollup merge of #104775 - spastorino:use-obligation-ctxt-normalize, r=lcnr
[rust.git] / compiler / rustc_trait_selection / src / infer.rs
1 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
2 use crate::traits::{self, ObligationCtxt};
3
4 use rustc_hir::def_id::DefId;
5 use rustc_hir::lang_items::LangItem;
6 use rustc_infer::traits::ObligationCause;
7 use rustc_middle::arena::ArenaAllocatable;
8 use rustc_middle::infer::canonical::{Canonical, CanonicalizedQueryResponse, QueryResponse};
9 use rustc_middle::traits::query::Fallible;
10 use rustc_middle::ty::{self, Ty, TypeFoldable, TypeVisitable};
11 use rustc_middle::ty::{GenericArg, ToPredicate};
12 use rustc_span::{Span, DUMMY_SP};
13
14 use std::fmt::Debug;
15
16 pub use rustc_infer::infer::*;
17
18 pub trait InferCtxtExt<'tcx> {
19     fn type_is_copy_modulo_regions(
20         &self,
21         param_env: ty::ParamEnv<'tcx>,
22         ty: Ty<'tcx>,
23         span: Span,
24     ) -> bool;
25
26     fn type_is_sized_modulo_regions(
27         &self,
28         param_env: ty::ParamEnv<'tcx>,
29         ty: Ty<'tcx>,
30         span: Span,
31     ) -> bool;
32
33     fn partially_normalize_associated_types_in<T>(
34         &self,
35         cause: ObligationCause<'tcx>,
36         param_env: ty::ParamEnv<'tcx>,
37         value: T,
38     ) -> InferOk<'tcx, T>
39     where
40         T: TypeFoldable<'tcx>;
41
42     /// Check whether a `ty` implements given trait(trait_def_id).
43     /// The inputs are:
44     ///
45     /// - the def-id of the trait
46     /// - the type parameters of the trait, including the self-type
47     /// - the parameter environment
48     ///
49     /// Invokes `evaluate_obligation`, so in the event that evaluating
50     /// `Ty: Trait` causes overflow, EvaluatedToRecur (or EvaluatedToUnknown)
51     /// will be returned.
52     fn type_implements_trait(
53         &self,
54         trait_def_id: DefId,
55         params: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
56         param_env: ty::ParamEnv<'tcx>,
57     ) -> traits::EvaluationResult;
58 }
59 impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
60     fn type_is_copy_modulo_regions(
61         &self,
62         param_env: ty::ParamEnv<'tcx>,
63         ty: Ty<'tcx>,
64         span: Span,
65     ) -> bool {
66         let ty = self.resolve_vars_if_possible(ty);
67
68         if !(param_env, ty).needs_infer() {
69             return ty.is_copy_modulo_regions(self.tcx, param_env);
70         }
71
72         let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, None);
73
74         // This can get called from typeck (by euv), and `moves_by_default`
75         // rightly refuses to work with inference variables, but
76         // moves_by_default has a cache, which we want to use in other
77         // cases.
78         traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span)
79     }
80
81     fn type_is_sized_modulo_regions(
82         &self,
83         param_env: ty::ParamEnv<'tcx>,
84         ty: Ty<'tcx>,
85         span: Span,
86     ) -> bool {
87         let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
88         traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item, span)
89     }
90
91     /// Normalizes associated types in `value`, potentially returning
92     /// new obligations that must further be processed.
93     #[instrument(level = "debug", skip(self, cause, param_env), ret)]
94     fn partially_normalize_associated_types_in<T>(
95         &self,
96         cause: ObligationCause<'tcx>,
97         param_env: ty::ParamEnv<'tcx>,
98         value: T,
99     ) -> InferOk<'tcx, T>
100     where
101         T: TypeFoldable<'tcx>,
102     {
103         let mut selcx = traits::SelectionContext::new(self);
104         let traits::Normalized { value, obligations } =
105             traits::normalize(&mut selcx, param_env, cause, value);
106         InferOk { value, obligations }
107     }
108
109     #[instrument(level = "debug", skip(self, params), ret)]
110     fn type_implements_trait(
111         &self,
112         trait_def_id: DefId,
113         params: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
114         param_env: ty::ParamEnv<'tcx>,
115     ) -> traits::EvaluationResult {
116         let trait_ref = self.tcx.mk_trait_ref(trait_def_id, params);
117
118         let obligation = traits::Obligation {
119             cause: traits::ObligationCause::dummy(),
120             param_env,
121             recursion_depth: 0,
122             predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx),
123         };
124         self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr)
125     }
126 }
127
128 pub trait InferCtxtBuilderExt<'tcx> {
129     fn enter_canonical_trait_query<K, R>(
130         &mut self,
131         canonical_key: &Canonical<'tcx, K>,
132         operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Fallible<R>,
133     ) -> Fallible<CanonicalizedQueryResponse<'tcx, R>>
134     where
135         K: TypeFoldable<'tcx>,
136         R: Debug + TypeFoldable<'tcx>,
137         Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>;
138 }
139
140 impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> {
141     /// The "main method" for a canonicalized trait query. Given the
142     /// canonical key `canonical_key`, this method will create a new
143     /// inference context, instantiate the key, and run your operation
144     /// `op`. The operation should yield up a result (of type `R`) as
145     /// well as a set of trait obligations that must be fully
146     /// satisfied. These obligations will be processed and the
147     /// canonical result created.
148     ///
149     /// Returns `NoSolution` in the event of any error.
150     ///
151     /// (It might be mildly nicer to implement this on `TyCtxt`, and
152     /// not `InferCtxtBuilder`, but that is a bit tricky right now.
153     /// In part because we would need a `for<'tcx>` sort of
154     /// bound for the closure and in part because it is convenient to
155     /// have `'tcx` be free on this function so that we can talk about
156     /// `K: TypeFoldable<'tcx>`.)
157     fn enter_canonical_trait_query<K, R>(
158         &mut self,
159         canonical_key: &Canonical<'tcx, K>,
160         operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Fallible<R>,
161     ) -> Fallible<CanonicalizedQueryResponse<'tcx, R>>
162     where
163         K: TypeFoldable<'tcx>,
164         R: Debug + TypeFoldable<'tcx>,
165         Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>,
166     {
167         let (infcx, key, canonical_inference_vars) =
168             self.build_with_canonical(DUMMY_SP, canonical_key);
169         let ocx = ObligationCtxt::new(&infcx);
170         let value = operation(&ocx, key)?;
171         ocx.make_canonicalized_query_response(canonical_inference_vars, value)
172     }
173 }