]>
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 | ||
ba9703b0 | 5 | pub mod auto_trait; |
f9f354fc | 6 | mod chalk_fulfill; |
ba9703b0 | 7 | mod coherence; |
5869c6ff | 8 | pub mod const_evaluatable; |
ba9703b0 XL |
9 | mod engine; |
10 | pub mod error_reporting; | |
11 | mod fulfill; | |
12 | pub mod misc; | |
13 | mod object_safety; | |
f2b60f7d | 14 | pub mod outlives_bounds; |
ba9703b0 XL |
15 | mod project; |
16 | pub mod query; | |
17 | mod select; | |
18 | mod specialize; | |
19 | mod structural_match; | |
20 | mod util; | |
487cf647 | 21 | mod vtable; |
ba9703b0 XL |
22 | pub mod wf; |
23 | ||
24 | use crate::infer::outlives::env::OutlivesEnvironment; | |
923072b8 | 25 | use crate::infer::{InferCtxt, TyCtxtInferExt}; |
2b03887a | 26 | use crate::traits::error_reporting::TypeErrCtxtExt as _; |
ba9703b0 | 27 | use crate::traits::query::evaluate_obligation::InferCtxtExt as _; |
5e7ed085 | 28 | use rustc_errors::ErrorGuaranteed; |
ba9703b0 | 29 | use rustc_middle::ty::fold::TypeFoldable; |
9ffffee4 | 30 | use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; |
487cf647 | 31 | use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeSuperVisitable}; |
2b03887a | 32 | use rustc_middle::ty::{InternalSubsts, SubstsRef}; |
9ffffee4 | 33 | use rustc_span::def_id::{DefId, CRATE_DEF_ID}; |
487cf647 | 34 | use rustc_span::Span; |
ba9703b0 XL |
35 | |
36 | use std::fmt::Debug; | |
94222f64 | 37 | use std::ops::ControlFlow; |
ba9703b0 XL |
38 | |
39 | pub use self::FulfillmentErrorCode::*; | |
f035d41b | 40 | pub use self::ImplSource::*; |
ba9703b0 XL |
41 | pub use self::ObligationCauseCode::*; |
42 | pub use self::SelectionError::*; | |
ba9703b0 XL |
43 | |
44 | pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls}; | |
45 | pub use self::coherence::{OrphanCheckErr, OverlapResult}; | |
064997fb | 46 | pub use self::engine::{ObligationCtxt, TraitEngineExt}; |
ba9703b0 XL |
47 | pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation}; |
48 | pub use self::object_safety::astconv_object_safety_violations; | |
49 | pub use self::object_safety::is_vtable_safe_method; | |
50 | pub use self::object_safety::MethodViolationCode; | |
51 | pub use self::object_safety::ObjectSafetyViolation; | |
487cf647 | 52 | pub use self::project::{normalize_projection_type, NormalizeExt}; |
ba9703b0 XL |
53 | pub use self::select::{EvaluationCache, SelectionCache, SelectionContext}; |
54 | pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError}; | |
55 | pub use self::specialize::specialization_graph::FutureCompatOverlapError; | |
56 | pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind; | |
57 | pub use self::specialize::{specialization_graph, translate_substs, OverlapError}; | |
064997fb FG |
58 | pub use self::structural_match::{ |
59 | search_for_adt_const_param_violation, search_for_structural_match_violation, | |
60 | }; | |
c295e0f8 | 61 | pub use self::util::{ |
3c0e092e XL |
62 | elaborate_obligations, elaborate_predicates, elaborate_predicates_with_span, |
63 | elaborate_trait_ref, elaborate_trait_refs, | |
c295e0f8 | 64 | }; |
ba9703b0 XL |
65 | pub use self::util::{expand_trait_aliases, TraitAliasExpander}; |
66 | pub use self::util::{ | |
67 | get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices, | |
68 | }; | |
69 | pub use self::util::{ | |
6a06907d XL |
70 | supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_type, |
71 | SupertraitDefIds, Supertraits, | |
ba9703b0 XL |
72 | }; |
73 | ||
f9f354fc XL |
74 | pub use self::chalk_fulfill::FulfillmentContext as ChalkFulfillmentContext; |
75 | ||
ba9703b0 XL |
76 | pub use rustc_infer::traits::*; |
77 | ||
78 | /// Whether to skip the leak check, as part of a future compatibility warning step. | |
3c0e092e XL |
79 | /// |
80 | /// The "default" for skip-leak-check corresponds to the current | |
81 | /// behavior (do not skip the leak check) -- not the behavior we are | |
82 | /// transitioning into. | |
83 | #[derive(Copy, Clone, PartialEq, Eq, Debug, Default)] | |
ba9703b0 XL |
84 | pub enum SkipLeakCheck { |
85 | Yes, | |
3c0e092e | 86 | #[default] |
ba9703b0 XL |
87 | No, |
88 | } | |
89 | ||
90 | impl SkipLeakCheck { | |
91 | fn is_yes(self) -> bool { | |
92 | self == SkipLeakCheck::Yes | |
93 | } | |
94 | } | |
95 | ||
ba9703b0 XL |
96 | /// The mode that trait queries run in. |
97 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] | |
98 | pub enum TraitQueryMode { | |
fc512014 XL |
99 | /// Standard/un-canonicalized queries get accurate |
100 | /// spans etc. passed in and hence can do reasonable | |
101 | /// error reporting on their own. | |
ba9703b0 | 102 | Standard, |
9c376795 | 103 | /// Canonical queries get dummy spans and hence |
fc512014 XL |
104 | /// must generally propagate errors to |
105 | /// pre-canonicalization callsites. | |
ba9703b0 XL |
106 | Canonical, |
107 | } | |
108 | ||
109 | /// Creates predicate obligations from the generic bounds. | |
487cf647 | 110 | #[instrument(level = "debug", skip(cause, param_env))] |
ba9703b0 | 111 | pub fn predicates_for_generics<'tcx>( |
f2b60f7d | 112 | cause: impl Fn(usize, Span) -> ObligationCause<'tcx>, |
ba9703b0 XL |
113 | param_env: ty::ParamEnv<'tcx>, |
114 | generic_bounds: ty::InstantiatedPredicates<'tcx>, | |
115 | ) -> impl Iterator<Item = PredicateObligation<'tcx>> { | |
9c376795 FG |
116 | generic_bounds.into_iter().enumerate().map(move |(idx, (predicate, span))| Obligation { |
117 | cause: cause(idx, span), | |
118 | recursion_depth: 0, | |
119 | param_env, | |
120 | predicate, | |
121 | }) | |
ba9703b0 XL |
122 | } |
123 | ||
124 | /// Determines whether the type `ty` is known to meet `bound` and | |
125 | /// returns true if so. Returns false if `ty` either does not meet | |
126 | /// `bound` or is not known to meet bound (note that this is | |
127 | /// conservative towards *no impl*, which is the opposite of the | |
128 | /// `evaluate` methods). | |
2b03887a FG |
129 | pub fn type_known_to_meet_bound_modulo_regions<'tcx>( |
130 | infcx: &InferCtxt<'tcx>, | |
ba9703b0 XL |
131 | param_env: ty::ParamEnv<'tcx>, |
132 | ty: Ty<'tcx>, | |
133 | def_id: DefId, | |
134 | span: Span, | |
135 | ) -> bool { | |
487cf647 FG |
136 | let trait_ref = ty::Binder::dummy(infcx.tcx.mk_trait_ref(def_id, [ty])); |
137 | pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref.without_const(), span) | |
138 | } | |
ba9703b0 | 139 | |
487cf647 FG |
140 | #[instrument(level = "debug", skip(infcx, param_env, span, pred), ret)] |
141 | fn pred_known_to_hold_modulo_regions<'tcx>( | |
142 | infcx: &InferCtxt<'tcx>, | |
143 | param_env: ty::ParamEnv<'tcx>, | |
9ffffee4 | 144 | pred: impl ToPredicate<'tcx> + TypeVisitable<TyCtxt<'tcx>>, |
487cf647 FG |
145 | span: Span, |
146 | ) -> bool { | |
147 | let has_non_region_infer = pred.has_non_region_infer(); | |
ba9703b0 XL |
148 | let obligation = Obligation { |
149 | param_env, | |
487cf647 FG |
150 | // We can use a dummy node-id here because we won't pay any mind |
151 | // to region obligations that arise (there shouldn't really be any | |
152 | // anyhow). | |
9ffffee4 | 153 | cause: ObligationCause::misc(span, CRATE_DEF_ID), |
ba9703b0 | 154 | recursion_depth: 0, |
487cf647 | 155 | predicate: pred.to_predicate(infcx.tcx), |
ba9703b0 XL |
156 | }; |
157 | ||
9ffffee4 | 158 | let result = infcx.evaluate_obligation_no_overflow(&obligation); |
487cf647 | 159 | debug!(?result); |
ba9703b0 | 160 | |
9ffffee4 FG |
161 | if result.must_apply_modulo_regions() && !has_non_region_infer { |
162 | true | |
163 | } else if result.may_apply() { | |
ba9703b0 XL |
164 | // Because of inference "guessing", selection can sometimes claim |
165 | // to succeed while the success requires a guess. To ensure | |
166 | // this function's result remains infallible, we must confirm | |
167 | // that guess. While imperfect, I believe this is sound. | |
168 | ||
487cf647 | 169 | // FIXME(@lcnr): this function doesn't seem right. |
9ffffee4 | 170 | // |
f2b60f7d FG |
171 | // The handling of regions in this area of the code is terrible, |
172 | // see issue #29149. We should be able to improve on this with | |
173 | // NLL. | |
487cf647 | 174 | let errors = fully_solve_obligation(infcx, obligation); |
ba9703b0 | 175 | |
f2b60f7d | 176 | match &errors[..] { |
487cf647 | 177 | [] => true, |
3c0e092e | 178 | errors => { |
487cf647 | 179 | debug!(?errors); |
ba9703b0 XL |
180 | false |
181 | } | |
182 | } | |
183 | } else { | |
9ffffee4 | 184 | false |
ba9703b0 XL |
185 | } |
186 | } | |
187 | ||
064997fb | 188 | #[instrument(level = "debug", skip(tcx, elaborated_env))] |
ba9703b0 XL |
189 | fn do_normalize_predicates<'tcx>( |
190 | tcx: TyCtxt<'tcx>, | |
ba9703b0 XL |
191 | cause: ObligationCause<'tcx>, |
192 | elaborated_env: ty::ParamEnv<'tcx>, | |
193 | predicates: Vec<ty::Predicate<'tcx>>, | |
5e7ed085 | 194 | ) -> Result<Vec<ty::Predicate<'tcx>>, ErrorGuaranteed> { |
ba9703b0 | 195 | let span = cause.span; |
064997fb FG |
196 | // FIXME. We should really... do something with these region |
197 | // obligations. But this call just continues the older | |
198 | // behavior (i.e., doesn't cause any new bugs), and it would | |
199 | // take some further refactoring to actually solve them. In | |
200 | // particular, we would have to handle implied bounds | |
201 | // properly, and that code is currently largely confined to | |
202 | // regionck (though I made some efforts to extract it | |
203 | // out). -nmatsakis | |
204 | // | |
205 | // @arielby: In any case, these obligations are checked | |
206 | // by wfcheck anyway, so I'm not sure we have to check | |
207 | // them here too, and we will remove this function when | |
208 | // we move over to lazy normalization *anyway*. | |
2b03887a FG |
209 | let infcx = tcx.infer_ctxt().ignoring_regions().build(); |
210 | let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) { | |
211 | Ok(predicates) => predicates, | |
212 | Err(errors) => { | |
487cf647 | 213 | let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None); |
2b03887a FG |
214 | return Err(reported); |
215 | } | |
216 | }; | |
ba9703b0 | 217 | |
2b03887a | 218 | debug!("do_normalize_predictes: normalized predicates = {:?}", predicates); |
ba9703b0 | 219 | |
2b03887a FG |
220 | // We can use the `elaborated_env` here; the region code only |
221 | // cares about declarations like `'a: 'b`. | |
222 | let outlives_env = OutlivesEnvironment::new(elaborated_env); | |
223 | ||
224 | // FIXME: It's very weird that we ignore region obligations but apparently | |
225 | // still need to use `resolve_regions` as we need the resolved regions in | |
226 | // the normalized predicates. | |
227 | let errors = infcx.resolve_regions(&outlives_env); | |
228 | if !errors.is_empty() { | |
229 | tcx.sess.delay_span_bug( | |
230 | span, | |
231 | format!("failed region resolution while normalizing {elaborated_env:?}: {errors:?}"), | |
232 | ); | |
233 | } | |
ba9703b0 | 234 | |
2b03887a FG |
235 | match infcx.fully_resolve(predicates) { |
236 | Ok(predicates) => Ok(predicates), | |
237 | Err(fixup_err) => { | |
238 | // If we encounter a fixup error, it means that some type | |
239 | // variable wound up unconstrained. I actually don't know | |
240 | // if this can happen, and I certainly don't expect it to | |
241 | // happen often, but if it did happen it probably | |
242 | // represents a legitimate failure due to some kind of | |
243 | // unconstrained variable. | |
244 | // | |
245 | // @lcnr: Let's still ICE here for now. I want a test case | |
246 | // for that. | |
247 | span_bug!( | |
064997fb | 248 | span, |
2b03887a FG |
249 | "inference variables in normalized parameter environment: {}", |
250 | fixup_err | |
064997fb FG |
251 | ); |
252 | } | |
2b03887a | 253 | } |
ba9703b0 XL |
254 | } |
255 | ||
256 | // FIXME: this is gonna need to be removed ... | |
257 | /// Normalizes the parameter environment, reporting errors if they occur. | |
064997fb | 258 | #[instrument(level = "debug", skip(tcx))] |
ba9703b0 XL |
259 | pub fn normalize_param_env_or_error<'tcx>( |
260 | tcx: TyCtxt<'tcx>, | |
ba9703b0 XL |
261 | unnormalized_env: ty::ParamEnv<'tcx>, |
262 | cause: ObligationCause<'tcx>, | |
263 | ) -> ty::ParamEnv<'tcx> { | |
264 | // I'm not wild about reporting errors here; I'd prefer to | |
265 | // have the errors get reported at a defined place (e.g., | |
266 | // during typeck). Instead I have all parameter | |
267 | // environments, in effect, going through this function | |
268 | // and hence potentially reporting errors. This ensures of | |
269 | // course that we never forget to normalize (the | |
270 | // alternative seemed like it would involve a lot of | |
271 | // manual invocations of this fn -- and then we'd have to | |
272 | // deal with the errors at each of those sites). | |
273 | // | |
274 | // In any case, in practice, typeck constructs all the | |
275 | // parameter environments once for every fn as it goes, | |
5099ac24 | 276 | // and errors will get reported then; so outside of type inference we |
ba9703b0 | 277 | // can be sure that no errors should occur. |
ba9703b0 | 278 | let mut predicates: Vec<_> = |
f035d41b | 279 | util::elaborate_predicates(tcx, unnormalized_env.caller_bounds().into_iter()) |
ba9703b0 XL |
280 | .map(|obligation| obligation.predicate) |
281 | .collect(); | |
282 | ||
283 | debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); | |
284 | ||
a2a8927a | 285 | let elaborated_env = ty::ParamEnv::new( |
9ffffee4 | 286 | tcx.mk_predicates(&predicates), |
a2a8927a XL |
287 | unnormalized_env.reveal(), |
288 | unnormalized_env.constness(), | |
289 | ); | |
ba9703b0 XL |
290 | |
291 | // HACK: we are trying to normalize the param-env inside *itself*. The problem is that | |
292 | // normalization expects its param-env to be already normalized, which means we have | |
293 | // a circularity. | |
294 | // | |
295 | // The way we handle this is by normalizing the param-env inside an unnormalized version | |
296 | // of the param-env, which means that if the param-env contains unnormalized projections, | |
297 | // we'll have some normalization failures. This is unfortunate. | |
298 | // | |
299 | // Lazy normalization would basically handle this by treating just the | |
300 | // normalizing-a-trait-ref-requires-itself cycles as evaluation failures. | |
301 | // | |
302 | // Inferred outlives bounds can create a lot of `TypeOutlives` predicates for associated | |
303 | // types, so to make the situation less bad, we normalize all the predicates *but* | |
304 | // the `TypeOutlives` predicates first inside the unnormalized parameter environment, and | |
305 | // then we normalize the `TypeOutlives` bounds inside the normalized parameter environment. | |
306 | // | |
9c376795 | 307 | // This works fairly well because trait matching does not actually care about param-env |
ba9703b0 XL |
308 | // TypeOutlives predicates - these are normally used by regionck. |
309 | let outlives_predicates: Vec<_> = predicates | |
5869c6ff | 310 | .drain_filter(|predicate| { |
487cf647 FG |
311 | matches!( |
312 | predicate.kind().skip_binder(), | |
313 | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) | |
314 | ) | |
ba9703b0 XL |
315 | }) |
316 | .collect(); | |
317 | ||
318 | debug!( | |
319 | "normalize_param_env_or_error: predicates=(non-outlives={:?}, outlives={:?})", | |
320 | predicates, outlives_predicates | |
321 | ); | |
5e7ed085 | 322 | let Ok(non_outlives_predicates) = do_normalize_predicates( |
ba9703b0 | 323 | tcx, |
ba9703b0 XL |
324 | cause.clone(), |
325 | elaborated_env, | |
326 | predicates, | |
5e7ed085 | 327 | ) else { |
ba9703b0 | 328 | // An unnormalized env is better than nothing. |
5e7ed085 FG |
329 | debug!("normalize_param_env_or_error: errored resolving non-outlives predicates"); |
330 | return elaborated_env; | |
ba9703b0 XL |
331 | }; |
332 | ||
333 | debug!("normalize_param_env_or_error: non-outlives predicates={:?}", non_outlives_predicates); | |
334 | ||
335 | // Not sure whether it is better to include the unnormalized TypeOutlives predicates | |
336 | // here. I believe they should not matter, because we are ignoring TypeOutlives param-env | |
337 | // predicates here anyway. Keeping them here anyway because it seems safer. | |
9ffffee4 | 338 | let outlives_env = non_outlives_predicates.iter().chain(&outlives_predicates).cloned(); |
a2a8927a | 339 | let outlives_env = ty::ParamEnv::new( |
9ffffee4 | 340 | tcx.mk_predicates_from_iter(outlives_env), |
a2a8927a XL |
341 | unnormalized_env.reveal(), |
342 | unnormalized_env.constness(), | |
343 | ); | |
5e7ed085 | 344 | let Ok(outlives_predicates) = do_normalize_predicates( |
ba9703b0 | 345 | tcx, |
ba9703b0 XL |
346 | cause, |
347 | outlives_env, | |
348 | outlives_predicates, | |
5e7ed085 | 349 | ) else { |
ba9703b0 | 350 | // An unnormalized env is better than nothing. |
5e7ed085 FG |
351 | debug!("normalize_param_env_or_error: errored resolving outlives predicates"); |
352 | return elaborated_env; | |
ba9703b0 XL |
353 | }; |
354 | debug!("normalize_param_env_or_error: outlives predicates={:?}", outlives_predicates); | |
355 | ||
356 | let mut predicates = non_outlives_predicates; | |
357 | predicates.extend(outlives_predicates); | |
358 | debug!("normalize_param_env_or_error: final predicates={:?}", predicates); | |
a2a8927a | 359 | ty::ParamEnv::new( |
9ffffee4 | 360 | tcx.mk_predicates(&predicates), |
a2a8927a XL |
361 | unnormalized_env.reveal(), |
362 | unnormalized_env.constness(), | |
363 | ) | |
ba9703b0 XL |
364 | } |
365 | ||
f2b60f7d | 366 | /// Normalize a type and process all resulting obligations, returning any errors |
487cf647 | 367 | #[instrument(skip_all)] |
2b03887a FG |
368 | pub fn fully_normalize<'tcx, T>( |
369 | infcx: &InferCtxt<'tcx>, | |
ba9703b0 XL |
370 | cause: ObligationCause<'tcx>, |
371 | param_env: ty::ParamEnv<'tcx>, | |
fc512014 | 372 | value: T, |
ba9703b0 XL |
373 | ) -> Result<T, Vec<FulfillmentError<'tcx>>> |
374 | where | |
9ffffee4 | 375 | T: TypeFoldable<TyCtxt<'tcx>>, |
ba9703b0 | 376 | { |
487cf647 FG |
377 | let ocx = ObligationCtxt::new(infcx); |
378 | debug!(?value); | |
379 | let normalized_value = ocx.normalize(&cause, param_env, value); | |
380 | debug!(?normalized_value); | |
381 | debug!("select_all_or_error start"); | |
382 | let errors = ocx.select_all_or_error(); | |
3c0e092e XL |
383 | if !errors.is_empty() { |
384 | return Err(errors); | |
385 | } | |
487cf647 | 386 | debug!("select_all_or_error complete"); |
fc512014 | 387 | let resolved_value = infcx.resolve_vars_if_possible(normalized_value); |
487cf647 | 388 | debug!(?resolved_value); |
ba9703b0 XL |
389 | Ok(resolved_value) |
390 | } | |
391 | ||
f2b60f7d FG |
392 | /// Process an obligation (and any nested obligations that come from it) to |
393 | /// completion, returning any errors | |
2b03887a FG |
394 | pub fn fully_solve_obligation<'tcx>( |
395 | infcx: &InferCtxt<'tcx>, | |
f2b60f7d FG |
396 | obligation: PredicateObligation<'tcx>, |
397 | ) -> Vec<FulfillmentError<'tcx>> { | |
487cf647 | 398 | fully_solve_obligations(infcx, [obligation]) |
f2b60f7d FG |
399 | } |
400 | ||
401 | /// Process a set of obligations (and any nested obligations that come from them) | |
402 | /// to completion | |
2b03887a FG |
403 | pub fn fully_solve_obligations<'tcx>( |
404 | infcx: &InferCtxt<'tcx>, | |
f2b60f7d FG |
405 | obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>, |
406 | ) -> Vec<FulfillmentError<'tcx>> { | |
487cf647 FG |
407 | let ocx = ObligationCtxt::new(infcx); |
408 | ocx.register_obligations(obligations); | |
409 | ocx.select_all_or_error() | |
f2b60f7d FG |
410 | } |
411 | ||
412 | /// Process a bound (and any nested obligations that come from it) to completion. | |
413 | /// This is a convenience function for traits that have no generic arguments, such | |
414 | /// as auto traits, and builtin traits like Copy or Sized. | |
2b03887a FG |
415 | pub fn fully_solve_bound<'tcx>( |
416 | infcx: &InferCtxt<'tcx>, | |
f2b60f7d FG |
417 | cause: ObligationCause<'tcx>, |
418 | param_env: ty::ParamEnv<'tcx>, | |
419 | ty: Ty<'tcx>, | |
420 | bound: DefId, | |
421 | ) -> Vec<FulfillmentError<'tcx>> { | |
487cf647 | 422 | let tcx = infcx.tcx; |
9c376795 FG |
423 | let trait_ref = tcx.mk_trait_ref(bound, [ty]); |
424 | let obligation = Obligation::new(tcx, cause, param_env, ty::Binder::dummy(trait_ref)); | |
487cf647 FG |
425 | |
426 | fully_solve_obligation(infcx, obligation) | |
f2b60f7d FG |
427 | } |
428 | ||
3dfed10e XL |
429 | /// Normalizes the predicates and checks whether they hold in an empty environment. If this |
430 | /// returns true, then either normalize encountered an error or one of the predicates did not | |
431 | /// hold. Used when creating vtables to check for unsatisfiable methods. | |
432 | pub fn impossible_predicates<'tcx>( | |
ba9703b0 XL |
433 | tcx: TyCtxt<'tcx>, |
434 | predicates: Vec<ty::Predicate<'tcx>>, | |
435 | ) -> bool { | |
3dfed10e | 436 | debug!("impossible_predicates(predicates={:?})", predicates); |
ba9703b0 | 437 | |
2b03887a FG |
438 | let infcx = tcx.infer_ctxt().build(); |
439 | let param_env = ty::ParamEnv::reveal_all(); | |
440 | let ocx = ObligationCtxt::new(&infcx); | |
487cf647 | 441 | let predicates = ocx.normalize(&ObligationCause::dummy(), param_env, predicates); |
2b03887a | 442 | for predicate in predicates { |
487cf647 | 443 | let obligation = Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate); |
2b03887a FG |
444 | ocx.register_obligation(obligation); |
445 | } | |
446 | let errors = ocx.select_all_or_error(); | |
3c0e092e | 447 | |
2b03887a | 448 | let result = !errors.is_empty(); |
fc512014 | 449 | debug!("impossible_predicates = {:?}", result); |
ba9703b0 XL |
450 | result |
451 | } | |
452 | ||
3dfed10e | 453 | fn subst_and_check_impossible_predicates<'tcx>( |
ba9703b0 XL |
454 | tcx: TyCtxt<'tcx>, |
455 | key: (DefId, SubstsRef<'tcx>), | |
456 | ) -> bool { | |
3dfed10e | 457 | debug!("subst_and_check_impossible_predicates(key={:?})", key); |
ba9703b0 | 458 | |
3dfed10e | 459 | let mut predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates; |
04454e1e FG |
460 | |
461 | // Specifically check trait fulfillment to avoid an error when trying to resolve | |
462 | // associated items. | |
463 | if let Some(trait_def_id) = tcx.trait_of_item(key.0) { | |
464 | let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, key.1); | |
487cf647 | 465 | predicates.push(ty::Binder::dummy(trait_ref).to_predicate(tcx)); |
04454e1e FG |
466 | } |
467 | ||
5099ac24 | 468 | predicates.retain(|predicate| !predicate.needs_subst()); |
3dfed10e | 469 | let result = impossible_predicates(tcx, predicates); |
ba9703b0 | 470 | |
3dfed10e | 471 | debug!("subst_and_check_impossible_predicates(key={:?}) = {:?}", key, result); |
ba9703b0 XL |
472 | result |
473 | } | |
474 | ||
f2b60f7d FG |
475 | /// Checks whether a trait's method is impossible to call on a given impl. |
476 | /// | |
477 | /// This only considers predicates that reference the impl's generics, and not | |
478 | /// those that reference the method's generics. | |
9c376795 | 479 | fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefId, DefId)) -> bool { |
f2b60f7d FG |
480 | struct ReferencesOnlyParentGenerics<'tcx> { |
481 | tcx: TyCtxt<'tcx>, | |
482 | generics: &'tcx ty::Generics, | |
483 | trait_item_def_id: DefId, | |
484 | } | |
9ffffee4 | 485 | impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for ReferencesOnlyParentGenerics<'tcx> { |
f2b60f7d FG |
486 | type BreakTy = (); |
487 | fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { | |
488 | // If this is a parameter from the trait item's own generics, then bail | |
489 | if let ty::Param(param) = t.kind() | |
490 | && let param_def_id = self.generics.type_param(param, self.tcx).def_id | |
491 | && self.tcx.parent(param_def_id) == self.trait_item_def_id | |
492 | { | |
9c376795 | 493 | return ControlFlow::Break(()); |
f2b60f7d FG |
494 | } |
495 | t.super_visit_with(self) | |
496 | } | |
497 | fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { | |
498 | if let ty::ReEarlyBound(param) = r.kind() | |
499 | && let param_def_id = self.generics.region_param(¶m, self.tcx).def_id | |
500 | && self.tcx.parent(param_def_id) == self.trait_item_def_id | |
501 | { | |
9c376795 | 502 | return ControlFlow::Break(()); |
f2b60f7d FG |
503 | } |
504 | r.super_visit_with(self) | |
505 | } | |
506 | fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { | |
507 | if let ty::ConstKind::Param(param) = ct.kind() | |
508 | && let param_def_id = self.generics.const_param(¶m, self.tcx).def_id | |
509 | && self.tcx.parent(param_def_id) == self.trait_item_def_id | |
510 | { | |
9c376795 | 511 | return ControlFlow::Break(()); |
f2b60f7d FG |
512 | } |
513 | ct.super_visit_with(self) | |
514 | } | |
515 | } | |
516 | ||
517 | let generics = tcx.generics_of(trait_item_def_id); | |
518 | let predicates = tcx.predicates_of(trait_item_def_id); | |
9c376795 FG |
519 | let impl_trait_ref = tcx |
520 | .impl_trait_ref(impl_def_id) | |
521 | .expect("expected impl to correspond to trait") | |
522 | .subst_identity(); | |
f2b60f7d FG |
523 | let param_env = tcx.param_env(impl_def_id); |
524 | ||
525 | let mut visitor = ReferencesOnlyParentGenerics { tcx, generics, trait_item_def_id }; | |
526 | let predicates_for_trait = predicates.predicates.iter().filter_map(|(pred, span)| { | |
9ffffee4 FG |
527 | pred.visit_with(&mut visitor).is_continue().then(|| { |
528 | Obligation::new( | |
487cf647 | 529 | tcx, |
f2b60f7d FG |
530 | ObligationCause::dummy_with_span(*span), |
531 | param_env, | |
532 | ty::EarlyBinder(*pred).subst(tcx, impl_trait_ref.substs), | |
9ffffee4 FG |
533 | ) |
534 | }) | |
f2b60f7d FG |
535 | }); |
536 | ||
2b03887a FG |
537 | let infcx = tcx.infer_ctxt().ignoring_regions().build(); |
538 | for obligation in predicates_for_trait { | |
539 | // Ignore overflow error, to be conservative. | |
540 | if let Ok(result) = infcx.evaluate_obligation(&obligation) | |
541 | && !result.may_apply() | |
542 | { | |
543 | return true; | |
f2b60f7d | 544 | } |
2b03887a FG |
545 | } |
546 | false | |
f2b60f7d FG |
547 | } |
548 | ||
f035d41b | 549 | pub fn provide(providers: &mut ty::query::Providers) { |
ba9703b0 | 550 | object_safety::provide(providers); |
487cf647 | 551 | vtable::provide(providers); |
ba9703b0 XL |
552 | *providers = ty::query::Providers { |
553 | specialization_graph_of: specialize::specialization_graph_provider, | |
554 | specializes: specialize::specializes, | |
3dfed10e | 555 | subst_and_check_impossible_predicates, |
9ffffee4 | 556 | check_tys_might_be_eq: misc::check_tys_might_be_eq, |
f2b60f7d | 557 | is_impossible_method, |
ba9703b0 XL |
558 | ..*providers |
559 | }; | |
560 | } |