1 use crate::infer
::{InferCtxt, TyOrConstInferVar}
;
2 use rustc_data_structures
::obligation_forest
::ProcessResult
;
3 use rustc_data_structures
::obligation_forest
::{DoCompleted, Error, ForestObligation}
;
4 use rustc_data_structures
::obligation_forest
::{ObligationForest, ObligationProcessor}
;
5 use rustc_infer
::traits
::{TraitEngine, TraitEngineExt as _}
;
6 use rustc_middle
::ty
::error
::ExpectedFound
;
7 use rustc_middle
::ty
::{self, ToPolyTraitRef, Ty, TypeFoldable}
;
8 use std
::marker
::PhantomData
;
11 use super::select
::SelectionContext
;
13 use super::CodeAmbiguity
;
14 use super::CodeProjectionError
;
15 use super::CodeSelectionError
;
16 use super::{ConstEvalFailure, Unimplemented}
;
17 use super::{FulfillmentError, FulfillmentErrorCode}
;
18 use super::{ObligationCause, PredicateObligation}
;
20 use crate::traits
::error_reporting
::InferCtxtExt
as _
;
21 use crate::traits
::query
::evaluate_obligation
::InferCtxtExt
as _
;
23 impl<'tcx
> ForestObligation
for PendingPredicateObligation
<'tcx
> {
24 /// Note that we include both the `ParamEnv` and the `Predicate`,
25 /// as the `ParamEnv` can influence whether fulfillment succeeds
27 type CacheKey
= ty
::ParamEnvAnd
<'tcx
, ty
::Predicate
<'tcx
>>;
29 fn as_cache_key(&self) -> Self::CacheKey
{
30 self.obligation
.param_env
.and(self.obligation
.predicate
)
34 /// The fulfillment context is used to drive trait resolution. It
35 /// consists of a list of obligations that must be (eventually)
36 /// satisfied. The job is to track which are satisfied, which yielded
37 /// errors, and which are still pending. At any point, users can call
38 /// `select_where_possible`, and the fulfillment context will try to do
39 /// selection, retaining only those obligations that remain
40 /// ambiguous. This may be helpful in pushing type inference
41 /// along. Once all type inference constraints have been generated, the
42 /// method `select_all_or_error` can be used to report any remaining
43 /// ambiguous cases as errors.
44 pub struct FulfillmentContext
<'tcx
> {
45 // A list of all obligations that have been registered with this
46 // fulfillment context.
47 predicates
: ObligationForest
<PendingPredicateObligation
<'tcx
>>,
48 // Should this fulfillment context register type-lives-for-region
49 // obligations on its parent infcx? In some cases, region
50 // obligations are either already known to hold (normalization) or
51 // hopefully verifed elsewhere (type-impls-bound), and therefore
52 // should not be checked.
54 // Note that if we are normalizing a type that we already
55 // know is well-formed, there should be no harm setting this
56 // to true - all the region variables should be determinable
57 // using the RFC 447 rules, which don't depend on
58 // type-lives-for-region constraints, and because the type
59 // is well-formed, the constraints should hold.
60 register_region_obligations
: bool
,
61 // Is it OK to register obligations into this infcx inside
64 // The "primary fulfillment" in many cases in typeck lives
65 // outside of any snapshot, so any use of it inside a snapshot
66 // will lead to trouble and therefore is checked against, but
67 // other fulfillment contexts sometimes do live inside of
68 // a snapshot (they don't *straddle* a snapshot, so there
69 // is no trouble there).
70 usable_in_snapshot
: bool
,
73 #[derive(Clone, Debug)]
74 pub struct PendingPredicateObligation
<'tcx
> {
75 pub obligation
: PredicateObligation
<'tcx
>,
76 // FIXME(eddyb) look into whether this could be a `SmallVec`.
77 // Judging by the comment in `process_obligation`, the 1-element case
78 // is common so this could be a `SmallVec<[TyOrConstInferVar<'tcx>; 1]>`.
79 pub stalled_on
: Vec
<TyOrConstInferVar
<'tcx
>>,
82 // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
83 #[cfg(target_arch = "x86_64")]
84 static_assert_size
!(PendingPredicateObligation
<'_
>, 136);
86 impl<'a
, 'tcx
> FulfillmentContext
<'tcx
> {
87 /// Creates a new fulfillment context.
88 pub fn new() -> FulfillmentContext
<'tcx
> {
90 predicates
: ObligationForest
::new(),
91 register_region_obligations
: true,
92 usable_in_snapshot
: false,
96 pub fn new_in_snapshot() -> FulfillmentContext
<'tcx
> {
98 predicates
: ObligationForest
::new(),
99 register_region_obligations
: true,
100 usable_in_snapshot
: true,
104 pub fn new_ignoring_regions() -> FulfillmentContext
<'tcx
> {
106 predicates
: ObligationForest
::new(),
107 register_region_obligations
: false,
108 usable_in_snapshot
: false,
112 /// Attempts to select obligations using `selcx`.
115 selcx
: &mut SelectionContext
<'a
, 'tcx
>,
116 ) -> Result
<(), Vec
<FulfillmentError
<'tcx
>>> {
117 debug
!("select(obligation-forest-size={})", self.predicates
.len());
119 let mut errors
= Vec
::new();
122 debug
!("select: starting another iteration");
124 // Process pending obligations.
125 let outcome
= self.predicates
.process_obligations(
126 &mut FulfillProcessor
{
128 register_region_obligations
: self.register_region_obligations
,
132 debug
!("select: outcome={:#?}", outcome
);
134 // FIXME: if we kept the original cache key, we could mark projection
135 // obligations as complete for the projection cache here.
137 errors
.extend(outcome
.errors
.into_iter().map(to_fulfillment_error
));
139 // If nothing new was added, no need to keep looping.
146 "select({} predicates remaining, {} errors) done",
147 self.predicates
.len(),
151 if errors
.is_empty() { Ok(()) }
else { Err(errors) }
155 impl<'tcx
> TraitEngine
<'tcx
> for FulfillmentContext
<'tcx
> {
156 /// "Normalize" a projection type `<SomeType as SomeTrait>::X` by
157 /// creating a fresh type variable `$0` as well as a projection
158 /// predicate `<SomeType as SomeTrait>::X == $0`. When the
159 /// inference engine runs, it will attempt to find an impl of
160 /// `SomeTrait` or a where-clause that lets us unify `$0` with
161 /// something concrete. If this fails, we'll unify `$0` with
162 /// `projection_ty` again.
163 fn normalize_projection_type(
165 infcx
: &InferCtxt
<'_
, 'tcx
>,
166 param_env
: ty
::ParamEnv
<'tcx
>,
167 projection_ty
: ty
::ProjectionTy
<'tcx
>,
168 cause
: ObligationCause
<'tcx
>,
170 debug
!("normalize_projection_type(projection_ty={:?})", projection_ty
);
172 debug_assert
!(!projection_ty
.has_escaping_bound_vars());
174 // FIXME(#20304) -- cache
176 let mut selcx
= SelectionContext
::new(infcx
);
177 let mut obligations
= vec
![];
178 let normalized_ty
= project
::normalize_projection_type(
186 self.register_predicate_obligations(infcx
, obligations
);
188 debug
!("normalize_projection_type: result={:?}", normalized_ty
);
193 fn register_predicate_obligation(
195 infcx
: &InferCtxt
<'_
, 'tcx
>,
196 obligation
: PredicateObligation
<'tcx
>,
198 // this helps to reduce duplicate errors, as well as making
199 // debug output much nicer to read and so on.
200 let obligation
= infcx
.resolve_vars_if_possible(&obligation
);
202 debug
!("register_predicate_obligation(obligation={:?})", obligation
);
204 assert
!(!infcx
.is_in_snapshot() || self.usable_in_snapshot
);
207 .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }
);
210 fn select_all_or_error(
212 infcx
: &InferCtxt
<'_
, 'tcx
>,
213 ) -> Result
<(), Vec
<FulfillmentError
<'tcx
>>> {
214 self.select_where_possible(infcx
)?
;
216 let errors
: Vec
<_
> = self
218 .to_errors(CodeAmbiguity
)
220 .map(to_fulfillment_error
)
222 if errors
.is_empty() { Ok(()) }
else { Err(errors) }
225 fn select_where_possible(
227 infcx
: &InferCtxt
<'_
, 'tcx
>,
228 ) -> Result
<(), Vec
<FulfillmentError
<'tcx
>>> {
229 let mut selcx
= SelectionContext
::new(infcx
);
230 self.select(&mut selcx
)
233 fn pending_obligations(&self) -> Vec
<PredicateObligation
<'tcx
>> {
234 self.predicates
.map_pending_obligations(|o
| o
.obligation
.clone())
238 struct FulfillProcessor
<'a
, 'b
, 'tcx
> {
239 selcx
: &'a
mut SelectionContext
<'b
, 'tcx
>,
240 register_region_obligations
: bool
,
243 fn mk_pending(os
: Vec
<PredicateObligation
<'tcx
>>) -> Vec
<PendingPredicateObligation
<'tcx
>> {
245 .map(|o
| PendingPredicateObligation { obligation: o, stalled_on: vec![] }
)
249 impl<'a
, 'b
, 'tcx
> ObligationProcessor
for FulfillProcessor
<'a
, 'b
, 'tcx
> {
250 type Obligation
= PendingPredicateObligation
<'tcx
>;
251 type Error
= FulfillmentErrorCode
<'tcx
>;
253 /// Processes a predicate obligation and returns either:
254 /// - `Changed(v)` if the predicate is true, presuming that `v` are also true
255 /// - `Unchanged` if we don't have enough info to be sure
256 /// - `Error(e)` if the predicate does not hold
258 /// This is always inlined, despite its size, because it has a single
259 /// callsite and it is called *very* frequently.
261 fn process_obligation(
263 pending_obligation
: &mut Self::Obligation
,
264 ) -> ProcessResult
<Self::Obligation
, Self::Error
> {
265 // If we were stalled on some unresolved variables, first check whether
266 // any of them have been resolved; if not, don't bother doing more work
268 let change
= match pending_obligation
.stalled_on
.len() {
269 // Match arms are in order of frequency, which matters because this
270 // code is so hot. 1 and 0 dominate; 2+ is fairly rare.
272 let infer_var
= pending_obligation
.stalled_on
[0];
273 self.selcx
.infcx().ty_or_const_infer_var_changed(infer_var
)
276 // In this case we haven't changed, but wish to make a change.
280 // This `for` loop was once a call to `all()`, but this lower-level
281 // form was a perf win. See #64545 for details.
283 for &infer_var
in &pending_obligation
.stalled_on
{
284 if self.selcx
.infcx().ty_or_const_infer_var_changed(infer_var
) {
295 "process_predicate: pending obligation {:?} still stalled on {:?}",
296 self.selcx
.infcx().resolve_vars_if_possible(&pending_obligation
.obligation
),
297 pending_obligation
.stalled_on
299 return ProcessResult
::Unchanged
;
302 // This part of the code is much colder.
304 pending_obligation
.stalled_on
.truncate(0);
306 let obligation
= &mut pending_obligation
.obligation
;
308 if obligation
.predicate
.has_infer_types_or_consts() {
309 obligation
.predicate
=
310 self.selcx
.infcx().resolve_vars_if_possible(&obligation
.predicate
);
313 debug
!("process_obligation: obligation = {:?} cause = {:?}", obligation
, obligation
.cause
);
315 match obligation
.predicate
{
316 ty
::Predicate
::Trait(ref data
, _
) => {
317 let trait_obligation
= obligation
.with(*data
);
319 if data
.is_global() {
320 // no type variables present, can use evaluation for better caching.
321 // FIXME: consider caching errors too.
322 if self.selcx
.infcx().predicate_must_hold_considering_regions(&obligation
) {
324 "selecting trait `{:?}` at depth {} evaluated to holds",
325 data
, obligation
.recursion_depth
327 return ProcessResult
::Changed(vec
![]);
331 match self.selcx
.select(&trait_obligation
) {
332 Ok(Some(vtable
)) => {
334 "selecting trait `{:?}` at depth {} yielded Ok(Some)",
335 data
, obligation
.recursion_depth
337 ProcessResult
::Changed(mk_pending(vtable
.nested_obligations()))
341 "selecting trait `{:?}` at depth {} yielded Ok(None)",
342 data
, obligation
.recursion_depth
345 // This is a bit subtle: for the most part, the
346 // only reason we can fail to make progress on
347 // trait selection is because we don't have enough
348 // information about the types in the trait.
349 pending_obligation
.stalled_on
=
350 trait_ref_type_vars(self.selcx
, data
.to_poly_trait_ref());
353 "process_predicate: pending obligation {:?} now stalled on {:?}",
354 self.selcx
.infcx().resolve_vars_if_possible(obligation
),
355 pending_obligation
.stalled_on
358 ProcessResult
::Unchanged
360 Err(selection_err
) => {
362 "selecting trait `{:?}` at depth {} yielded Err",
363 data
, obligation
.recursion_depth
366 ProcessResult
::Error(CodeSelectionError(selection_err
))
371 ty
::Predicate
::RegionOutlives(ref binder
) => {
372 match self.selcx
.infcx().region_outlives_predicate(&obligation
.cause
, binder
) {
373 Ok(()) => ProcessResult
::Changed(vec
![]),
374 Err(_
) => ProcessResult
::Error(CodeSelectionError(Unimplemented
)),
378 ty
::Predicate
::TypeOutlives(ref binder
) => {
379 // Check if there are higher-ranked vars.
380 match binder
.no_bound_vars() {
381 // If there are, inspect the underlying type further.
383 // Convert from `Binder<OutlivesPredicate<Ty, Region>>` to `Binder<Ty>`.
384 let binder
= binder
.map_bound_ref(|pred
| pred
.0);
386 // Check if the type has any bound vars.
387 match binder
.no_bound_vars() {
388 // If so, this obligation is an error (for now). Eventually we should be
389 // able to support additional cases here, like `for<'a> &'a str: 'a`.
390 // NOTE: this is duplicate-implemented between here and fulfillment.
391 None
=> ProcessResult
::Error(CodeSelectionError(Unimplemented
)),
392 // Otherwise, we have something of the form
393 // `for<'a> T: 'a where 'a not in T`, which we can treat as
396 let r_static
= self.selcx
.tcx().lifetimes
.re_static
;
397 if self.register_region_obligations
{
398 self.selcx
.infcx().register_region_obligation_with_cause(
404 ProcessResult
::Changed(vec
![])
408 // If there aren't, register the obligation.
409 Some(ty
::OutlivesPredicate(t_a
, r_b
)) => {
410 if self.register_region_obligations
{
411 self.selcx
.infcx().register_region_obligation_with_cause(
417 ProcessResult
::Changed(vec
![])
422 ty
::Predicate
::Projection(ref data
) => {
423 let project_obligation
= obligation
.with(*data
);
424 match project
::poly_project_and_unify_type(self.selcx
, &project_obligation
) {
426 let tcx
= self.selcx
.tcx();
427 pending_obligation
.stalled_on
=
428 trait_ref_type_vars(self.selcx
, data
.to_poly_trait_ref(tcx
));
429 ProcessResult
::Unchanged
431 Ok(Some(os
)) => ProcessResult
::Changed(mk_pending(os
)),
432 Err(e
) => ProcessResult
::Error(CodeProjectionError(e
)),
436 ty
::Predicate
::ObjectSafe(trait_def_id
) => {
437 if !self.selcx
.tcx().is_object_safe(trait_def_id
) {
438 ProcessResult
::Error(CodeSelectionError(Unimplemented
))
440 ProcessResult
::Changed(vec
![])
444 ty
::Predicate
::ClosureKind(_
, closure_substs
, kind
) => {
445 match self.selcx
.infcx().closure_kind(closure_substs
) {
446 Some(closure_kind
) => {
447 if closure_kind
.extends(kind
) {
448 ProcessResult
::Changed(vec
![])
450 ProcessResult
::Error(CodeSelectionError(Unimplemented
))
453 None
=> ProcessResult
::Unchanged
,
457 ty
::Predicate
::WellFormed(ty
) => {
458 match wf
::obligations(
460 obligation
.param_env
,
461 obligation
.cause
.body_id
,
463 obligation
.cause
.span
,
466 pending_obligation
.stalled_on
=
467 vec
![TyOrConstInferVar
::maybe_from_ty(ty
).unwrap()];
468 ProcessResult
::Unchanged
470 Some(os
) => ProcessResult
::Changed(mk_pending(os
)),
474 ty
::Predicate
::Subtype(ref subtype
) => {
475 match self.selcx
.infcx().subtype_predicate(
477 obligation
.param_env
,
481 // None means that both are unresolved.
482 pending_obligation
.stalled_on
= vec
![
483 TyOrConstInferVar
::maybe_from_ty(subtype
.skip_binder().a
).unwrap(),
484 TyOrConstInferVar
::maybe_from_ty(subtype
.skip_binder().b
).unwrap(),
486 ProcessResult
::Unchanged
488 Some(Ok(ok
)) => ProcessResult
::Changed(mk_pending(ok
.obligations
)),
490 let expected_found
= ExpectedFound
::new(
491 subtype
.skip_binder().a_is_expected
,
492 subtype
.skip_binder().a
,
493 subtype
.skip_binder().b
,
495 ProcessResult
::Error(FulfillmentErrorCode
::CodeSubtypeError(
503 ty
::Predicate
::ConstEvaluatable(def_id
, substs
) => {
504 match self.selcx
.infcx().const_eval_resolve(
505 obligation
.param_env
,
509 Some(obligation
.cause
.span
),
511 Ok(_
) => ProcessResult
::Changed(vec
![]),
512 Err(err
) => ProcessResult
::Error(CodeSelectionError(ConstEvalFailure(err
))),
518 fn process_backedge
<'c
, I
>(
521 _marker
: PhantomData
<&'c PendingPredicateObligation
<'tcx
>>,
523 I
: Clone
+ Iterator
<Item
= &'c PendingPredicateObligation
<'tcx
>>,
525 if self.selcx
.coinductive_match(cycle
.clone().map(|s
| s
.obligation
.predicate
)) {
526 debug
!("process_child_obligations: coinductive match");
528 let cycle
: Vec
<_
> = cycle
.map(|c
| c
.obligation
.clone()).collect();
529 self.selcx
.infcx().report_overflow_error_cycle(&cycle
);
534 /// Returns the set of type inference variables contained in a trait ref.
535 fn trait_ref_type_vars
<'a
, 'tcx
>(
536 selcx
: &mut SelectionContext
<'a
, 'tcx
>,
537 trait_ref
: ty
::PolyTraitRef
<'tcx
>,
538 ) -> Vec
<TyOrConstInferVar
<'tcx
>> {
541 .resolve_vars_if_possible(&trait_ref
)
542 .skip_binder() // ok b/c this check doesn't care about regions
545 // FIXME(eddyb) try using `skip_current_subtree` to skip everything that
546 // doesn't contain inference variables, not just the outermost level.
547 .filter(|arg
| arg
.has_infer_types_or_consts())
548 .flat_map(|arg
| arg
.walk())
549 .filter_map(TyOrConstInferVar
::maybe_from_generic_arg
)
553 fn to_fulfillment_error
<'tcx
>(
554 error
: Error
<PendingPredicateObligation
<'tcx
>, FulfillmentErrorCode
<'tcx
>>,
555 ) -> FulfillmentError
<'tcx
> {
556 let obligation
= error
.backtrace
.into_iter().next().unwrap().obligation
;
557 FulfillmentError
::new(obligation
, error
.error
)