]>
Commit | Line | Data |
---|---|---|
9fa01778 | 1 | use crate::infer::InferCtxt; |
ba9703b0 XL |
2 | use crate::opaque_types::required_region_bounds; |
3 | use crate::traits; | |
dfeec247 XL |
4 | use rustc_hir as hir; |
5 | use rustc_hir::def_id::DefId; | |
3dfed10e | 6 | use rustc_hir::lang_items::LangItem; |
f035d41b | 7 | use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; |
ba9703b0 | 8 | use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; |
dfeec247 | 9 | use rustc_span::Span; |
ba9703b0 | 10 | use std::rc::Rc; |
e9174d1e | 11 | |
f035d41b XL |
12 | /// Returns the set of obligations needed to make `arg` well-formed. |
13 | /// If `arg` contains unresolved inference variables, this may include | |
14 | /// further WF obligations. However, if `arg` IS an unresolved | |
e9174d1e SL |
15 | /// inference variable, returns `None`, because we are not able to |
16 | /// make any progress at all. This is to prevent "livelock" where we | |
17 | /// say "$0 is WF if $0 is WF". | |
dc9dc135 XL |
18 | pub fn obligations<'a, 'tcx>( |
19 | infcx: &InferCtxt<'a, 'tcx>, | |
20 | param_env: ty::ParamEnv<'tcx>, | |
21 | body_id: hir::HirId, | |
f035d41b | 22 | arg: GenericArg<'tcx>, |
dc9dc135 XL |
23 | span: Span, |
24 | ) -> Option<Vec<traits::PredicateObligation<'tcx>>> { | |
f9f354fc | 25 | // Handle the "livelock" case (see comment above) by bailing out if necessary. |
f035d41b XL |
26 | let arg = match arg.unpack() { |
27 | GenericArgKind::Type(ty) => { | |
28 | match ty.kind { | |
29 | ty::Infer(ty::TyVar(_)) => { | |
30 | let resolved_ty = infcx.shallow_resolve(ty); | |
31 | if resolved_ty == ty { | |
32 | // No progress, bail out to prevent "livelock". | |
33 | return None; | |
34 | } | |
35 | ||
36 | resolved_ty | |
37 | } | |
38 | _ => ty, | |
f9f354fc | 39 | } |
f035d41b XL |
40 | .into() |
41 | } | |
42 | GenericArgKind::Const(ct) => { | |
43 | match ct.val { | |
44 | ty::ConstKind::Infer(infer) => { | |
45 | let resolved = infcx.shallow_resolve(infer); | |
46 | if resolved == infer { | |
47 | // No progress. | |
48 | return None; | |
49 | } | |
f9f354fc | 50 | |
f035d41b XL |
51 | infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Infer(resolved), ty: ct.ty }) |
52 | } | |
53 | _ => ct, | |
54 | } | |
55 | .into() | |
f9f354fc | 56 | } |
f035d41b XL |
57 | // There is nothing we have to do for lifetimes. |
58 | GenericArgKind::Lifetime(..) => return Some(Vec::new()), | |
f9f354fc XL |
59 | }; |
60 | ||
dfeec247 | 61 | let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None }; |
f035d41b XL |
62 | wf.compute(arg); |
63 | debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out); | |
f9f354fc XL |
64 | |
65 | let result = wf.normalize(); | |
f035d41b | 66 | debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", arg, body_id, result); |
f9f354fc | 67 | Some(result) |
e9174d1e SL |
68 | } |
69 | ||
70 | /// Returns the obligations that make this trait reference | |
71 | /// well-formed. For example, if there is a trait `Set` defined like | |
72 | /// `trait Set<K:Eq>`, then the trait reference `Foo: Set<Bar>` is WF | |
73 | /// if `Bar: Eq`. | |
dc9dc135 XL |
74 | pub fn trait_obligations<'a, 'tcx>( |
75 | infcx: &InferCtxt<'a, 'tcx>, | |
76 | param_env: ty::ParamEnv<'tcx>, | |
77 | body_id: hir::HirId, | |
78 | trait_ref: &ty::TraitRef<'tcx>, | |
79 | span: Span, | |
dfeec247 | 80 | item: Option<&'tcx hir::Item<'tcx>>, |
dc9dc135 | 81 | ) -> Vec<traits::PredicateObligation<'tcx>> { |
e74abb32 | 82 | let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item }; |
3b2f2976 | 83 | wf.compute_trait_ref(trait_ref, Elaborate::All); |
e9174d1e SL |
84 | wf.normalize() |
85 | } | |
86 | ||
dc9dc135 XL |
87 | pub fn predicate_obligations<'a, 'tcx>( |
88 | infcx: &InferCtxt<'a, 'tcx>, | |
89 | param_env: ty::ParamEnv<'tcx>, | |
90 | body_id: hir::HirId, | |
f9f354fc | 91 | predicate: ty::Predicate<'tcx>, |
dc9dc135 XL |
92 | span: Span, |
93 | ) -> Vec<traits::PredicateObligation<'tcx>> { | |
e74abb32 | 94 | let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None }; |
e9174d1e | 95 | |
3dfed10e XL |
96 | // It's ok to skip the binder here because wf code is prepared for it |
97 | match predicate.skip_binders() { | |
98 | ty::PredicateAtom::Trait(t, _) => { | |
99 | wf.compute_trait_ref(&t.trait_ref, Elaborate::None); | |
e9174d1e | 100 | } |
3dfed10e XL |
101 | ty::PredicateAtom::RegionOutlives(..) => {} |
102 | ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => { | |
103 | wf.compute(ty.into()); | |
e9174d1e | 104 | } |
3dfed10e | 105 | ty::PredicateAtom::Projection(t) => { |
e9174d1e | 106 | wf.compute_projection(t.projection_ty); |
f035d41b | 107 | wf.compute(t.ty.into()); |
e9174d1e | 108 | } |
3dfed10e | 109 | ty::PredicateAtom::WellFormed(arg) => { |
f035d41b | 110 | wf.compute(arg); |
e9174d1e | 111 | } |
3dfed10e XL |
112 | ty::PredicateAtom::ObjectSafe(_) => {} |
113 | ty::PredicateAtom::ClosureKind(..) => {} | |
114 | ty::PredicateAtom::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ }) => { | |
115 | wf.compute(a.into()); | |
116 | wf.compute(b.into()); | |
cc61c64b | 117 | } |
3dfed10e XL |
118 | ty::PredicateAtom::ConstEvaluatable(def, substs) => { |
119 | let obligations = wf.nominal_obligations(def.did, substs); | |
ea8adc8c XL |
120 | wf.out.extend(obligations); |
121 | ||
f035d41b XL |
122 | for arg in substs.iter() { |
123 | wf.compute(arg); | |
ea8adc8c XL |
124 | } |
125 | } | |
3dfed10e | 126 | ty::PredicateAtom::ConstEquate(c1, c2) => { |
f035d41b XL |
127 | wf.compute(c1.into()); |
128 | wf.compute(c2.into()); | |
f9f354fc | 129 | } |
e9174d1e SL |
130 | } |
131 | ||
132 | wf.normalize() | |
133 | } | |
134 | ||
dc9dc135 XL |
135 | struct WfPredicates<'a, 'tcx> { |
136 | infcx: &'a InferCtxt<'a, 'tcx>, | |
7cac9316 | 137 | param_env: ty::ParamEnv<'tcx>, |
9fa01778 | 138 | body_id: hir::HirId, |
e9174d1e SL |
139 | span: Span, |
140 | out: Vec<traits::PredicateObligation<'tcx>>, | |
dfeec247 | 141 | item: Option<&'tcx hir::Item<'tcx>>, |
e9174d1e SL |
142 | } |
143 | ||
3b2f2976 XL |
144 | /// Controls whether we "elaborate" supertraits and so forth on the WF |
145 | /// predicates. This is a kind of hack to address #43784. The | |
146 | /// underlying problem in that issue was a trait structure like: | |
147 | /// | |
148 | /// ``` | |
149 | /// trait Foo: Copy { } | |
150 | /// trait Bar: Foo { } | |
151 | /// impl<T: Bar> Foo for T { } | |
152 | /// impl<T> Bar for T { } | |
153 | /// ``` | |
154 | /// | |
155 | /// Here, in the `Foo` impl, we will check that `T: Copy` holds -- but | |
156 | /// we decide that this is true because `T: Bar` is in the | |
157 | /// where-clauses (and we can elaborate that to include `T: | |
158 | /// Copy`). This wouldn't be a problem, except that when we check the | |
159 | /// `Bar` impl, we decide that `T: Foo` must hold because of the `Foo` | |
160 | /// impl. And so nowhere did we check that `T: Copy` holds! | |
161 | /// | |
162 | /// To resolve this, we elaborate the WF requirements that must be | |
163 | /// proven when checking impls. This means that (e.g.) the `impl Bar | |
164 | /// for T` will be forced to prove not only that `T: Foo` but also `T: | |
165 | /// Copy` (which it won't be able to do, because there is no `Copy` | |
166 | /// impl for `T`). | |
167 | #[derive(Debug, PartialEq, Eq, Copy, Clone)] | |
168 | enum Elaborate { | |
169 | All, | |
170 | None, | |
171 | } | |
172 | ||
ba9703b0 XL |
173 | fn extend_cause_with_original_assoc_item_obligation<'tcx>( |
174 | tcx: TyCtxt<'tcx>, | |
175 | trait_ref: &ty::TraitRef<'tcx>, | |
176 | item: Option<&hir::Item<'tcx>>, | |
177 | cause: &mut traits::ObligationCause<'tcx>, | |
3dfed10e | 178 | pred: &ty::Predicate<'tcx>, |
ba9703b0 XL |
179 | mut trait_assoc_items: impl Iterator<Item = &'tcx ty::AssocItem>, |
180 | ) { | |
181 | debug!( | |
182 | "extended_cause_with_original_assoc_item_obligation {:?} {:?} {:?} {:?}", | |
183 | trait_ref, item, cause, pred | |
184 | ); | |
185 | let items = match item { | |
186 | Some(hir::Item { kind: hir::ItemKind::Impl { items, .. }, .. }) => items, | |
187 | _ => return, | |
188 | }; | |
189 | let fix_span = | |
190 | |impl_item_ref: &hir::ImplItemRef<'_>| match tcx.hir().impl_item(impl_item_ref.id).kind { | |
191 | hir::ImplItemKind::Const(ty, _) | hir::ImplItemKind::TyAlias(ty) => ty.span, | |
192 | _ => impl_item_ref.span, | |
193 | }; | |
3dfed10e XL |
194 | |
195 | // It is fine to skip the binder as we don't care about regions here. | |
196 | match pred.skip_binders() { | |
197 | ty::PredicateAtom::Projection(proj) => { | |
f9f354fc XL |
198 | // The obligation comes not from the current `impl` nor the `trait` being implemented, |
199 | // but rather from a "second order" obligation, where an associated type has a | |
200 | // projection coming from another associated type. See | |
201 | // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs` and | |
202 | // `traits-assoc-type-in-supertrait-bad.rs`. | |
3dfed10e | 203 | if let ty::Projection(projection_ty) = proj.ty.kind { |
f9f354fc XL |
204 | let trait_assoc_item = tcx.associated_item(projection_ty.item_def_id); |
205 | if let Some(impl_item_span) = | |
206 | items.iter().find(|item| item.ident == trait_assoc_item.ident).map(fix_span) | |
207 | { | |
f035d41b | 208 | cause.make_mut().span = impl_item_span; |
ba9703b0 XL |
209 | } |
210 | } | |
211 | } | |
3dfed10e | 212 | ty::PredicateAtom::Trait(pred, _) => { |
ba9703b0 XL |
213 | // An associated item obligation born out of the `trait` failed to be met. An example |
214 | // can be seen in `ui/associated-types/point-at-type-on-obligation-failure-2.rs`. | |
215 | debug!("extended_cause_with_original_assoc_item_obligation trait proj {:?}", pred); | |
3dfed10e | 216 | if let ty::Projection(ty::ProjectionTy { item_def_id, .. }) = pred.self_ty().kind { |
ba9703b0 | 217 | if let Some(impl_item_span) = trait_assoc_items |
3dfed10e | 218 | .find(|i| i.def_id == item_def_id) |
ba9703b0 XL |
219 | .and_then(|trait_assoc_item| { |
220 | items.iter().find(|i| i.ident == trait_assoc_item.ident).map(fix_span) | |
221 | }) | |
222 | { | |
f035d41b | 223 | cause.make_mut().span = impl_item_span; |
ba9703b0 XL |
224 | } |
225 | } | |
226 | } | |
227 | _ => {} | |
228 | } | |
229 | } | |
230 | ||
dc9dc135 | 231 | impl<'a, 'tcx> WfPredicates<'a, 'tcx> { |
f9f354fc XL |
232 | fn tcx(&self) -> TyCtxt<'tcx> { |
233 | self.infcx.tcx | |
234 | } | |
235 | ||
f035d41b | 236 | fn cause(&self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { |
9cc50fc6 | 237 | traits::ObligationCause::new(self.span, self.body_id, code) |
e9174d1e SL |
238 | } |
239 | ||
240 | fn normalize(&mut self) -> Vec<traits::PredicateObligation<'tcx>> { | |
241 | let cause = self.cause(traits::MiscObligation); | |
242 | let infcx = &mut self.infcx; | |
7cac9316 | 243 | let param_env = self.param_env; |
74b04a01 XL |
244 | let mut obligations = Vec::with_capacity(self.out.len()); |
245 | for pred in &self.out { | |
246 | assert!(!pred.has_escaping_bound_vars()); | |
247 | let mut selcx = traits::SelectionContext::new(infcx); | |
248 | let i = obligations.len(); | |
249 | let value = | |
250 | traits::normalize_to(&mut selcx, param_env, cause.clone(), pred, &mut obligations); | |
251 | obligations.insert(i, value); | |
252 | } | |
253 | obligations | |
e9174d1e SL |
254 | } |
255 | ||
e74abb32 | 256 | /// Pushes the obligations required for `trait_ref` to be WF into `self.out`. |
3b2f2976 | 257 | fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elaborate) { |
e74abb32 | 258 | let tcx = self.infcx.tcx; |
e9174d1e | 259 | let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs); |
e9174d1e | 260 | |
ba9703b0 | 261 | debug!("compute_trait_ref obligations {:?}", obligations); |
e9174d1e | 262 | let cause = self.cause(traits::MiscObligation); |
7cac9316 | 263 | let param_env = self.param_env; |
3b2f2976 | 264 | |
ba9703b0 | 265 | let item = self.item; |
dfeec247 | 266 | |
ba9703b0 XL |
267 | let extend = |obligation: traits::PredicateObligation<'tcx>| { |
268 | let mut cause = cause.clone(); | |
269 | if let Some(parent_trait_ref) = obligation.predicate.to_opt_poly_trait_ref() { | |
270 | let derived_cause = traits::DerivedObligationCause { | |
271 | parent_trait_ref, | |
272 | parent_code: Rc::new(obligation.cause.code.clone()), | |
273 | }; | |
f035d41b XL |
274 | cause.make_mut().code = |
275 | traits::ObligationCauseCode::DerivedObligation(derived_cause); | |
ba9703b0 XL |
276 | } |
277 | extend_cause_with_original_assoc_item_obligation( | |
278 | tcx, | |
279 | trait_ref, | |
280 | item, | |
281 | &mut cause, | |
282 | &obligation.predicate, | |
283 | tcx.associated_items(trait_ref.def_id).in_definition_order(), | |
284 | ); | |
285 | traits::Obligation::new(cause, param_env, obligation.predicate) | |
286 | }; | |
e74abb32 | 287 | |
3b2f2976 | 288 | if let Elaborate::All = elaborate { |
ba9703b0 XL |
289 | let implied_obligations = traits::util::elaborate_obligations(tcx, obligations); |
290 | let implied_obligations = implied_obligations.map(extend); | |
3b2f2976 | 291 | self.out.extend(implied_obligations); |
ba9703b0 XL |
292 | } else { |
293 | self.out.extend(obligations); | |
3b2f2976 XL |
294 | } |
295 | ||
f9f354fc | 296 | let tcx = self.tcx(); |
f035d41b XL |
297 | self.out.extend( |
298 | trait_ref | |
299 | .substs | |
300 | .iter() | |
3dfed10e XL |
301 | .enumerate() |
302 | .filter(|(_, arg)| { | |
f035d41b XL |
303 | matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..)) |
304 | }) | |
3dfed10e XL |
305 | .filter(|(_, arg)| !arg.has_escaping_bound_vars()) |
306 | .map(|(i, arg)| { | |
307 | let mut new_cause = cause.clone(); | |
308 | // The first subst is the self ty - use the correct span for it. | |
309 | if i == 0 { | |
310 | if let Some(hir::ItemKind::Impl { self_ty, .. }) = item.map(|i| &i.kind) { | |
311 | new_cause.make_mut().span = self_ty.span; | |
312 | } | |
313 | } | |
f035d41b | 314 | traits::Obligation::new( |
3dfed10e | 315 | new_cause, |
f035d41b | 316 | param_env, |
3dfed10e | 317 | ty::PredicateAtom::WellFormed(arg).to_predicate(tcx), |
f035d41b XL |
318 | ) |
319 | }), | |
320 | ); | |
e9174d1e SL |
321 | } |
322 | ||
323 | /// Pushes the obligations required for `trait_ref::Item` to be WF | |
324 | /// into `self.out`. | |
325 | fn compute_projection(&mut self, data: ty::ProjectionTy<'tcx>) { | |
326 | // A projection is well-formed if (a) the trait ref itself is | |
a7813a04 | 327 | // WF and (b) the trait-ref holds. (It may also be |
e9174d1e | 328 | // normalizable and be WF that way.) |
041b39d2 | 329 | let trait_ref = data.trait_ref(self.infcx.tcx); |
3b2f2976 | 330 | self.compute_trait_ref(&trait_ref, Elaborate::None); |
e9174d1e | 331 | |
a1dfa0c6 | 332 | if !data.has_escaping_bound_vars() { |
f9f354fc | 333 | let predicate = trait_ref.without_const().to_predicate(self.infcx.tcx); |
e9174d1e | 334 | let cause = self.cause(traits::ProjectionWf(data)); |
7cac9316 | 335 | self.out.push(traits::Obligation::new(cause, self.param_env, predicate)); |
e9174d1e SL |
336 | } |
337 | } | |
338 | ||
9e0c209e | 339 | fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) { |
a1dfa0c6 | 340 | if !subty.has_escaping_bound_vars() { |
a7813a04 | 341 | let cause = self.cause(cause); |
476ff2be | 342 | let trait_ref = ty::TraitRef { |
3dfed10e | 343 | def_id: self.infcx.tcx.require_lang_item(LangItem::Sized, None), |
476ff2be SL |
344 | substs: self.infcx.tcx.mk_substs_trait(subty, &[]), |
345 | }; | |
dfeec247 XL |
346 | self.out.push(traits::Obligation::new( |
347 | cause, | |
348 | self.param_env, | |
f9f354fc | 349 | trait_ref.without_const().to_predicate(self.infcx.tcx), |
dfeec247 | 350 | )); |
a7813a04 XL |
351 | } |
352 | } | |
353 | ||
f9f354fc | 354 | /// Pushes all the predicates needed to validate that `ty` is WF into `out`. |
f035d41b XL |
355 | fn compute(&mut self, arg: GenericArg<'tcx>) { |
356 | let mut walker = arg.walk(); | |
7cac9316 | 357 | let param_env = self.param_env; |
ba9703b0 XL |
358 | while let Some(arg) = walker.next() { |
359 | let ty = match arg.unpack() { | |
360 | GenericArgKind::Type(ty) => ty, | |
361 | ||
362 | // No WF constraints for lifetimes being present, any outlives | |
363 | // obligations are handled by the parent (e.g. `ty::Ref`). | |
364 | GenericArgKind::Lifetime(_) => continue, | |
365 | ||
f035d41b XL |
366 | GenericArgKind::Const(constant) => { |
367 | match constant.val { | |
3dfed10e | 368 | ty::ConstKind::Unevaluated(def, substs, promoted) => { |
f035d41b XL |
369 | assert!(promoted.is_none()); |
370 | ||
3dfed10e | 371 | let obligations = self.nominal_obligations(def.did, substs); |
f035d41b XL |
372 | self.out.extend(obligations); |
373 | ||
3dfed10e | 374 | let predicate = ty::PredicateAtom::ConstEvaluatable(def, substs) |
f035d41b XL |
375 | .to_predicate(self.tcx()); |
376 | let cause = self.cause(traits::MiscObligation); | |
377 | self.out.push(traits::Obligation::new( | |
378 | cause, | |
379 | self.param_env, | |
380 | predicate, | |
381 | )); | |
382 | } | |
383 | ty::ConstKind::Infer(infer) => { | |
384 | let resolved = self.infcx.shallow_resolve(infer); | |
385 | // the `InferConst` changed, meaning that we made progress. | |
386 | if resolved != infer { | |
387 | let cause = self.cause(traits::MiscObligation); | |
388 | ||
389 | let resolved_constant = self.infcx.tcx.mk_const(ty::Const { | |
390 | val: ty::ConstKind::Infer(resolved), | |
391 | ..*constant | |
392 | }); | |
393 | self.out.push(traits::Obligation::new( | |
394 | cause, | |
395 | self.param_env, | |
3dfed10e | 396 | ty::PredicateAtom::WellFormed(resolved_constant.into()) |
f035d41b XL |
397 | .to_predicate(self.tcx()), |
398 | )); | |
399 | } | |
400 | } | |
401 | ty::ConstKind::Error(_) | |
402 | | ty::ConstKind::Param(_) | |
403 | | ty::ConstKind::Bound(..) | |
404 | | ty::ConstKind::Placeholder(..) => { | |
405 | // These variants are trivially WF, so nothing to do here. | |
406 | } | |
407 | ty::ConstKind::Value(..) => { | |
408 | // FIXME: Enforce that values are structurally-matchable. | |
409 | } | |
410 | } | |
411 | continue; | |
412 | } | |
ba9703b0 XL |
413 | }; |
414 | ||
e74abb32 | 415 | match ty.kind { |
dfeec247 XL |
416 | ty::Bool |
417 | | ty::Char | |
418 | | ty::Int(..) | |
419 | | ty::Uint(..) | |
420 | | ty::Float(..) | |
f035d41b | 421 | | ty::Error(_) |
dfeec247 XL |
422 | | ty::Str |
423 | | ty::GeneratorWitness(..) | |
424 | | ty::Never | |
425 | | ty::Param(_) | |
426 | | ty::Bound(..) | |
427 | | ty::Placeholder(..) | |
428 | | ty::Foreign(..) => { | |
e9174d1e SL |
429 | // WfScalar, WfParameter, etc |
430 | } | |
431 | ||
f9f354fc XL |
432 | // Can only infer to `ty::Int(_) | ty::Uint(_)`. |
433 | ty::Infer(ty::IntVar(_)) => {} | |
434 | ||
435 | // Can only infer to `ty::Float(_)`. | |
436 | ty::Infer(ty::FloatVar(_)) => {} | |
437 | ||
b7449926 | 438 | ty::Slice(subty) => { |
ea8adc8c XL |
439 | self.require_sized(subty, traits::SliceOrArrayElem); |
440 | } | |
441 | ||
f035d41b | 442 | ty::Array(subty, _) => { |
9e0c209e | 443 | self.require_sized(subty, traits::SliceOrArrayElem); |
f035d41b | 444 | // Note that we handle the len is implicitly checked while walking `arg`. |
a7813a04 XL |
445 | } |
446 | ||
b7449926 | 447 | ty::Tuple(ref tys) => { |
a7813a04 XL |
448 | if let Some((_last, rest)) = tys.split_last() { |
449 | for elem in rest { | |
48663c56 | 450 | self.require_sized(elem.expect_ty(), traits::TupleElem); |
e9174d1e | 451 | } |
9cc50fc6 | 452 | } |
e9174d1e SL |
453 | } |
454 | ||
b7449926 | 455 | ty::RawPtr(_) => { |
f035d41b | 456 | // Simple cases that are WF if their type args are WF. |
e9174d1e SL |
457 | } |
458 | ||
b7449926 | 459 | ty::Projection(data) => { |
f035d41b | 460 | walker.skip_current_subtree(); // Subtree handled by compute_projection. |
e9174d1e SL |
461 | self.compute_projection(data); |
462 | } | |
463 | ||
b7449926 | 464 | ty::Adt(def, substs) => { |
e9174d1e SL |
465 | // WfNominalType |
466 | let obligations = self.nominal_obligations(def.did, substs); | |
467 | self.out.extend(obligations); | |
468 | } | |
469 | ||
0731742a XL |
470 | ty::FnDef(did, substs) => { |
471 | let obligations = self.nominal_obligations(did, substs); | |
472 | self.out.extend(obligations); | |
473 | } | |
474 | ||
b7449926 | 475 | ty::Ref(r, rty, _) => { |
e9174d1e | 476 | // WfReference |
a1dfa0c6 | 477 | if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() { |
e9174d1e | 478 | let cause = self.cause(traits::ReferenceOutlivesReferent(ty)); |
dfeec247 XL |
479 | self.out.push(traits::Obligation::new( |
480 | cause, | |
481 | param_env, | |
3dfed10e XL |
482 | ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(rty, r)) |
483 | .to_predicate(self.tcx()), | |
dfeec247 | 484 | )); |
e9174d1e SL |
485 | } |
486 | } | |
487 | ||
b7449926 | 488 | ty::Generator(..) => { |
ff7c6d11 XL |
489 | // Walk ALL the types in the generator: this will |
490 | // include the upvar types as well as the yield | |
491 | // type. Note that this is mildly distinct from | |
492 | // the closure case, where we have to be careful | |
493 | // about the signature of the closure. We don't | |
494 | // have the problem of implied bounds here since | |
495 | // generators don't take arguments. | |
496 | } | |
497 | ||
ba9703b0 | 498 | ty::Closure(_, substs) => { |
ff7c6d11 XL |
499 | // Only check the upvar types for WF, not the rest |
500 | // of the types within. This is needed because we | |
501 | // capture the signature and it may not be WF | |
502 | // without the implied bounds. Consider a closure | |
503 | // like `|x: &'a T|` -- it may be that `T: 'a` is | |
504 | // not known to hold in the creator's context (and | |
505 | // indeed the closure may not be invoked by its | |
506 | // creator, but rather turned to someone who *can* | |
507 | // verify that). | |
508 | // | |
509 | // The special treatment of closures here really | |
510 | // ought not to be necessary either; the problem | |
511 | // is related to #25860 -- there is no way for us | |
512 | // to express a fn type complete with the implied | |
513 | // bounds that it is assuming. I think in reality | |
514 | // the WF rules around fn are a bit messed up, and | |
515 | // that is the rot problem: `fn(&'a T)` should | |
516 | // probably always be WF, because it should be | |
517 | // shorthand for something like `where(T: 'a) { | |
518 | // fn(&'a T) }`, as discussed in #25860. | |
9cc50fc6 | 519 | // |
ff7c6d11 XL |
520 | // Note that we are also skipping the generic |
521 | // types. This is consistent with the `outlives` | |
522 | // code, but anyway doesn't matter: within the fn | |
523 | // body where they are created, the generics will | |
524 | // always be WF, and outside of that fn body we | |
525 | // are not directly inspecting closure types | |
526 | // anyway, except via auto trait matching (which | |
527 | // only inspects the upvar types). | |
f9f354fc | 528 | walker.skip_current_subtree(); // subtree handled below |
ba9703b0 | 529 | for upvar_ty in substs.as_closure().upvar_tys() { |
f9f354fc | 530 | // FIXME(eddyb) add the type to `walker` instead of recursing. |
f035d41b | 531 | self.compute(upvar_ty.into()); |
ff7c6d11 | 532 | } |
e9174d1e SL |
533 | } |
534 | ||
0731742a | 535 | ty::FnPtr(_) => { |
54a0048b | 536 | // let the loop iterate into the argument/return |
9cc50fc6 | 537 | // types appearing in the fn signature |
e9174d1e SL |
538 | } |
539 | ||
b7449926 | 540 | ty::Opaque(did, substs) => { |
5bcae85e SL |
541 | // all of the requirements on type parameters |
542 | // should've been checked by the instantiation | |
543 | // of whatever returned this exact `impl Trait`. | |
8faf50e0 | 544 | |
416331ca | 545 | // for named opaque `impl Trait` types we still need to check them |
dfeec247 | 546 | if ty::is_impl_trait_defn(self.infcx.tcx, did).is_none() { |
8faf50e0 XL |
547 | let obligations = self.nominal_obligations(did, substs); |
548 | self.out.extend(obligations); | |
549 | } | |
5bcae85e SL |
550 | } |
551 | ||
b7449926 | 552 | ty::Dynamic(data, r) => { |
e9174d1e SL |
553 | // WfObject |
554 | // | |
555 | // Here, we defer WF checking due to higher-ranked | |
556 | // regions. This is perhaps not ideal. | |
476ff2be | 557 | self.from_object_ty(ty, data, r); |
e9174d1e SL |
558 | |
559 | // FIXME(#27579) RFC also considers adding trait | |
560 | // obligations that don't refer to Self and | |
561 | // checking those | |
562 | ||
f9f354fc | 563 | let defer_to_coercion = self.tcx().features().object_safe_for_dispatch; |
e74abb32 XL |
564 | |
565 | if !defer_to_coercion { | |
566 | let cause = self.cause(traits::MiscObligation); | |
dfeec247 | 567 | let component_traits = data.auto_traits().chain(data.principal_def_id()); |
f9f354fc | 568 | let tcx = self.tcx(); |
dfeec247 XL |
569 | self.out.extend(component_traits.map(|did| { |
570 | traits::Obligation::new( | |
e74abb32 XL |
571 | cause.clone(), |
572 | param_env, | |
3dfed10e | 573 | ty::PredicateAtom::ObjectSafe(did).to_predicate(tcx), |
dfeec247 XL |
574 | ) |
575 | })); | |
e74abb32 | 576 | } |
e9174d1e SL |
577 | } |
578 | ||
579 | // Inference variables are the complicated case, since we don't | |
580 | // know what type they are. We do two things: | |
581 | // | |
582 | // 1. Check if they have been resolved, and if so proceed with | |
583 | // THAT type. | |
f9f354fc XL |
584 | // 2. If not, we've at least simplified things (e.g., we went |
585 | // from `Vec<$0>: WF` to `$0: WF`), so we can | |
e9174d1e SL |
586 | // register a pending obligation and keep |
587 | // moving. (Goal is that an "inductive hypothesis" | |
588 | // is satisfied to ensure termination.) | |
f9f354fc XL |
589 | // See also the comment on `fn obligations`, describing "livelock" |
590 | // prevention, which happens before this can be reached. | |
b7449926 | 591 | ty::Infer(_) => { |
e9174d1e | 592 | let ty = self.infcx.shallow_resolve(ty); |
f9f354fc XL |
593 | if let ty::Infer(ty::TyVar(_)) = ty.kind { |
594 | // Not yet resolved, but we've made progress. | |
e9174d1e | 595 | let cause = self.cause(traits::MiscObligation); |
f9f354fc XL |
596 | self.out.push(traits::Obligation::new( |
597 | cause, | |
598 | param_env, | |
3dfed10e | 599 | ty::PredicateAtom::WellFormed(ty.into()).to_predicate(self.tcx()), |
f9f354fc | 600 | )); |
e9174d1e | 601 | } else { |
f9f354fc XL |
602 | // Yes, resolved, proceed with the result. |
603 | // FIXME(eddyb) add the type to `walker` instead of recursing. | |
f035d41b | 604 | self.compute(ty.into()); |
e9174d1e SL |
605 | } |
606 | } | |
607 | } | |
608 | } | |
e9174d1e SL |
609 | } |
610 | ||
dfeec247 XL |
611 | fn nominal_obligations( |
612 | &mut self, | |
613 | def_id: DefId, | |
614 | substs: SubstsRef<'tcx>, | |
615 | ) -> Vec<traits::PredicateObligation<'tcx>> { | |
616 | let predicates = self.infcx.tcx.predicates_of(def_id).instantiate(self.infcx.tcx, substs); | |
dfeec247 XL |
617 | predicates |
618 | .predicates | |
619 | .into_iter() | |
ba9703b0 XL |
620 | .zip(predicates.spans.into_iter()) |
621 | .map(|(pred, span)| { | |
622 | let cause = self.cause(traits::BindingObligation(def_id, span)); | |
623 | traits::Obligation::new(cause, self.param_env, pred) | |
624 | }) | |
dfeec247 XL |
625 | .filter(|pred| !pred.has_escaping_bound_vars()) |
626 | .collect() | |
e9174d1e SL |
627 | } |
628 | ||
dfeec247 XL |
629 | fn from_object_ty( |
630 | &mut self, | |
631 | ty: Ty<'tcx>, | |
632 | data: ty::Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>, | |
633 | region: ty::Region<'tcx>, | |
634 | ) { | |
e9174d1e SL |
635 | // Imagine a type like this: |
636 | // | |
637 | // trait Foo { } | |
638 | // trait Bar<'c> : 'c { } | |
639 | // | |
640 | // &'b (Foo+'c+Bar<'d>) | |
641 | // ^ | |
642 | // | |
643 | // In this case, the following relationships must hold: | |
644 | // | |
645 | // 'b <= 'c | |
646 | // 'd <= 'c | |
647 | // | |
648 | // The first conditions is due to the normal region pointer | |
649 | // rules, which say that a reference cannot outlive its | |
650 | // referent. | |
651 | // | |
652 | // The final condition may be a bit surprising. In particular, | |
653 | // you may expect that it would have been `'c <= 'd`, since | |
654 | // usually lifetimes of outer things are conservative | |
655 | // approximations for inner things. However, it works somewhat | |
656 | // differently with trait objects: here the idea is that if the | |
657 | // user specifies a region bound (`'c`, in this case) it is the | |
658 | // "master bound" that *implies* that bounds from other traits are | |
659 | // all met. (Remember that *all bounds* in a type like | |
660 | // `Foo+Bar+Zed` must be met, not just one, hence if we write | |
661 | // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and | |
662 | // 'y.) | |
663 | // | |
664 | // Note: in fact we only permit builtin traits, not `Bar<'d>`, I | |
665 | // am looking forward to the future here. | |
532ac7d7 | 666 | if !data.has_escaping_bound_vars() && !region.has_escaping_bound_vars() { |
dfeec247 | 667 | let implicit_bounds = object_region_bounds(self.infcx.tcx, data); |
e9174d1e | 668 | |
476ff2be | 669 | let explicit_bound = region; |
e9174d1e | 670 | |
0bf4aa26 | 671 | self.out.reserve(implicit_bounds.len()); |
e9174d1e | 672 | for implicit_bound in implicit_bounds { |
c30ab7b3 | 673 | let cause = self.cause(traits::ObjectTypeBound(ty, explicit_bound)); |
dfeec247 XL |
674 | let outlives = |
675 | ty::Binder::dummy(ty::OutlivesPredicate(explicit_bound, implicit_bound)); | |
676 | self.out.push(traits::Obligation::new( | |
677 | cause, | |
678 | self.param_env, | |
f9f354fc | 679 | outlives.to_predicate(self.infcx.tcx), |
dfeec247 | 680 | )); |
e9174d1e SL |
681 | } |
682 | } | |
683 | } | |
684 | } | |
685 | ||
9fa01778 | 686 | /// Given an object type like `SomeTrait + Send`, computes the lifetime |
e9174d1e SL |
687 | /// bounds that must hold on the elided self type. These are derived |
688 | /// from the declarations of `SomeTrait`, `Send`, and friends -- if | |
689 | /// they declare `trait SomeTrait : 'static`, for example, then | |
690 | /// `'static` would appear in the list. The hard work is done by | |
dfeec247 | 691 | /// `infer::required_region_bounds`, see that for more information. |
dc9dc135 XL |
692 | pub fn object_region_bounds<'tcx>( |
693 | tcx: TyCtxt<'tcx>, | |
694 | existential_predicates: ty::Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>, | |
695 | ) -> Vec<ty::Region<'tcx>> { | |
e9174d1e SL |
696 | // Since we don't actually *know* the self type for an object, |
697 | // this "open(err)" serves as a kind of dummy standin -- basically | |
0bf4aa26 | 698 | // a placeholder type. |
48663c56 | 699 | let open_ty = tcx.mk_ty_infer(ty::FreshTy(0)); |
e9174d1e | 700 | |
ba9703b0 | 701 | let predicates = existential_predicates.iter().filter_map(|predicate| { |
f035d41b | 702 | if let ty::ExistentialPredicate::Projection(_) = predicate.skip_binder() { |
ba9703b0 XL |
703 | None |
704 | } else { | |
705 | Some(predicate.with_self_ty(tcx, open_ty)) | |
60c5eb7d | 706 | } |
ba9703b0 | 707 | }); |
60c5eb7d | 708 | |
ba9703b0 | 709 | required_region_bounds(tcx, open_ty, predicates) |
60c5eb7d | 710 | } |