]>
Commit | Line | Data |
---|---|---|
ba9703b0 XL |
1 | //! Trait Resolution. See the [rustc dev guide] for more information on how this works. |
2 | //! | |
3 | //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html | |
4 | ||
5 | #[allow(dead_code)] | |
6 | pub mod auto_trait; | |
f9f354fc | 7 | mod chalk_fulfill; |
ba9703b0 XL |
8 | pub mod codegen; |
9 | mod coherence; | |
10 | mod engine; | |
11 | pub mod error_reporting; | |
12 | mod fulfill; | |
13 | pub mod misc; | |
14 | mod object_safety; | |
15 | mod on_unimplemented; | |
16 | mod project; | |
17 | pub mod query; | |
18 | mod select; | |
19 | mod specialize; | |
20 | mod structural_match; | |
21 | mod util; | |
22 | pub mod wf; | |
23 | ||
24 | use crate::infer::outlives::env::OutlivesEnvironment; | |
25 | use crate::infer::{InferCtxt, RegionckMode, TyCtxtInferExt}; | |
26 | use crate::traits::error_reporting::InferCtxtExt as _; | |
27 | use crate::traits::query::evaluate_obligation::InferCtxtExt as _; | |
28 | use rustc_errors::ErrorReported; | |
29 | use rustc_hir as hir; | |
30 | use rustc_hir::def_id::DefId; | |
ba9703b0 XL |
31 | use rustc_middle::ty::fold::TypeFoldable; |
32 | use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; | |
f9f354fc XL |
33 | use rustc_middle::ty::{ |
34 | self, GenericParamDefKind, ParamEnv, ToPredicate, Ty, TyCtxt, WithConstness, | |
35 | }; | |
ba9703b0 XL |
36 | use rustc_span::Span; |
37 | ||
38 | use std::fmt::Debug; | |
39 | ||
40 | pub use self::FulfillmentErrorCode::*; | |
f035d41b | 41 | pub use self::ImplSource::*; |
ba9703b0 XL |
42 | pub use self::ObligationCauseCode::*; |
43 | pub use self::SelectionError::*; | |
ba9703b0 XL |
44 | |
45 | pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls}; | |
46 | pub use self::coherence::{OrphanCheckErr, OverlapResult}; | |
47 | pub use self::engine::TraitEngineExt; | |
48 | pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation}; | |
49 | pub use self::object_safety::astconv_object_safety_violations; | |
50 | pub use self::object_safety::is_vtable_safe_method; | |
51 | pub use self::object_safety::MethodViolationCode; | |
52 | pub use self::object_safety::ObjectSafetyViolation; | |
53 | pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote}; | |
f9652781 | 54 | pub use self::project::{normalize, normalize_projection_type, normalize_to}; |
ba9703b0 XL |
55 | pub use self::select::{EvaluationCache, SelectionCache, SelectionContext}; |
56 | pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError}; | |
57 | pub use self::specialize::specialization_graph::FutureCompatOverlapError; | |
58 | pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind; | |
59 | pub use self::specialize::{specialization_graph, translate_substs, OverlapError}; | |
60 | pub use self::structural_match::search_for_structural_match_violation; | |
ba9703b0 XL |
61 | pub use self::structural_match::NonStructuralMatchTy; |
62 | pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs}; | |
63 | pub use self::util::{expand_trait_aliases, TraitAliasExpander}; | |
64 | pub use self::util::{ | |
65 | get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices, | |
66 | }; | |
67 | pub use self::util::{ | |
68 | supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits, | |
69 | }; | |
70 | ||
f9f354fc XL |
71 | pub use self::chalk_fulfill::FulfillmentContext as ChalkFulfillmentContext; |
72 | ||
ba9703b0 XL |
73 | pub use rustc_infer::traits::*; |
74 | ||
75 | /// Whether to skip the leak check, as part of a future compatibility warning step. | |
76 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] | |
77 | pub enum SkipLeakCheck { | |
78 | Yes, | |
79 | No, | |
80 | } | |
81 | ||
82 | impl SkipLeakCheck { | |
83 | fn is_yes(self) -> bool { | |
84 | self == SkipLeakCheck::Yes | |
85 | } | |
86 | } | |
87 | ||
88 | /// The "default" for skip-leak-check corresponds to the current | |
89 | /// behavior (do not skip the leak check) -- not the behavior we are | |
90 | /// transitioning into. | |
91 | impl Default for SkipLeakCheck { | |
92 | fn default() -> Self { | |
93 | SkipLeakCheck::No | |
94 | } | |
95 | } | |
96 | ||
97 | /// The mode that trait queries run in. | |
98 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] | |
99 | pub enum TraitQueryMode { | |
100 | // Standard/un-canonicalized queries get accurate | |
101 | // spans etc. passed in and hence can do reasonable | |
102 | // error reporting on their own. | |
103 | Standard, | |
104 | // Canonicalized queries get dummy spans and hence | |
105 | // must generally propagate errors to | |
106 | // pre-canonicalization callsites. | |
107 | Canonical, | |
108 | } | |
109 | ||
110 | /// Creates predicate obligations from the generic bounds. | |
111 | pub fn predicates_for_generics<'tcx>( | |
112 | cause: ObligationCause<'tcx>, | |
113 | param_env: ty::ParamEnv<'tcx>, | |
114 | generic_bounds: ty::InstantiatedPredicates<'tcx>, | |
115 | ) -> impl Iterator<Item = PredicateObligation<'tcx>> { | |
116 | util::predicates_for_generics(cause, 0, param_env, generic_bounds) | |
117 | } | |
118 | ||
119 | /// Determines whether the type `ty` is known to meet `bound` and | |
120 | /// returns true if so. Returns false if `ty` either does not meet | |
121 | /// `bound` or is not known to meet bound (note that this is | |
122 | /// conservative towards *no impl*, which is the opposite of the | |
123 | /// `evaluate` methods). | |
124 | pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>( | |
125 | infcx: &InferCtxt<'a, 'tcx>, | |
126 | param_env: ty::ParamEnv<'tcx>, | |
127 | ty: Ty<'tcx>, | |
128 | def_id: DefId, | |
129 | span: Span, | |
130 | ) -> bool { | |
131 | debug!( | |
132 | "type_known_to_meet_bound_modulo_regions(ty={:?}, bound={:?})", | |
133 | ty, | |
134 | infcx.tcx.def_path_str(def_id) | |
135 | ); | |
136 | ||
137 | let trait_ref = ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) }; | |
138 | let obligation = Obligation { | |
139 | param_env, | |
140 | cause: ObligationCause::misc(span, hir::CRATE_HIR_ID), | |
141 | recursion_depth: 0, | |
f9f354fc | 142 | predicate: trait_ref.without_const().to_predicate(infcx.tcx), |
ba9703b0 XL |
143 | }; |
144 | ||
145 | let result = infcx.predicate_must_hold_modulo_regions(&obligation); | |
146 | debug!( | |
147 | "type_known_to_meet_ty={:?} bound={} => {:?}", | |
148 | ty, | |
149 | infcx.tcx.def_path_str(def_id), | |
150 | result | |
151 | ); | |
152 | ||
153 | if result && ty.has_infer_types_or_consts() { | |
154 | // Because of inference "guessing", selection can sometimes claim | |
155 | // to succeed while the success requires a guess. To ensure | |
156 | // this function's result remains infallible, we must confirm | |
157 | // that guess. While imperfect, I believe this is sound. | |
158 | ||
159 | // The handling of regions in this area of the code is terrible, | |
160 | // see issue #29149. We should be able to improve on this with | |
161 | // NLL. | |
162 | let mut fulfill_cx = FulfillmentContext::new_ignoring_regions(); | |
163 | ||
164 | // We can use a dummy node-id here because we won't pay any mind | |
165 | // to region obligations that arise (there shouldn't really be any | |
166 | // anyhow). | |
167 | let cause = ObligationCause::misc(span, hir::CRATE_HIR_ID); | |
168 | ||
169 | fulfill_cx.register_bound(infcx, param_env, ty, def_id, cause); | |
170 | ||
171 | // Note: we only assume something is `Copy` if we can | |
172 | // *definitively* show that it implements `Copy`. Otherwise, | |
173 | // assume it is move; linear is always ok. | |
174 | match fulfill_cx.select_all_or_error(infcx) { | |
175 | Ok(()) => { | |
176 | debug!( | |
177 | "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success", | |
178 | ty, | |
179 | infcx.tcx.def_path_str(def_id) | |
180 | ); | |
181 | true | |
182 | } | |
183 | Err(e) => { | |
184 | debug!( | |
185 | "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} errors={:?}", | |
186 | ty, | |
187 | infcx.tcx.def_path_str(def_id), | |
188 | e | |
189 | ); | |
190 | false | |
191 | } | |
192 | } | |
193 | } else { | |
194 | result | |
195 | } | |
196 | } | |
197 | ||
198 | fn do_normalize_predicates<'tcx>( | |
199 | tcx: TyCtxt<'tcx>, | |
200 | region_context: DefId, | |
201 | cause: ObligationCause<'tcx>, | |
202 | elaborated_env: ty::ParamEnv<'tcx>, | |
203 | predicates: Vec<ty::Predicate<'tcx>>, | |
204 | ) -> Result<Vec<ty::Predicate<'tcx>>, ErrorReported> { | |
205 | debug!( | |
206 | "do_normalize_predicates(predicates={:?}, region_context={:?}, cause={:?})", | |
207 | predicates, region_context, cause, | |
208 | ); | |
209 | let span = cause.span; | |
210 | tcx.infer_ctxt().enter(|infcx| { | |
211 | // FIXME. We should really... do something with these region | |
212 | // obligations. But this call just continues the older | |
213 | // behavior (i.e., doesn't cause any new bugs), and it would | |
214 | // take some further refactoring to actually solve them. In | |
215 | // particular, we would have to handle implied bounds | |
216 | // properly, and that code is currently largely confined to | |
217 | // regionck (though I made some efforts to extract it | |
218 | // out). -nmatsakis | |
219 | // | |
220 | // @arielby: In any case, these obligations are checked | |
221 | // by wfcheck anyway, so I'm not sure we have to check | |
222 | // them here too, and we will remove this function when | |
223 | // we move over to lazy normalization *anyway*. | |
224 | let fulfill_cx = FulfillmentContext::new_ignoring_regions(); | |
225 | let predicates = | |
226 | match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, &predicates) { | |
227 | Ok(predicates) => predicates, | |
228 | Err(errors) => { | |
229 | infcx.report_fulfillment_errors(&errors, None, false); | |
230 | return Err(ErrorReported); | |
231 | } | |
232 | }; | |
233 | ||
234 | debug!("do_normalize_predictes: normalized predicates = {:?}", predicates); | |
235 | ||
ba9703b0 XL |
236 | // We can use the `elaborated_env` here; the region code only |
237 | // cares about declarations like `'a: 'b`. | |
238 | let outlives_env = OutlivesEnvironment::new(elaborated_env); | |
239 | ||
240 | infcx.resolve_regions_and_report_errors( | |
241 | region_context, | |
ba9703b0 XL |
242 | &outlives_env, |
243 | RegionckMode::default(), | |
244 | ); | |
245 | ||
246 | let predicates = match infcx.fully_resolve(&predicates) { | |
247 | Ok(predicates) => predicates, | |
248 | Err(fixup_err) => { | |
249 | // If we encounter a fixup error, it means that some type | |
250 | // variable wound up unconstrained. I actually don't know | |
251 | // if this can happen, and I certainly don't expect it to | |
252 | // happen often, but if it did happen it probably | |
253 | // represents a legitimate failure due to some kind of | |
254 | // unconstrained variable, and it seems better not to ICE, | |
255 | // all things considered. | |
256 | tcx.sess.span_err(span, &fixup_err.to_string()); | |
257 | return Err(ErrorReported); | |
258 | } | |
259 | }; | |
260 | if predicates.needs_infer() { | |
261 | tcx.sess.delay_span_bug(span, "encountered inference variables after `fully_resolve`"); | |
262 | Err(ErrorReported) | |
263 | } else { | |
264 | Ok(predicates) | |
265 | } | |
266 | }) | |
267 | } | |
268 | ||
269 | // FIXME: this is gonna need to be removed ... | |
270 | /// Normalizes the parameter environment, reporting errors if they occur. | |
271 | pub fn normalize_param_env_or_error<'tcx>( | |
272 | tcx: TyCtxt<'tcx>, | |
273 | region_context: DefId, | |
274 | unnormalized_env: ty::ParamEnv<'tcx>, | |
275 | cause: ObligationCause<'tcx>, | |
276 | ) -> ty::ParamEnv<'tcx> { | |
277 | // I'm not wild about reporting errors here; I'd prefer to | |
278 | // have the errors get reported at a defined place (e.g., | |
279 | // during typeck). Instead I have all parameter | |
280 | // environments, in effect, going through this function | |
281 | // and hence potentially reporting errors. This ensures of | |
282 | // course that we never forget to normalize (the | |
283 | // alternative seemed like it would involve a lot of | |
284 | // manual invocations of this fn -- and then we'd have to | |
285 | // deal with the errors at each of those sites). | |
286 | // | |
287 | // In any case, in practice, typeck constructs all the | |
288 | // parameter environments once for every fn as it goes, | |
289 | // and errors will get reported then; so after typeck we | |
290 | // can be sure that no errors should occur. | |
291 | ||
292 | debug!( | |
293 | "normalize_param_env_or_error(region_context={:?}, unnormalized_env={:?}, cause={:?})", | |
294 | region_context, unnormalized_env, cause | |
295 | ); | |
296 | ||
297 | let mut predicates: Vec<_> = | |
f035d41b | 298 | util::elaborate_predicates(tcx, unnormalized_env.caller_bounds().into_iter()) |
ba9703b0 XL |
299 | .map(|obligation| obligation.predicate) |
300 | .collect(); | |
301 | ||
302 | debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); | |
303 | ||
304 | let elaborated_env = ty::ParamEnv::new( | |
305 | tcx.intern_predicates(&predicates), | |
f035d41b | 306 | unnormalized_env.reveal(), |
ba9703b0 XL |
307 | unnormalized_env.def_id, |
308 | ); | |
309 | ||
310 | // HACK: we are trying to normalize the param-env inside *itself*. The problem is that | |
311 | // normalization expects its param-env to be already normalized, which means we have | |
312 | // a circularity. | |
313 | // | |
314 | // The way we handle this is by normalizing the param-env inside an unnormalized version | |
315 | // of the param-env, which means that if the param-env contains unnormalized projections, | |
316 | // we'll have some normalization failures. This is unfortunate. | |
317 | // | |
318 | // Lazy normalization would basically handle this by treating just the | |
319 | // normalizing-a-trait-ref-requires-itself cycles as evaluation failures. | |
320 | // | |
321 | // Inferred outlives bounds can create a lot of `TypeOutlives` predicates for associated | |
322 | // types, so to make the situation less bad, we normalize all the predicates *but* | |
323 | // the `TypeOutlives` predicates first inside the unnormalized parameter environment, and | |
324 | // then we normalize the `TypeOutlives` bounds inside the normalized parameter environment. | |
325 | // | |
326 | // This works fairly well because trait matching does not actually care about param-env | |
327 | // TypeOutlives predicates - these are normally used by regionck. | |
328 | let outlives_predicates: Vec<_> = predicates | |
3dfed10e XL |
329 | .drain_filter(|predicate| match predicate.skip_binders() { |
330 | ty::PredicateAtom::TypeOutlives(..) => true, | |
ba9703b0 XL |
331 | _ => false, |
332 | }) | |
333 | .collect(); | |
334 | ||
335 | debug!( | |
336 | "normalize_param_env_or_error: predicates=(non-outlives={:?}, outlives={:?})", | |
337 | predicates, outlives_predicates | |
338 | ); | |
339 | let non_outlives_predicates = match do_normalize_predicates( | |
340 | tcx, | |
341 | region_context, | |
342 | cause.clone(), | |
343 | elaborated_env, | |
344 | predicates, | |
345 | ) { | |
346 | Ok(predicates) => predicates, | |
347 | // An unnormalized env is better than nothing. | |
348 | Err(ErrorReported) => { | |
349 | debug!("normalize_param_env_or_error: errored resolving non-outlives predicates"); | |
350 | return elaborated_env; | |
351 | } | |
352 | }; | |
353 | ||
354 | debug!("normalize_param_env_or_error: non-outlives predicates={:?}", non_outlives_predicates); | |
355 | ||
356 | // Not sure whether it is better to include the unnormalized TypeOutlives predicates | |
357 | // here. I believe they should not matter, because we are ignoring TypeOutlives param-env | |
358 | // predicates here anyway. Keeping them here anyway because it seems safer. | |
359 | let outlives_env: Vec<_> = | |
360 | non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect(); | |
361 | let outlives_env = | |
f035d41b | 362 | ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal(), None); |
ba9703b0 XL |
363 | let outlives_predicates = match do_normalize_predicates( |
364 | tcx, | |
365 | region_context, | |
366 | cause, | |
367 | outlives_env, | |
368 | outlives_predicates, | |
369 | ) { | |
370 | Ok(predicates) => predicates, | |
371 | // An unnormalized env is better than nothing. | |
372 | Err(ErrorReported) => { | |
373 | debug!("normalize_param_env_or_error: errored resolving outlives predicates"); | |
374 | return elaborated_env; | |
375 | } | |
376 | }; | |
377 | debug!("normalize_param_env_or_error: outlives predicates={:?}", outlives_predicates); | |
378 | ||
379 | let mut predicates = non_outlives_predicates; | |
380 | predicates.extend(outlives_predicates); | |
381 | debug!("normalize_param_env_or_error: final predicates={:?}", predicates); | |
382 | ty::ParamEnv::new( | |
383 | tcx.intern_predicates(&predicates), | |
f035d41b | 384 | unnormalized_env.reveal(), |
ba9703b0 XL |
385 | unnormalized_env.def_id, |
386 | ) | |
387 | } | |
388 | ||
389 | pub fn fully_normalize<'a, 'tcx, T>( | |
390 | infcx: &InferCtxt<'a, 'tcx>, | |
391 | mut fulfill_cx: FulfillmentContext<'tcx>, | |
392 | cause: ObligationCause<'tcx>, | |
393 | param_env: ty::ParamEnv<'tcx>, | |
394 | value: &T, | |
395 | ) -> Result<T, Vec<FulfillmentError<'tcx>>> | |
396 | where | |
397 | T: TypeFoldable<'tcx>, | |
398 | { | |
399 | debug!("fully_normalize_with_fulfillcx(value={:?})", value); | |
400 | let selcx = &mut SelectionContext::new(infcx); | |
401 | let Normalized { value: normalized_value, obligations } = | |
402 | project::normalize(selcx, param_env, cause, value); | |
403 | debug!( | |
404 | "fully_normalize: normalized_value={:?} obligations={:?}", | |
405 | normalized_value, obligations | |
406 | ); | |
407 | for obligation in obligations { | |
408 | fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation); | |
409 | } | |
410 | ||
411 | debug!("fully_normalize: select_all_or_error start"); | |
412 | fulfill_cx.select_all_or_error(infcx)?; | |
413 | debug!("fully_normalize: select_all_or_error complete"); | |
414 | let resolved_value = infcx.resolve_vars_if_possible(&normalized_value); | |
415 | debug!("fully_normalize: resolved_value={:?}", resolved_value); | |
416 | Ok(resolved_value) | |
417 | } | |
418 | ||
3dfed10e XL |
419 | /// Normalizes the predicates and checks whether they hold in an empty environment. If this |
420 | /// returns true, then either normalize encountered an error or one of the predicates did not | |
421 | /// hold. Used when creating vtables to check for unsatisfiable methods. | |
422 | pub fn impossible_predicates<'tcx>( | |
ba9703b0 XL |
423 | tcx: TyCtxt<'tcx>, |
424 | predicates: Vec<ty::Predicate<'tcx>>, | |
425 | ) -> bool { | |
3dfed10e | 426 | debug!("impossible_predicates(predicates={:?})", predicates); |
ba9703b0 XL |
427 | |
428 | let result = tcx.infer_ctxt().enter(|infcx| { | |
429 | let param_env = ty::ParamEnv::reveal_all(); | |
430 | let mut selcx = SelectionContext::new(&infcx); | |
431 | let mut fulfill_cx = FulfillmentContext::new(); | |
432 | let cause = ObligationCause::dummy(); | |
433 | let Normalized { value: predicates, obligations } = | |
434 | normalize(&mut selcx, param_env, cause.clone(), &predicates); | |
435 | for obligation in obligations { | |
436 | fulfill_cx.register_predicate_obligation(&infcx, obligation); | |
437 | } | |
438 | for predicate in predicates { | |
439 | let obligation = Obligation::new(cause.clone(), param_env, predicate); | |
440 | fulfill_cx.register_predicate_obligation(&infcx, obligation); | |
441 | } | |
442 | ||
3dfed10e | 443 | fulfill_cx.select_all_or_error(&infcx).is_err() |
ba9703b0 | 444 | }); |
3dfed10e | 445 | debug!("impossible_predicates(predicates={:?}) = {:?}", predicates, result); |
ba9703b0 XL |
446 | result |
447 | } | |
448 | ||
3dfed10e | 449 | fn subst_and_check_impossible_predicates<'tcx>( |
ba9703b0 XL |
450 | tcx: TyCtxt<'tcx>, |
451 | key: (DefId, SubstsRef<'tcx>), | |
452 | ) -> bool { | |
3dfed10e | 453 | debug!("subst_and_check_impossible_predicates(key={:?})", key); |
ba9703b0 | 454 | |
3dfed10e XL |
455 | let mut predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates; |
456 | predicates.retain(|predicate| !predicate.needs_subst()); | |
457 | let result = impossible_predicates(tcx, predicates); | |
ba9703b0 | 458 | |
3dfed10e | 459 | debug!("subst_and_check_impossible_predicates(key={:?}) = {:?}", key, result); |
ba9703b0 XL |
460 | result |
461 | } | |
462 | ||
463 | /// Given a trait `trait_ref`, iterates the vtable entries | |
464 | /// that come from `trait_ref`, including its supertraits. | |
465 | #[inline] // FIXME(#35870): avoid closures being unexported due to `impl Trait`. | |
466 | fn vtable_methods<'tcx>( | |
467 | tcx: TyCtxt<'tcx>, | |
468 | trait_ref: ty::PolyTraitRef<'tcx>, | |
469 | ) -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] { | |
470 | debug!("vtable_methods({:?})", trait_ref); | |
471 | ||
472 | tcx.arena.alloc_from_iter(supertraits(tcx, trait_ref).flat_map(move |trait_ref| { | |
473 | let trait_methods = tcx | |
474 | .associated_items(trait_ref.def_id()) | |
475 | .in_definition_order() | |
476 | .filter(|item| item.kind == ty::AssocKind::Fn); | |
477 | ||
478 | // Now list each method's DefId and InternalSubsts (for within its trait). | |
479 | // If the method can never be called from this object, produce None. | |
480 | trait_methods.map(move |trait_method| { | |
481 | debug!("vtable_methods: trait_method={:?}", trait_method); | |
482 | let def_id = trait_method.def_id; | |
483 | ||
484 | // Some methods cannot be called on an object; skip those. | |
485 | if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) { | |
486 | debug!("vtable_methods: not vtable safe"); | |
487 | return None; | |
488 | } | |
489 | ||
490 | // The method may have some early-bound lifetimes; add regions for those. | |
491 | let substs = trait_ref.map_bound(|trait_ref| { | |
492 | InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind { | |
493 | GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), | |
494 | GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => { | |
495 | trait_ref.substs[param.index as usize] | |
496 | } | |
497 | }) | |
498 | }); | |
499 | ||
500 | // The trait type may have higher-ranked lifetimes in it; | |
501 | // erase them if they appear, so that we get the type | |
502 | // at some particular call site. | |
503 | let substs = | |
504 | tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &substs); | |
505 | ||
506 | // It's possible that the method relies on where-clauses that | |
507 | // do not hold for this particular set of type parameters. | |
508 | // Note that this method could then never be called, so we | |
509 | // do not want to try and codegen it, in that case (see #23435). | |
510 | let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs); | |
3dfed10e | 511 | if impossible_predicates(tcx, predicates.predicates) { |
ba9703b0 XL |
512 | debug!("vtable_methods: predicates do not hold"); |
513 | return None; | |
514 | } | |
515 | ||
516 | Some((def_id, substs)) | |
517 | }) | |
518 | })) | |
519 | } | |
520 | ||
f9f354fc XL |
521 | /// Check whether a `ty` implements given trait(trait_def_id). |
522 | /// | |
523 | /// NOTE: Always return `false` for a type which needs inference. | |
524 | fn type_implements_trait<'tcx>( | |
525 | tcx: TyCtxt<'tcx>, | |
526 | key: ( | |
527 | DefId, // trait_def_id, | |
528 | Ty<'tcx>, // type | |
529 | SubstsRef<'tcx>, | |
530 | ParamEnv<'tcx>, | |
531 | ), | |
532 | ) -> bool { | |
533 | let (trait_def_id, ty, params, param_env) = key; | |
534 | ||
535 | debug!( | |
536 | "type_implements_trait: trait_def_id={:?}, type={:?}, params={:?}, param_env={:?}", | |
537 | trait_def_id, ty, params, param_env | |
538 | ); | |
539 | ||
540 | let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, params) }; | |
541 | ||
542 | let obligation = Obligation { | |
543 | cause: ObligationCause::dummy(), | |
544 | param_env, | |
545 | recursion_depth: 0, | |
546 | predicate: trait_ref.without_const().to_predicate(tcx), | |
547 | }; | |
548 | tcx.infer_ctxt().enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation)) | |
549 | } | |
550 | ||
f035d41b | 551 | pub fn provide(providers: &mut ty::query::Providers) { |
ba9703b0 | 552 | object_safety::provide(providers); |
f035d41b | 553 | structural_match::provide(providers); |
ba9703b0 XL |
554 | *providers = ty::query::Providers { |
555 | specialization_graph_of: specialize::specialization_graph_provider, | |
556 | specializes: specialize::specializes, | |
557 | codegen_fulfill_obligation: codegen::codegen_fulfill_obligation, | |
558 | vtable_methods, | |
f9f354fc | 559 | type_implements_trait, |
3dfed10e | 560 | subst_and_check_impossible_predicates, |
ba9703b0 XL |
561 | ..*providers |
562 | }; | |
563 | } |