]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | //! "Object safety" refers to the ability for a trait to be converted |
2 | //! to an object. In general, traits may only be converted to an | |
3 | //! object if all of their methods meet certain criteria. In particular, | |
4 | //! they must: | |
5 | //! | |
a1dfa0c6 XL |
6 | //! - have a suitable receiver from which we can extract a vtable and coerce to a "thin" version |
7 | //! that doesn't contain the vtable; | |
1a4d82fc | 8 | //! - not reference the erased type `Self` except for in this receiver; |
9fa01778 | 9 | //! - not have generic type parameters. |
1a4d82fc | 10 | |
1a4d82fc JJ |
11 | use super::elaborate_predicates; |
12 | ||
74b04a01 | 13 | use crate::infer::TyCtxtInferExt; |
ba9703b0 | 14 | use crate::traits::query::evaluate_obligation::InferCtxtExt; |
9fa01778 | 15 | use crate::traits::{self, Obligation, ObligationCause}; |
f2b60f7d | 16 | use hir::def::DefKind; |
04454e1e | 17 | use rustc_errors::{FatalError, MultiSpan}; |
dfeec247 XL |
18 | use rustc_hir as hir; |
19 | use rustc_hir::def_id::DefId; | |
064997fb | 20 | use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst}; |
f9f354fc | 21 | use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst}; |
923072b8 | 22 | use rustc_middle::ty::{ |
064997fb | 23 | self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, |
923072b8 | 24 | }; |
f9f354fc | 25 | use rustc_middle::ty::{Predicate, ToPredicate}; |
dfeec247 XL |
26 | use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; |
27 | use rustc_span::symbol::Symbol; | |
04454e1e | 28 | use rustc_span::Span; |
74b04a01 | 29 | use smallvec::SmallVec; |
dfeec247 | 30 | |
74b04a01 | 31 | use std::iter; |
29967ef6 | 32 | use std::ops::ControlFlow; |
1a4d82fc | 33 | |
74b04a01 | 34 | pub use crate::traits::{MethodViolationCode, ObjectSafetyViolation}; |
1a4d82fc | 35 | |
dfeec247 XL |
36 | /// Returns the object safety violations that affect |
37 | /// astconv -- currently, `Self` in supertraits. This is needed | |
38 | /// because `object_safety_violations` can't be used during | |
39 | /// type collection. | |
40 | pub fn astconv_object_safety_violations( | |
41 | tcx: TyCtxt<'_>, | |
42 | trait_def_id: DefId, | |
43 | ) -> Vec<ObjectSafetyViolation> { | |
44 | debug_assert!(tcx.generics_of(trait_def_id).has_self); | |
45 | let violations = traits::supertrait_def_ids(tcx, trait_def_id) | |
74b04a01 XL |
46 | .map(|def_id| predicates_reference_self(tcx, def_id, true)) |
47 | .filter(|spans| !spans.is_empty()) | |
ba9703b0 | 48 | .map(ObjectSafetyViolation::SupertraitSelf) |
dfeec247 XL |
49 | .collect(); |
50 | ||
51 | debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}", trait_def_id, violations); | |
52 | ||
53 | violations | |
54 | } | |
1a4d82fc | 55 | |
a2a8927a | 56 | fn object_safety_violations(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &'_ [ObjectSafetyViolation] { |
dfeec247 XL |
57 | debug_assert!(tcx.generics_of(trait_def_id).has_self); |
58 | debug!("object_safety_violations: {:?}", trait_def_id); | |
1a4d82fc | 59 | |
ba9703b0 XL |
60 | tcx.arena.alloc_from_iter( |
61 | traits::supertrait_def_ids(tcx, trait_def_id) | |
62 | .flat_map(|def_id| object_safety_violations_for_trait(tcx, def_id)), | |
63 | ) | |
dfeec247 | 64 | } |
a7813a04 | 65 | |
dfeec247 XL |
66 | /// We say a method is *vtable safe* if it can be invoked on a trait |
67 | /// object. Note that object-safe traits can have some | |
68 | /// non-vtable-safe methods, so long as they require `Self: Sized` or | |
69 | /// otherwise ensure that they cannot be used when `Self = Trait`. | |
70 | pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: &ty::AssocItem) -> bool { | |
71 | debug_assert!(tcx.generics_of(trait_def_id).has_self); | |
72 | debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method); | |
73 | // Any method that has a `Self: Sized` bound cannot be called. | |
74 | if generics_require_sized_self(tcx, method.def_id) { | |
75 | return false; | |
76 | } | |
a1dfa0c6 | 77 | |
dfeec247 XL |
78 | match virtual_call_violation_for_method(tcx, trait_def_id, method) { |
79 | None | Some(MethodViolationCode::WhereClauseReferencesSelf) => true, | |
80 | Some(_) => false, | |
85aaf69f | 81 | } |
dfeec247 | 82 | } |
1a4d82fc | 83 | |
dfeec247 XL |
84 | fn object_safety_violations_for_trait( |
85 | tcx: TyCtxt<'_>, | |
86 | trait_def_id: DefId, | |
87 | ) -> Vec<ObjectSafetyViolation> { | |
88 | // Check methods for violations. | |
89 | let mut violations: Vec<_> = tcx | |
90 | .associated_items(trait_def_id) | |
74b04a01 | 91 | .in_definition_order() |
ba9703b0 | 92 | .filter(|item| item.kind == ty::AssocKind::Fn) |
dfeec247 XL |
93 | .filter_map(|item| { |
94 | object_safety_violation_for_method(tcx, trait_def_id, &item) | |
5099ac24 | 95 | .map(|(code, span)| ObjectSafetyViolation::Method(item.name, code, span)) |
dfeec247 XL |
96 | }) |
97 | .filter(|violation| { | |
98 | if let ObjectSafetyViolation::Method( | |
99 | _, | |
100 | MethodViolationCode::WhereClauseReferencesSelf, | |
101 | span, | |
102 | ) = violation | |
103 | { | |
923072b8 | 104 | lint_object_unsafe_trait(tcx, *span, trait_def_id, &violation); |
dfeec247 XL |
105 | false |
106 | } else { | |
107 | true | |
108 | } | |
109 | }) | |
110 | .collect(); | |
e1599b0c | 111 | |
dfeec247 XL |
112 | // Check the trait itself. |
113 | if trait_has_sized_self(tcx, trait_def_id) { | |
74b04a01 XL |
114 | // We don't want to include the requirement from `Sized` itself to be `Sized` in the list. |
115 | let spans = get_sized_bounds(tcx, trait_def_id); | |
116 | violations.push(ObjectSafetyViolation::SizedSelf(spans)); | |
dfeec247 | 117 | } |
74b04a01 XL |
118 | let spans = predicates_reference_self(tcx, trait_def_id, false); |
119 | if !spans.is_empty() { | |
120 | violations.push(ObjectSafetyViolation::SupertraitSelf(spans)); | |
e1599b0c | 121 | } |
29967ef6 XL |
122 | let spans = bounds_reference_self(tcx, trait_def_id); |
123 | if !spans.is_empty() { | |
124 | violations.push(ObjectSafetyViolation::SupertraitSelf(spans)); | |
125 | } | |
e1599b0c | 126 | |
dfeec247 XL |
127 | violations.extend( |
128 | tcx.associated_items(trait_def_id) | |
74b04a01 | 129 | .in_definition_order() |
dfeec247 | 130 | .filter(|item| item.kind == ty::AssocKind::Const) |
5099ac24 FG |
131 | .map(|item| { |
132 | let ident = item.ident(tcx); | |
133 | ObjectSafetyViolation::AssocConst(ident.name, ident.span) | |
134 | }), | |
dfeec247 XL |
135 | ); |
136 | ||
5e7ed085 FG |
137 | if !tcx.features().generic_associated_types_extended { |
138 | violations.extend( | |
139 | tcx.associated_items(trait_def_id) | |
140 | .in_definition_order() | |
141 | .filter(|item| item.kind == ty::AssocKind::Type) | |
142 | .filter(|item| !tcx.generics_of(item.def_id).params.is_empty()) | |
143 | .map(|item| { | |
144 | let ident = item.ident(tcx); | |
145 | ObjectSafetyViolation::GAT(ident.name, ident.span) | |
146 | }), | |
147 | ); | |
148 | } | |
cdc7bbd5 | 149 | |
dfeec247 XL |
150 | debug!( |
151 | "object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", | |
152 | trait_def_id, violations | |
153 | ); | |
154 | ||
155 | violations | |
156 | } | |
157 | ||
29967ef6 XL |
158 | /// Lint object-unsafe trait. |
159 | fn lint_object_unsafe_trait( | |
160 | tcx: TyCtxt<'_>, | |
161 | span: Span, | |
162 | trait_def_id: DefId, | |
163 | violation: &ObjectSafetyViolation, | |
164 | ) { | |
165 | // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id. | |
166 | // It's also hard to get a use site span, so we use the method definition span. | |
167 | tcx.struct_span_lint_hir(WHERE_CLAUSES_OBJECT_SAFETY, hir::CRATE_HIR_ID, span, |lint| { | |
168 | let mut err = lint.build(&format!( | |
169 | "the trait `{}` cannot be made into an object", | |
170 | tcx.def_path_str(trait_def_id) | |
171 | )); | |
172 | let node = tcx.hir().get_if_local(trait_def_id); | |
173 | let mut spans = MultiSpan::from_span(span); | |
174 | if let Some(hir::Node::Item(item)) = node { | |
04454e1e | 175 | spans.push_span_label(item.ident.span, "this trait cannot be made into an object..."); |
29967ef6 XL |
176 | spans.push_span_label(span, format!("...because {}", violation.error_msg())); |
177 | } else { | |
178 | spans.push_span_label( | |
179 | span, | |
180 | format!( | |
181 | "the trait cannot be made into an object because {}", | |
182 | violation.error_msg() | |
183 | ), | |
184 | ); | |
185 | }; | |
186 | err.span_note( | |
187 | spans, | |
188 | "for a trait to be \"object safe\" it needs to allow building a vtable to allow the \ | |
189 | call to be resolvable dynamically; for more information visit \ | |
190 | <https://doc.rust-lang.org/reference/items/traits.html#object-safety>", | |
191 | ); | |
192 | if node.is_some() { | |
193 | // Only provide the help if its a local trait, otherwise it's not | |
194 | violation.solution(&mut err); | |
195 | } | |
196 | err.emit(); | |
197 | }); | |
198 | } | |
199 | ||
ba9703b0 XL |
200 | fn sized_trait_bound_spans<'tcx>( |
201 | tcx: TyCtxt<'tcx>, | |
202 | bounds: hir::GenericBounds<'tcx>, | |
203 | ) -> impl 'tcx + Iterator<Item = Span> { | |
204 | bounds.iter().filter_map(move |b| match b { | |
205 | hir::GenericBound::Trait(trait_ref, hir::TraitBoundModifier::None) | |
206 | if trait_has_sized_self( | |
207 | tcx, | |
208 | trait_ref.trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()), | |
209 | ) => | |
210 | { | |
211 | // Fetch spans for supertraits that are `Sized`: `trait T: Super` | |
212 | Some(trait_ref.span) | |
213 | } | |
214 | _ => None, | |
215 | }) | |
216 | } | |
217 | ||
74b04a01 XL |
218 | fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> { |
219 | tcx.hir() | |
220 | .get_if_local(trait_def_id) | |
221 | .and_then(|node| match node { | |
222 | hir::Node::Item(hir::Item { | |
223 | kind: hir::ItemKind::Trait(.., generics, bounds, _), | |
224 | .. | |
225 | }) => Some( | |
226 | generics | |
74b04a01 XL |
227 | .predicates |
228 | .iter() | |
229 | .filter_map(|pred| { | |
230 | match pred { | |
231 | hir::WherePredicate::BoundPredicate(pred) | |
ba9703b0 | 232 | if pred.bounded_ty.hir_id.owner.to_def_id() == trait_def_id => |
74b04a01 XL |
233 | { |
234 | // Fetch spans for trait bounds that are Sized: | |
235 | // `trait T where Self: Pred` | |
ba9703b0 | 236 | Some(sized_trait_bound_spans(tcx, pred.bounds)) |
74b04a01 XL |
237 | } |
238 | _ => None, | |
239 | } | |
240 | }) | |
241 | .flatten() | |
ba9703b0 XL |
242 | // Fetch spans for supertraits that are `Sized`: `trait T: Super`. |
243 | .chain(sized_trait_bound_spans(tcx, bounds)) | |
74b04a01 XL |
244 | .collect::<SmallVec<[Span; 1]>>(), |
245 | ), | |
246 | _ => None, | |
247 | }) | |
248 | .unwrap_or_else(SmallVec::new) | |
249 | } | |
250 | ||
251 | fn predicates_reference_self( | |
252 | tcx: TyCtxt<'_>, | |
253 | trait_def_id: DefId, | |
254 | supertraits_only: bool, | |
255 | ) -> SmallVec<[Span; 1]> { | |
c295e0f8 | 256 | let trait_ref = ty::TraitRef::identity(tcx, trait_def_id); |
dfeec247 XL |
257 | let predicates = if supertraits_only { |
258 | tcx.super_predicates_of(trait_def_id) | |
259 | } else { | |
260 | tcx.predicates_of(trait_def_id) | |
261 | }; | |
dfeec247 XL |
262 | predicates |
263 | .predicates | |
264 | .iter() | |
29967ef6 XL |
265 | .map(|&(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp)) |
266 | .filter_map(|predicate| predicate_references_self(tcx, predicate)) | |
267 | .collect() | |
268 | } | |
269 | ||
270 | fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> { | |
29967ef6 XL |
271 | tcx.associated_items(trait_def_id) |
272 | .in_definition_order() | |
273 | .filter(|item| item.kind == ty::AssocKind::Type) | |
274 | .flat_map(|item| tcx.explicit_item_bounds(item.def_id)) | |
5869c6ff | 275 | .filter_map(|pred_span| predicate_references_self(tcx, *pred_span)) |
74b04a01 | 276 | .collect() |
dfeec247 | 277 | } |
1a4d82fc | 278 | |
a2a8927a | 279 | fn predicate_references_self<'tcx>( |
29967ef6 XL |
280 | tcx: TyCtxt<'tcx>, |
281 | (predicate, sp): (ty::Predicate<'tcx>, Span), | |
282 | ) -> Option<Span> { | |
283 | let self_ty = tcx.types.self_param; | |
923072b8 | 284 | let has_self_ty = |arg: &GenericArg<'tcx>| arg.walk().any(|arg| arg == self_ty.into()); |
5869c6ff | 285 | match predicate.kind().skip_binder() { |
94222f64 | 286 | ty::PredicateKind::Trait(ref data) => { |
29967ef6 XL |
287 | // In the case of a trait predicate, we can skip the "self" type. |
288 | if data.trait_ref.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None } | |
289 | } | |
5869c6ff | 290 | ty::PredicateKind::Projection(ref data) => { |
29967ef6 XL |
291 | // And similarly for projections. This should be redundant with |
292 | // the previous check because any projection should have a | |
293 | // matching `Trait` predicate with the same inputs, but we do | |
294 | // the check to be safe. | |
295 | // | |
296 | // It's also won't be redundant if we allow type-generic associated | |
297 | // types for trait objects. | |
298 | // | |
299 | // Note that we *do* allow projection *outputs* to contain | |
300 | // `self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`), | |
301 | // we just require the user to specify *both* outputs | |
302 | // in the object type (i.e., `dyn Foo<Output=(), Result=()>`). | |
303 | // | |
304 | // This is ALT2 in issue #56288, see that for discussion of the | |
305 | // possible alternatives. | |
6a06907d | 306 | if data.projection_ty.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None } |
29967ef6 | 307 | } |
5869c6ff XL |
308 | ty::PredicateKind::WellFormed(..) |
309 | | ty::PredicateKind::ObjectSafe(..) | |
310 | | ty::PredicateKind::TypeOutlives(..) | |
311 | | ty::PredicateKind::RegionOutlives(..) | |
312 | | ty::PredicateKind::ClosureKind(..) | |
313 | | ty::PredicateKind::Subtype(..) | |
94222f64 | 314 | | ty::PredicateKind::Coerce(..) |
5869c6ff XL |
315 | | ty::PredicateKind::ConstEvaluatable(..) |
316 | | ty::PredicateKind::ConstEquate(..) | |
317 | | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, | |
29967ef6 XL |
318 | } |
319 | } | |
320 | ||
dfeec247 XL |
321 | fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { |
322 | generics_require_sized_self(tcx, trait_def_id) | |
323 | } | |
324 | ||
325 | fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | |
5e7ed085 FG |
326 | let Some(sized_def_id) = tcx.lang_items().sized_trait() else { |
327 | return false; /* No Sized trait, can't require it! */ | |
dfeec247 XL |
328 | }; |
329 | ||
330 | // Search for a predicate like `Self : Sized` amongst the trait bounds. | |
331 | let predicates = tcx.predicates_of(def_id); | |
332 | let predicates = predicates.instantiate_identity(tcx).predicates; | |
f9f354fc | 333 | elaborate_predicates(tcx, predicates.into_iter()).any(|obligation| { |
5869c6ff | 334 | match obligation.predicate.kind().skip_binder() { |
94222f64 | 335 | ty::PredicateKind::Trait(ref trait_pred) => { |
3dfed10e | 336 | trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0) |
f9f354fc | 337 | } |
5869c6ff XL |
338 | ty::PredicateKind::Projection(..) |
339 | | ty::PredicateKind::Subtype(..) | |
94222f64 | 340 | | ty::PredicateKind::Coerce(..) |
5869c6ff XL |
341 | | ty::PredicateKind::RegionOutlives(..) |
342 | | ty::PredicateKind::WellFormed(..) | |
343 | | ty::PredicateKind::ObjectSafe(..) | |
344 | | ty::PredicateKind::ClosureKind(..) | |
345 | | ty::PredicateKind::TypeOutlives(..) | |
346 | | ty::PredicateKind::ConstEvaluatable(..) | |
347 | | ty::PredicateKind::ConstEquate(..) | |
348 | | ty::PredicateKind::TypeWellFormedFromEnv(..) => false, | |
a7813a04 | 349 | } |
dfeec247 XL |
350 | }) |
351 | } | |
1a4d82fc | 352 | |
dfeec247 XL |
353 | /// Returns `Some(_)` if this method makes the containing trait not object safe. |
354 | fn object_safety_violation_for_method( | |
355 | tcx: TyCtxt<'_>, | |
356 | trait_def_id: DefId, | |
357 | method: &ty::AssocItem, | |
74b04a01 | 358 | ) -> Option<(MethodViolationCode, Span)> { |
dfeec247 XL |
359 | debug!("object_safety_violation_for_method({:?}, {:?})", trait_def_id, method); |
360 | // Any method that has a `Self : Sized` requisite is otherwise | |
361 | // exempt from the regulations. | |
362 | if generics_require_sized_self(tcx, method.def_id) { | |
363 | return None; | |
364 | } | |
cc61c64b | 365 | |
74b04a01 XL |
366 | let violation = virtual_call_violation_for_method(tcx, trait_def_id, method); |
367 | // Get an accurate span depending on the violation. | |
368 | violation.map(|v| { | |
369 | let node = tcx.hir().get_if_local(method.def_id); | |
064997fb FG |
370 | let span = match (&v, node) { |
371 | (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span, | |
372 | (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span, | |
74b04a01 | 373 | (MethodViolationCode::ReferencesSelfOutput, Some(node)) => { |
5099ac24 | 374 | node.fn_decl().map_or(method.ident(tcx).span, |decl| decl.output.span()) |
74b04a01 | 375 | } |
5099ac24 | 376 | _ => method.ident(tcx).span, |
74b04a01 XL |
377 | }; |
378 | (v, span) | |
379 | }) | |
dfeec247 | 380 | } |
85aaf69f | 381 | |
dfeec247 XL |
382 | /// Returns `Some(_)` if this method cannot be called on a trait |
383 | /// object; this does not necessarily imply that the enclosing trait | |
384 | /// is not object safe, because the method might have a where clause | |
385 | /// `Self:Sized`. | |
386 | fn virtual_call_violation_for_method<'tcx>( | |
387 | tcx: TyCtxt<'tcx>, | |
388 | trait_def_id: DefId, | |
389 | method: &ty::AssocItem, | |
390 | ) -> Option<MethodViolationCode> { | |
29967ef6 XL |
391 | let sig = tcx.fn_sig(method.def_id); |
392 | ||
dfeec247 | 393 | // The method's first parameter must be named `self` |
ba9703b0 | 394 | if !method.fn_has_self_parameter { |
064997fb FG |
395 | let sugg = if let Some(hir::Node::TraitItem(hir::TraitItem { |
396 | generics, | |
397 | kind: hir::TraitItemKind::Fn(sig, _), | |
398 | .. | |
399 | })) = tcx.hir().get_if_local(method.def_id).as_ref() | |
400 | { | |
401 | let sm = tcx.sess.source_map(); | |
402 | Some(( | |
403 | ( | |
404 | format!("&self{}", if sig.decl.inputs.is_empty() { "" } else { ", " }), | |
405 | sm.span_through_char(sig.span, '(').shrink_to_hi(), | |
406 | ), | |
407 | ( | |
408 | format!("{} Self: Sized", generics.add_where_or_trailing_comma()), | |
409 | generics.tail_span_for_predicate_suggestion(), | |
410 | ), | |
411 | )) | |
412 | } else { | |
413 | None | |
414 | }; | |
415 | return Some(MethodViolationCode::StaticMethod(sugg)); | |
a7813a04 | 416 | } |
c34b1796 | 417 | |
064997fb | 418 | for (i, &input_ty) in sig.skip_binder().inputs().iter().enumerate().skip(1) { |
fc512014 | 419 | if contains_illegal_self_type_reference(tcx, trait_def_id, sig.rebind(input_ty)) { |
064997fb FG |
420 | let span = if let Some(hir::Node::TraitItem(hir::TraitItem { |
421 | kind: hir::TraitItemKind::Fn(sig, _), | |
422 | .. | |
423 | })) = tcx.hir().get_if_local(method.def_id).as_ref() | |
424 | { | |
425 | Some(sig.decl.inputs[i].span) | |
426 | } else { | |
427 | None | |
428 | }; | |
429 | return Some(MethodViolationCode::ReferencesSelfInput(span)); | |
dfeec247 XL |
430 | } |
431 | } | |
fc512014 | 432 | if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) { |
74b04a01 | 433 | return Some(MethodViolationCode::ReferencesSelfOutput); |
c34b1796 | 434 | } |
f2b60f7d FG |
435 | if contains_illegal_impl_trait_in_trait(tcx, sig.output()) { |
436 | return Some(MethodViolationCode::ReferencesImplTraitInTrait); | |
437 | } | |
c34b1796 | 438 | |
dfeec247 XL |
439 | // We can't monomorphize things like `fn foo<A>(...)`. |
440 | let own_counts = tcx.generics_of(method.def_id).own_counts(); | |
441 | if own_counts.types + own_counts.consts != 0 { | |
442 | return Some(MethodViolationCode::Generic); | |
a7813a04 | 443 | } |
1a4d82fc | 444 | |
dfeec247 XL |
445 | if tcx |
446 | .predicates_of(method.def_id) | |
447 | .predicates | |
448 | .iter() | |
449 | // A trait object can't claim to live more than the concrete type, | |
450 | // so outlives predicates will always hold. | |
451 | .cloned() | |
452 | .filter(|(p, _)| p.to_opt_type_outlives().is_none()) | |
29967ef6 | 453 | .any(|pred| contains_illegal_self_type_reference(tcx, trait_def_id, pred)) |
dfeec247 XL |
454 | { |
455 | return Some(MethodViolationCode::WhereClauseReferencesSelf); | |
456 | } | |
457 | ||
cdc7bbd5 | 458 | let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0)); |
dfeec247 XL |
459 | |
460 | // Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on. | |
461 | // However, this is already considered object-safe. We allow it as a special case here. | |
462 | // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows | |
463 | // `Receiver: Unsize<Receiver[Self => dyn Trait]>`. | |
464 | if receiver_ty != tcx.types.self_param { | |
465 | if !receiver_is_dispatchable(tcx, method, receiver_ty) { | |
064997fb FG |
466 | let span = if let Some(hir::Node::TraitItem(hir::TraitItem { |
467 | kind: hir::TraitItemKind::Fn(sig, _), | |
468 | .. | |
469 | })) = tcx.hir().get_if_local(method.def_id).as_ref() | |
470 | { | |
471 | Some(sig.decl.inputs[0].span) | |
472 | } else { | |
473 | None | |
474 | }; | |
475 | return Some(MethodViolationCode::UndispatchableReceiver(span)); | |
dfeec247 XL |
476 | } else { |
477 | // Do sanity check to make sure the receiver actually has the layout of a pointer. | |
a7813a04 | 478 | |
ba9703b0 | 479 | use rustc_target::abi::Abi; |
dfeec247 XL |
480 | |
481 | let param_env = tcx.param_env(method.def_id); | |
482 | ||
c295e0f8 | 483 | let abi_of_ty = |ty: Ty<'tcx>| -> Option<Abi> { |
dfeec247 | 484 | match tcx.layout_of(param_env.and(ty)) { |
c295e0f8 | 485 | Ok(layout) => Some(layout.abi), |
1b1a35ee XL |
486 | Err(err) => { |
487 | // #78372 | |
488 | tcx.sess.delay_span_bug( | |
489 | tcx.def_span(method.def_id), | |
490 | &format!("error: {}\n while computing layout for type {:?}", err, ty), | |
491 | ); | |
492 | None | |
493 | } | |
a7813a04 | 494 | } |
dfeec247 XL |
495 | }; |
496 | ||
497 | // e.g., `Rc<()>` | |
498 | let unit_receiver_ty = | |
499 | receiver_for_self_ty(tcx, receiver_ty, tcx.mk_unit(), method.def_id); | |
500 | ||
501 | match abi_of_ty(unit_receiver_ty) { | |
1b1a35ee | 502 | Some(Abi::Scalar(..)) => (), |
dfeec247 XL |
503 | abi => { |
504 | tcx.sess.delay_span_bug( | |
505 | tcx.def_span(method.def_id), | |
506 | &format!( | |
507 | "receiver when `Self = ()` should have a Scalar ABI; found {:?}", | |
508 | abi | |
509 | ), | |
510 | ); | |
0bf4aa26 XL |
511 | } |
512 | } | |
c34b1796 | 513 | |
dfeec247 XL |
514 | let trait_object_ty = |
515 | object_ty_for_trait(tcx, trait_def_id, tcx.mk_region(ty::ReStatic)); | |
1a4d82fc | 516 | |
dfeec247 XL |
517 | // e.g., `Rc<dyn Trait>` |
518 | let trait_object_receiver = | |
519 | receiver_for_self_ty(tcx, receiver_ty, trait_object_ty, method.def_id); | |
1a4d82fc | 520 | |
dfeec247 | 521 | match abi_of_ty(trait_object_receiver) { |
1b1a35ee | 522 | Some(Abi::ScalarPair(..)) => (), |
dfeec247 XL |
523 | abi => { |
524 | tcx.sess.delay_span_bug( | |
525 | tcx.def_span(method.def_id), | |
526 | &format!( | |
1b1a35ee | 527 | "receiver when `Self = {}` should have a ScalarPair ABI; found {:?}", |
dfeec247 XL |
528 | trait_object_ty, abi |
529 | ), | |
530 | ); | |
531 | } | |
532 | } | |
a7813a04 | 533 | } |
dfeec247 | 534 | } |
1a4d82fc | 535 | |
dfeec247 XL |
536 | None |
537 | } | |
abe05a73 | 538 | |
dfeec247 XL |
539 | /// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`. |
540 | /// For example, for `receiver_ty = Rc<Self>` and `self_ty = Foo`, returns `Rc<Foo>`. | |
541 | fn receiver_for_self_ty<'tcx>( | |
542 | tcx: TyCtxt<'tcx>, | |
543 | receiver_ty: Ty<'tcx>, | |
544 | self_ty: Ty<'tcx>, | |
545 | method_def_id: DefId, | |
546 | ) -> Ty<'tcx> { | |
547 | debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id); | |
548 | let substs = InternalSubsts::for_item(tcx, method_def_id, |param, _| { | |
549 | if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) } | |
550 | }); | |
551 | ||
04454e1e | 552 | let result = EarlyBinder(receiver_ty).subst(tcx, substs); |
dfeec247 XL |
553 | debug!( |
554 | "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}", | |
555 | receiver_ty, self_ty, method_def_id, result | |
556 | ); | |
557 | result | |
558 | } | |
1a4d82fc | 559 | |
dfeec247 XL |
560 | /// Creates the object type for the current trait. For example, |
561 | /// if the current trait is `Deref`, then this will be | |
562 | /// `dyn Deref<Target = Self::Target> + 'static`. | |
563 | fn object_ty_for_trait<'tcx>( | |
564 | tcx: TyCtxt<'tcx>, | |
565 | trait_def_id: DefId, | |
566 | lifetime: ty::Region<'tcx>, | |
567 | ) -> Ty<'tcx> { | |
568 | debug!("object_ty_for_trait: trait_def_id={:?}", trait_def_id); | |
1a4d82fc | 569 | |
dfeec247 | 570 | let trait_ref = ty::TraitRef::identity(tcx, trait_def_id); |
8faf50e0 | 571 | |
c295e0f8 XL |
572 | let trait_predicate = trait_ref.map_bound(|trait_ref| { |
573 | ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)) | |
574 | }); | |
a1dfa0c6 | 575 | |
c295e0f8 | 576 | let mut associated_types = traits::supertraits(tcx, trait_ref) |
dfeec247 | 577 | .flat_map(|super_trait_ref| { |
74b04a01 XL |
578 | tcx.associated_items(super_trait_ref.def_id()) |
579 | .in_definition_order() | |
580 | .map(move |item| (super_trait_ref, item)) | |
dfeec247 XL |
581 | }) |
582 | .filter(|(_, item)| item.kind == ty::AssocKind::Type) | |
583 | .collect::<Vec<_>>(); | |
a1dfa0c6 | 584 | |
dfeec247 XL |
585 | // existential predicates need to be in a specific order |
586 | associated_types.sort_by_cached_key(|(_, item)| tcx.def_path_hash(item.def_id)); | |
a1dfa0c6 | 587 | |
dfeec247 XL |
588 | let projection_predicates = associated_types.into_iter().map(|(super_trait_ref, item)| { |
589 | // We *can* get bound lifetimes here in cases like | |
590 | // `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`. | |
fc512014 XL |
591 | super_trait_ref.map_bound(|super_trait_ref| { |
592 | ty::ExistentialPredicate::Projection(ty::ExistentialProjection { | |
5099ac24 | 593 | term: tcx.mk_projection(item.def_id, super_trait_ref.substs).into(), |
fc512014 XL |
594 | item_def_id: item.def_id, |
595 | substs: super_trait_ref.substs, | |
596 | }) | |
dfeec247 XL |
597 | }) |
598 | }); | |
a1dfa0c6 | 599 | |
fc512014 XL |
600 | let existential_predicates = tcx |
601 | .mk_poly_existential_predicates(iter::once(trait_predicate).chain(projection_predicates)); | |
a1dfa0c6 | 602 | |
f2b60f7d | 603 | let object_ty = tcx.mk_dynamic(existential_predicates, lifetime, ty::Dyn); |
a7813a04 | 604 | |
dfeec247 | 605 | debug!("object_ty_for_trait: object_ty=`{}`", object_ty); |
a1dfa0c6 | 606 | |
dfeec247 XL |
607 | object_ty |
608 | } | |
a1dfa0c6 | 609 | |
dfeec247 XL |
610 | /// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a |
611 | /// trait object. We require that `DispatchableFromDyn` be implemented for the receiver type | |
612 | /// in the following way: | |
613 | /// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc<Self>`, | |
614 | /// - require the following bound: | |
615 | /// | |
04454e1e | 616 | /// ```ignore (not-rust) |
dfeec247 XL |
617 | /// Receiver[Self => T]: DispatchFromDyn<Receiver[Self => dyn Trait]> |
618 | /// ``` | |
619 | /// | |
620 | /// where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`" | |
621 | /// (substitution notation). | |
622 | /// | |
623 | /// Some examples of receiver types and their required obligation: | |
624 | /// - `&'a mut self` requires `&'a mut Self: DispatchFromDyn<&'a mut dyn Trait>`, | |
625 | /// - `self: Rc<Self>` requires `Rc<Self>: DispatchFromDyn<Rc<dyn Trait>>`, | |
626 | /// - `self: Pin<Box<Self>>` requires `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<dyn Trait>>>`. | |
627 | /// | |
628 | /// The only case where the receiver is not dispatchable, but is still a valid receiver | |
629 | /// type (just not object-safe), is when there is more than one level of pointer indirection. | |
630 | /// E.g., `self: &&Self`, `self: &Rc<Self>`, `self: Box<Box<Self>>`. In these cases, there | |
631 | /// is no way, or at least no inexpensive way, to coerce the receiver from the version where | |
632 | /// `Self = dyn Trait` to the version where `Self = T`, where `T` is the unknown erased type | |
633 | /// contained by the trait object, because the object that needs to be coerced is behind | |
634 | /// a pointer. | |
635 | /// | |
636 | /// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result | |
637 | /// in a new check that `Trait` is object safe, creating a cycle (until object_safe_for_dispatch | |
29967ef6 | 638 | /// is stabilized, see tracking issue <https://github.com/rust-lang/rust/issues/43561>). |
dfeec247 XL |
639 | /// Instead, we fudge a little by introducing a new type parameter `U` such that |
640 | /// `Self: Unsize<U>` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`. | |
641 | /// Written as a chalk-style query: | |
04454e1e FG |
642 | /// ```ignore (not-rust) |
643 | /// forall (U: Trait + ?Sized) { | |
644 | /// if (Self: Unsize<U>) { | |
645 | /// Receiver: DispatchFromDyn<Receiver[Self => U]> | |
dfeec247 | 646 | /// } |
04454e1e FG |
647 | /// } |
648 | /// ``` | |
dfeec247 XL |
649 | /// for `self: &'a mut Self`, this means `&'a mut Self: DispatchFromDyn<&'a mut U>` |
650 | /// for `self: Rc<Self>`, this means `Rc<Self>: DispatchFromDyn<Rc<U>>` | |
651 | /// for `self: Pin<Box<Self>>`, this means `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<U>>>` | |
652 | // | |
653 | // FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this | |
654 | // fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like | |
655 | // `self: Wrapper<Self>`. | |
656 | #[allow(dead_code)] | |
657 | fn receiver_is_dispatchable<'tcx>( | |
658 | tcx: TyCtxt<'tcx>, | |
659 | method: &ty::AssocItem, | |
660 | receiver_ty: Ty<'tcx>, | |
661 | ) -> bool { | |
662 | debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty); | |
663 | ||
664 | let traits = (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait()); | |
3c0e092e | 665 | let (Some(unsize_did), Some(dispatch_from_dyn_did)) = traits else { |
dfeec247 XL |
666 | debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits"); |
667 | return false; | |
668 | }; | |
669 | ||
670 | // the type `U` in the query | |
74b04a01 | 671 | // use a bogus type parameter to mimic a forall(U) query using u32::MAX for now. |
dfeec247 XL |
672 | // FIXME(mikeyhew) this is a total hack. Once object_safe_for_dispatch is stabilized, we can |
673 | // replace this with `dyn Trait` | |
674 | let unsized_self_ty: Ty<'tcx> = | |
ba9703b0 | 675 | tcx.mk_ty_param(u32::MAX, Symbol::intern("RustaceansAreAwesome")); |
dfeec247 XL |
676 | |
677 | // `Receiver[Self => U]` | |
678 | let unsized_receiver_ty = | |
679 | receiver_for_self_ty(tcx, receiver_ty, unsized_self_ty, method.def_id); | |
680 | ||
681 | // create a modified param env, with `Self: Unsize<U>` and `U: Trait` added to caller bounds | |
682 | // `U: ?Sized` is already implied here | |
683 | let param_env = { | |
f035d41b | 684 | let param_env = tcx.param_env(method.def_id); |
dfeec247 XL |
685 | |
686 | // Self: Unsize<U> | |
c295e0f8 | 687 | let unsize_predicate = ty::Binder::dummy(ty::TraitRef { |
dfeec247 XL |
688 | def_id: unsize_did, |
689 | substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]), | |
c295e0f8 | 690 | }) |
dfeec247 | 691 | .without_const() |
f9f354fc | 692 | .to_predicate(tcx); |
dfeec247 XL |
693 | |
694 | // U: Trait<Arg1, ..., ArgN> | |
695 | let trait_predicate = { | |
696 | let substs = | |
064997fb | 697 | InternalSubsts::for_item(tcx, method.trait_container(tcx).unwrap(), |param, _| { |
dfeec247 XL |
698 | if param.index == 0 { |
699 | unsized_self_ty.into() | |
700 | } else { | |
701 | tcx.mk_param_from_def(param) | |
702 | } | |
703 | }); | |
a1dfa0c6 | 704 | |
c295e0f8 XL |
705 | ty::Binder::dummy(ty::TraitRef { def_id: unsize_did, substs }) |
706 | .without_const() | |
707 | .to_predicate(tcx) | |
a1dfa0c6 XL |
708 | }; |
709 | ||
a2a8927a XL |
710 | let caller_bounds: Vec<Predicate<'tcx>> = |
711 | param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]).collect(); | |
a1dfa0c6 | 712 | |
a2a8927a XL |
713 | ty::ParamEnv::new( |
714 | tcx.intern_predicates(&caller_bounds), | |
715 | param_env.reveal(), | |
716 | param_env.constness(), | |
717 | ) | |
dfeec247 | 718 | }; |
a1dfa0c6 | 719 | |
dfeec247 XL |
720 | // Receiver: DispatchFromDyn<Receiver[Self => U]> |
721 | let obligation = { | |
c295e0f8 | 722 | let predicate = ty::Binder::dummy(ty::TraitRef { |
dfeec247 XL |
723 | def_id: dispatch_from_dyn_did, |
724 | substs: tcx.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]), | |
c295e0f8 | 725 | }) |
dfeec247 | 726 | .without_const() |
f9f354fc | 727 | .to_predicate(tcx); |
a1dfa0c6 | 728 | |
dfeec247 XL |
729 | Obligation::new(ObligationCause::dummy(), param_env, predicate) |
730 | }; | |
a1dfa0c6 | 731 | |
dfeec247 XL |
732 | tcx.infer_ctxt().enter(|ref infcx| { |
733 | // the receiver is dispatchable iff the obligation holds | |
734 | infcx.predicate_must_hold_modulo_regions(&obligation) | |
735 | }) | |
736 | } | |
a7813a04 | 737 | |
064997fb | 738 | fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>( |
dfeec247 XL |
739 | tcx: TyCtxt<'tcx>, |
740 | trait_def_id: DefId, | |
29967ef6 | 741 | value: T, |
dfeec247 XL |
742 | ) -> bool { |
743 | // This is somewhat subtle. In general, we want to forbid | |
744 | // references to `Self` in the argument and return types, | |
745 | // since the value of `Self` is erased. However, there is one | |
746 | // exception: it is ok to reference `Self` in order to access | |
747 | // an associated type of the current trait, since we retain | |
748 | // the value of those associated types in the object type | |
749 | // itself. | |
750 | // | |
751 | // ```rust | |
752 | // trait SuperTrait { | |
753 | // type X; | |
754 | // } | |
755 | // | |
756 | // trait Trait : SuperTrait { | |
757 | // type Y; | |
758 | // fn foo(&self, x: Self) // bad | |
759 | // fn foo(&self) -> Self // bad | |
760 | // fn foo(&self) -> Option<Self> // bad | |
761 | // fn foo(&self) -> Self::Y // OK, desugars to next example | |
762 | // fn foo(&self) -> <Self as Trait>::Y // OK | |
763 | // fn foo(&self) -> Self::X // OK, desugars to next example | |
764 | // fn foo(&self) -> <Self as SuperTrait>::X // OK | |
765 | // } | |
766 | // ``` | |
767 | // | |
768 | // However, it is not as simple as allowing `Self` in a projected | |
769 | // type, because there are illegal ways to use `Self` as well: | |
770 | // | |
771 | // ```rust | |
772 | // trait Trait : SuperTrait { | |
773 | // ... | |
774 | // fn foo(&self) -> <Self as SomeOtherTrait>::X; | |
775 | // } | |
776 | // ``` | |
777 | // | |
778 | // Here we will not have the type of `X` recorded in the | |
779 | // object type, and we cannot resolve `Self as SomeOtherTrait` | |
780 | // without knowing what `Self` is. | |
781 | ||
f9f354fc XL |
782 | struct IllegalSelfTypeVisitor<'tcx> { |
783 | tcx: TyCtxt<'tcx>, | |
f9f354fc | 784 | trait_def_id: DefId, |
cdc7bbd5 | 785 | supertraits: Option<Vec<DefId>>, |
f9f354fc | 786 | } |
a7813a04 | 787 | |
f9f354fc | 788 | impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> { |
fc512014 XL |
789 | type BreakTy = (); |
790 | ||
791 | fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { | |
1b1a35ee | 792 | match t.kind() { |
29967ef6 XL |
793 | ty::Param(_) => { |
794 | if t == self.tcx.types.self_param { | |
795 | ControlFlow::BREAK | |
796 | } else { | |
797 | ControlFlow::CONTINUE | |
798 | } | |
799 | } | |
f2b60f7d FG |
800 | ty::Projection(ref data) |
801 | if self.tcx.def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder => | |
802 | { | |
803 | // We'll deny these later in their own pass | |
804 | ControlFlow::CONTINUE | |
805 | } | |
f9f354fc XL |
806 | ty::Projection(ref data) => { |
807 | // This is a projected type `<Foo as SomeTrait>::X`. | |
808 | ||
809 | // Compute supertraits of current trait lazily. | |
810 | if self.supertraits.is_none() { | |
c295e0f8 | 811 | let trait_ref = ty::TraitRef::identity(self.tcx, self.trait_def_id); |
cdc7bbd5 XL |
812 | self.supertraits = Some( |
813 | traits::supertraits(self.tcx, trait_ref).map(|t| t.def_id()).collect(), | |
814 | ); | |
f9f354fc | 815 | } |
1a4d82fc | 816 | |
f9f354fc XL |
817 | // Determine whether the trait reference `Foo as |
818 | // SomeTrait` is in fact a supertrait of the | |
819 | // current trait. In that case, this type is | |
820 | // legal, because the type `X` will be specified | |
821 | // in the object type. Note that we can just use | |
822 | // direct equality here because all of these types | |
823 | // are part of the formal parameter listing, and | |
824 | // hence there should be no inference variables. | |
cdc7bbd5 XL |
825 | let is_supertrait_of_current_trait = self |
826 | .supertraits | |
827 | .as_ref() | |
828 | .unwrap() | |
829 | .contains(&data.trait_ref(self.tcx).def_id); | |
f9f354fc XL |
830 | |
831 | if is_supertrait_of_current_trait { | |
29967ef6 | 832 | ControlFlow::CONTINUE // do not walk contained types, do not report error, do collect $200 |
f9f354fc XL |
833 | } else { |
834 | t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error | |
835 | } | |
dfeec247 | 836 | } |
f9f354fc | 837 | _ => t.super_visit_with(self), // walk contained types, if any |
ba9703b0 | 838 | } |
dfeec247 | 839 | } |
dfeec247 | 840 | |
923072b8 | 841 | fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> { |
29967ef6 XL |
842 | // Constants can only influence object safety if they reference `Self`. |
843 | // This is only possible for unevaluated constants, so we walk these here. | |
844 | // | |
845 | // If `AbstractConst::new` returned an error we already failed compilation | |
846 | // so we don't have to emit an additional error here. | |
847 | // | |
848 | // We currently recurse into abstract consts here but do not recurse in | |
849 | // `is_const_evaluatable`. This means that the object safety check is more | |
850 | // liberal than the const eval check. | |
851 | // | |
852 | // This shouldn't really matter though as we can't really use any | |
853 | // constants which are not considered const evaluatable. | |
064997fb | 854 | use rustc_middle::ty::abstract_const::Node; |
94222f64 | 855 | if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv.shrink()) { |
064997fb FG |
856 | walk_abstract_const(self.tcx, ct, |node| match node.root(self.tcx) { |
857 | Node::Leaf(leaf) => self.visit_const(leaf), | |
858 | Node::Cast(_, _, ty) => self.visit_ty(ty), | |
859 | Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { | |
860 | ControlFlow::CONTINUE | |
29967ef6 XL |
861 | } |
862 | }) | |
863 | } else { | |
864 | ControlFlow::CONTINUE | |
865 | } | |
866 | } | |
ba9703b0 XL |
867 | } |
868 | ||
29967ef6 XL |
869 | value |
870 | .visit_with(&mut IllegalSelfTypeVisitor { tcx, trait_def_id, supertraits: None }) | |
871 | .is_break() | |
1a4d82fc | 872 | } |
7cac9316 | 873 | |
f2b60f7d FG |
874 | pub fn contains_illegal_impl_trait_in_trait<'tcx>( |
875 | tcx: TyCtxt<'tcx>, | |
876 | ty: ty::Binder<'tcx, Ty<'tcx>>, | |
877 | ) -> bool { | |
878 | // FIXME(RPITIT): Perhaps we should use a visitor here? | |
879 | ty.skip_binder().walk().any(|arg| { | |
880 | if let ty::GenericArgKind::Type(ty) = arg.unpack() | |
881 | && let ty::Projection(proj) = ty.kind() | |
882 | { | |
883 | tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder | |
884 | } else { | |
885 | false | |
886 | } | |
887 | }) | |
888 | } | |
889 | ||
f035d41b | 890 | pub fn provide(providers: &mut ty::query::Providers) { |
74b04a01 | 891 | *providers = ty::query::Providers { object_safety_violations, ..*providers }; |
7cac9316 | 892 | } |