]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_hir_analysis/src/autoderef.rs
bump version to 1.81.0+dfsg1-2~bpo12+pve1
[rustc.git] / compiler / rustc_hir_analysis / src / autoderef.rs
CommitLineData
f2b60f7d 1use crate::errors::AutoDerefReachedRecursionLimit;
31ef2f64 2use crate::traits;
f035d41b 3use crate::traits::query::evaluate_obligation::InferCtxtExt;
f035d41b 4use rustc_infer::infer::InferCtxt;
9ffffee4 5use rustc_middle::ty::TypeVisitableExt;
487cf647 6use rustc_middle::ty::{self, Ty, TyCtxt};
5e7ed085 7use rustc_session::Limit;
9ffffee4 8use rustc_span::def_id::LocalDefId;
17df50a5 9use rustc_span::def_id::LOCAL_CRATE;
f035d41b 10use rustc_span::Span;
31ef2f64 11use rustc_trait_selection::traits::ObligationCtxt;
f035d41b
XL
12
13#[derive(Copy, Clone, Debug)]
14pub enum AutoderefKind {
c0240ec0 15 /// A true pointer type, such as `&T` and `*mut T`.
f035d41b 16 Builtin,
c0240ec0 17 /// A type which must dispatch to a `Deref` implementation.
f035d41b
XL
18 Overloaded,
19}
20
21struct AutoderefSnapshot<'tcx> {
22 at_start: bool,
23 reached_recursion_limit: bool,
24 steps: Vec<(Ty<'tcx>, AutoderefKind)>,
25 cur_ty: Ty<'tcx>,
26 obligations: Vec<traits::PredicateObligation<'tcx>>,
27}
28
29pub struct Autoderef<'a, 'tcx> {
30 // Meta infos:
2b03887a 31 infcx: &'a InferCtxt<'tcx>,
f035d41b 32 span: Span,
9ffffee4 33 body_id: LocalDefId,
f035d41b
XL
34 param_env: ty::ParamEnv<'tcx>,
35
36 // Current state:
37 state: AutoderefSnapshot<'tcx>,
38
39 // Configurations:
40 include_raw_pointers: bool,
41 silence_errors: bool,
42}
43
44impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
45 type Item = (Ty<'tcx>, usize);
46
47 fn next(&mut self) -> Option<Self::Item> {
48 let tcx = self.infcx.tcx;
49
50 debug!("autoderef: steps={:?}, cur_ty={:?}", self.state.steps, self.state.cur_ty);
51 if self.state.at_start {
52 self.state.at_start = false;
53 debug!("autoderef stage #0 is {:?}", self.state.cur_ty);
54 return Some((self.state.cur_ty, 0));
55 }
56
57 // If we have reached the recursion limit, error gracefully.
136023e0 58 if !tcx.recursion_limit().value_within_limit(self.state.steps.len()) {
f035d41b
XL
59 if !self.silence_errors {
60 report_autoderef_recursion_limit_error(tcx, self.span, self.state.cur_ty);
61 }
62 self.state.reached_recursion_limit = true;
63 return None;
64 }
65
66 if self.state.cur_ty.is_ty_var() {
67 return None;
68 }
69
70 // Otherwise, deref if type is derefable:
31ef2f64
FG
71 let (kind, new_ty) =
72 if let Some(ty) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) {
73 debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty));
74 // NOTE: we may still need to normalize the built-in deref in case
75 // we have some type like `&<Ty as Trait>::Assoc`, since users of
76 // autoderef expect this type to have been structurally normalized.
77 if self.infcx.next_trait_solver()
78 && let ty::Alias(..) = ty.kind()
79 {
80 let (normalized_ty, obligations) = self.structurally_normalize(ty)?;
81 self.state.obligations.extend(obligations);
82 (AutoderefKind::Builtin, normalized_ty)
83 } else {
84 (AutoderefKind::Builtin, ty)
85 }
86 } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) {
87 // The overloaded deref check already normalizes the pointee type.
88 (AutoderefKind::Overloaded, ty)
f035d41b 89 } else {
31ef2f64
FG
90 return None;
91 };
f035d41b 92
f035d41b
XL
93 self.state.steps.push((self.state.cur_ty, kind));
94 debug!(
95 "autoderef stage #{:?} is {:?} from {:?}",
96 self.step_count(),
97 new_ty,
98 (self.state.cur_ty, kind)
99 );
100 self.state.cur_ty = new_ty;
101
102 Some((self.state.cur_ty, self.step_count()))
103 }
104}
105
106impl<'a, 'tcx> Autoderef<'a, 'tcx> {
107 pub fn new(
2b03887a 108 infcx: &'a InferCtxt<'tcx>,
f035d41b 109 param_env: ty::ParamEnv<'tcx>,
9ffffee4 110 body_def_id: LocalDefId,
f035d41b
XL
111 span: Span,
112 base_ty: Ty<'tcx>,
113 ) -> Autoderef<'a, 'tcx> {
114 Autoderef {
115 infcx,
116 span,
9ffffee4 117 body_id: body_def_id,
f035d41b
XL
118 param_env,
119 state: AutoderefSnapshot {
120 steps: vec![],
fc512014 121 cur_ty: infcx.resolve_vars_if_possible(base_ty),
f035d41b
XL
122 obligations: vec![],
123 at_start: true,
124 reached_recursion_limit: false,
125 },
126 include_raw_pointers: false,
127 silence_errors: false,
128 }
129 }
130
131 fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
132 debug!("overloaded_deref_ty({:?})", ty);
f035d41b
XL
133 let tcx = self.infcx.tcx;
134
c620b35d
FG
135 if ty.references_error() {
136 return None;
137 }
138
f035d41b 139 // <ty as Deref>
49aad941 140 let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]);
f035d41b 141 let cause = traits::ObligationCause::misc(self.span, self.body_id);
f035d41b 142 let obligation = traits::Obligation::new(
487cf647 143 tcx,
f035d41b
XL
144 cause.clone(),
145 self.param_env,
487cf647 146 ty::Binder::dummy(trait_ref),
f035d41b
XL
147 );
148 if !self.infcx.predicate_may_hold(&obligation) {
149 debug!("overloaded_deref_ty: cannot match obligation");
150 return None;
151 }
152
fe692bf9
FG
153 let (normalized_ty, obligations) = self.structurally_normalize(Ty::new_projection(
154 tcx,
155 tcx.lang_items().deref_target()?,
156 [ty],
157 ))?;
49aad941
FG
158 debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
159 self.state.obligations.extend(obligations);
160
161 Some(self.infcx.resolve_vars_if_possible(normalized_ty))
162 }
163
164 #[instrument(level = "debug", skip(self), ret)]
165 pub fn structurally_normalize(
166 &self,
167 ty: Ty<'tcx>,
168 ) -> Option<(Ty<'tcx>, Vec<traits::PredicateObligation<'tcx>>)> {
31ef2f64
FG
169 let ocx = ObligationCtxt::new(self.infcx);
170 let Ok(normalized_ty) = ocx.structurally_normalize(
171 &traits::ObligationCause::misc(self.span, self.body_id),
172 self.param_env,
173 ty,
174 ) else {
175 // We shouldn't have errors here, except for evaluate/fulfill mismatches,
176 // but that's not a reason for an ICE (`predicate_may_hold` is conservative
177 // by design).
178 // FIXME(-Znext-solver): This *actually* shouldn't happen then.
179 return None;
49aad941 180 };
31ef2f64 181 let errors = ocx.select_where_possible();
3c0e092e 182 if !errors.is_empty() {
f035d41b
XL
183 // This shouldn't happen, except for evaluate/fulfill mismatches,
184 // but that's not a reason for an ICE (`predicate_may_hold` is conservative
185 // by design).
49aad941 186 debug!(?errors, "encountered errors while fulfilling");
f035d41b
XL
187 return None;
188 }
f035d41b 189
31ef2f64 190 Some((normalized_ty, ocx.into_pending_obligations()))
f035d41b
XL
191 }
192
193 /// Returns the final type we ended up with, which may be an inference
194 /// variable (we will resolve it first, if we want).
195 pub fn final_ty(&self, resolve: bool) -> Ty<'tcx> {
196 if resolve {
fc512014 197 self.infcx.resolve_vars_if_possible(self.state.cur_ty)
f035d41b
XL
198 } else {
199 self.state.cur_ty
200 }
201 }
202
203 pub fn step_count(&self) -> usize {
204 self.state.steps.len()
205 }
206
207 pub fn into_obligations(self) -> Vec<traits::PredicateObligation<'tcx>> {
208 self.state.obligations
209 }
210
9c376795
FG
211 pub fn current_obligations(&self) -> Vec<traits::PredicateObligation<'tcx>> {
212 self.state.obligations.clone()
213 }
214
f035d41b
XL
215 pub fn steps(&self) -> &[(Ty<'tcx>, AutoderefKind)] {
216 &self.state.steps
217 }
218
219 pub fn span(&self) -> Span {
3dfed10e 220 self.span
1b1a35ee
XL
221 }
222
f035d41b
XL
223 pub fn reached_recursion_limit(&self) -> bool {
224 self.state.reached_recursion_limit
225 }
226
227 /// also dereference through raw pointer types
228 /// e.g., assuming ptr_to_Foo is the type `*const Foo`
229 /// fcx.autoderef(span, ptr_to_Foo) => [*const Foo]
230 /// fcx.autoderef(span, ptr_to_Foo).include_raw_ptrs() => [*const Foo, Foo]
231 pub fn include_raw_pointers(mut self) -> Self {
232 self.include_raw_pointers = true;
233 self
234 }
235
236 pub fn silence_errors(mut self) -> Self {
237 self.silence_errors = true;
238 self
239 }
240}
241
242pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
243 // We've reached the recursion limit, error gracefully.
c295e0f8
XL
244 let suggested_limit = match tcx.recursion_limit() {
245 Limit(0) => Limit(2),
246 limit => limit * 2,
247 };
c0240ec0 248 tcx.dcx().emit_err(AutoDerefReachedRecursionLimit {
5e7ed085 249 span,
f2b60f7d 250 ty,
5e7ed085 251 suggested_limit,
f2b60f7d
FG
252 crate_name: tcx.crate_name(LOCAL_CRATE),
253 });
f035d41b 254}