2019-05-17 01:20:14 +00:00
//! Support code for rustdoc and external tools.
//! You really don't want to be using this unless you need to.
2018-04-15 12:56:14 +00:00
2018-03-09 21:49:37 +00:00
use super ::* ;
2019-02-05 17:20:45 +00:00
use crate ::infer ::region_constraints ::{ Constraint , RegionConstraintData } ;
use crate ::infer ::InferCtxt ;
2022-03-11 23:46:49 +00:00
use crate ::traits ::project ::ProjectAndUnifyResult ;
2022-02-16 09:56:01 +00:00
use rustc_middle ::mir ::interpret ::ErrorHandled ;
Folding revamp.
This commit makes type folding more like the way chalk does it.
Currently, `TypeFoldable` has `fold_with` and `super_fold_with` methods.
- `fold_with` is the standard entry point, and defaults to calling
`super_fold_with`.
- `super_fold_with` does the actual work of traversing a type.
- For a few types of interest (`Ty`, `Region`, etc.) `fold_with` instead
calls into a `TypeFolder`, which can then call back into
`super_fold_with`.
With the new approach, `TypeFoldable` has `fold_with` and
`TypeSuperFoldable` has `super_fold_with`.
- `fold_with` is still the standard entry point, *and* it does the
actual work of traversing a type, for all types except types of
interest.
- `super_fold_with` is only implemented for the types of interest.
Benefits of the new model.
- I find it easier to understand. The distinction between types of
interest and other types is clearer, and `super_fold_with` doesn't
exist for most types.
- With the current model is easy to get confused and implement a
`super_fold_with` method that should be left defaulted. (Some of the
precursor commits fixed such cases.)
- With the current model it's easy to call `super_fold_with` within
`TypeFolder` impls where `fold_with` should be called. The new
approach makes this mistake impossible, and this commit fixes a number
of such cases.
- It's potentially faster, because it avoids the `fold_with` ->
`super_fold_with` call in all cases except types of interest. A lot of
the time the compile would inline those away, but not necessarily
always.
2022-06-02 01:38:15 +00:00
use rustc_middle ::ty ::fold ::{ TypeFolder , TypeSuperFoldable } ;
2022-01-10 23:39:21 +00:00
use rustc_middle ::ty ::{ Region , RegionVid , Term } ;
2018-03-09 21:49:37 +00:00
2019-05-17 01:20:14 +00:00
use rustc_data_structures ::fx ::{ FxHashMap , FxHashSet } ;
use std ::collections ::hash_map ::Entry ;
use std ::collections ::VecDeque ;
2021-03-08 23:32:41 +00:00
use std ::iter ;
2019-05-17 01:20:14 +00:00
2018-04-05 19:21:17 +00:00
// FIXME(twk): this is obviously not nice to duplicate like that
2018-03-09 21:49:37 +00:00
#[ derive(Eq, PartialEq, Hash, Copy, Clone, Debug) ]
2018-04-01 20:38:47 +00:00
pub enum RegionTarget < ' tcx > {
2018-03-09 21:49:37 +00:00
Region ( Region < ' tcx > ) ,
2018-04-06 22:25:25 +00:00
RegionVid ( RegionVid ) ,
2018-03-09 21:49:37 +00:00
}
#[ derive(Default, Debug, Clone) ]
2018-04-01 20:38:47 +00:00
pub struct RegionDeps < ' tcx > {
2018-03-09 21:49:37 +00:00
larger : FxHashSet < RegionTarget < ' tcx > > ,
2018-04-06 22:25:25 +00:00
smaller : FxHashSet < RegionTarget < ' tcx > > ,
2018-03-09 21:49:37 +00:00
}
2018-04-05 18:10:15 +00:00
pub enum AutoTraitResult < A > {
2018-03-09 21:49:37 +00:00
ExplicitImpl ,
2018-04-05 18:10:15 +00:00
PositiveImpl ( A ) ,
2018-03-09 21:49:37 +00:00
NegativeImpl ,
}
2020-09-25 23:17:54 +00:00
#[ allow(dead_code) ]
2018-04-05 18:10:15 +00:00
impl < A > AutoTraitResult < A > {
2018-03-09 21:49:37 +00:00
fn is_auto ( & self ) -> bool {
2020-12-24 01:55:21 +00:00
matches! ( self , AutoTraitResult ::PositiveImpl ( _ ) | AutoTraitResult ::NegativeImpl )
2018-03-09 21:49:37 +00:00
}
}
2018-04-05 18:10:15 +00:00
pub struct AutoTraitInfo < ' cx > {
pub full_user_env : ty ::ParamEnv < ' cx > ,
pub region_data : RegionConstraintData < ' cx > ,
pub vid_to_region : FxHashMap < ty ::RegionVid , ty ::Region < ' cx > > ,
}
2019-06-11 19:03:44 +00:00
pub struct AutoTraitFinder < ' tcx > {
2019-06-13 21:48:52 +00:00
tcx : TyCtxt < ' tcx > ,
2018-03-09 21:49:37 +00:00
}
2019-06-11 19:03:44 +00:00
impl < ' tcx > AutoTraitFinder < ' tcx > {
2019-06-13 21:48:52 +00:00
pub fn new ( tcx : TyCtxt < ' tcx > ) -> Self {
2018-04-06 22:12:51 +00:00
AutoTraitFinder { tcx }
}
2019-02-08 13:53:55 +00:00
/// Makes a best effort to determine whether and under which conditions an auto trait is
2018-04-26 20:22:06 +00:00
/// implemented for a type. For example, if you have
///
/// ```
/// struct Foo<T> { data: Box<T> }
/// ```
2018-08-10 17:13:43 +00:00
///
2018-04-26 20:22:06 +00:00
/// then this might return that Foo<T>: Send if T: Send (encoded in the AutoTraitResult type).
/// The analysis attempts to account for custom impls as well as other complex cases. This
/// result is intended for use by rustdoc and other such consumers.
2018-08-10 17:13:43 +00:00
///
2018-04-26 20:22:06 +00:00
/// (Note that due to the coinductive nature of Send, the full and correct result is actually
/// quite simple to generate. That is, when a type has no custom impl, it is Send iff its field
/// types are all Send. So, in our example, we might have that Foo<T>: Send if Box<T>: Send.
/// But this is often not the best way to present to the user.)
2018-08-10 17:13:43 +00:00
///
2018-04-26 20:22:06 +00:00
/// Warning: The API should be considered highly unstable, and it may be refactored or removed
/// in the future.
2018-04-12 09:58:34 +00:00
pub fn find_auto_trait_generics < A > (
& self ,
2019-04-20 15:27:44 +00:00
ty : Ty < ' tcx > ,
2019-04-22 19:52:51 +00:00
orig_env : ty ::ParamEnv < ' tcx > ,
2018-04-12 09:58:34 +00:00
trait_did : DefId ,
2021-02-27 17:13:10 +00:00
mut auto_trait_callback : impl FnMut ( AutoTraitInfo < ' tcx > ) -> A ,
2018-04-12 09:58:34 +00:00
) -> AutoTraitResult < A > {
2018-03-09 21:49:37 +00:00
let tcx = self . tcx ;
let trait_ref = ty ::TraitRef { def_id : trait_did , substs : tcx . mk_substs_trait ( ty , & [ ] ) } ;
2021-01-07 05:41:55 +00:00
let trait_pred = ty ::Binder ::dummy ( trait_ref ) ;
2018-03-09 21:49:37 +00:00
2018-04-12 09:58:34 +00:00
let bail_out = tcx . infer_ctxt ( ) . enter ( | infcx | {
2022-03-27 01:01:34 +00:00
let mut selcx = SelectionContext ::new ( & infcx ) ;
2018-04-12 09:58:34 +00:00
let result = selcx . select ( & Obligation ::new (
ObligationCause ::dummy ( ) ,
2019-04-22 19:52:51 +00:00
orig_env ,
2018-04-12 09:58:34 +00:00
trait_pred . to_poly_trait_predicate ( ) ,
) ) ;
2018-09-12 14:57:19 +00:00
2022-03-26 13:58:19 +00:00
match result {
Ok ( Some ( ImplSource ::UserDefined ( _ ) ) ) = > {
debug! (
" find_auto_trait_generics({:?}): \
manual impl found , bailing out " ,
trait_ref
) ;
return true ;
}
_ = > { }
}
let result = selcx . select ( & Obligation ::new (
ObligationCause ::dummy ( ) ,
orig_env ,
trait_pred . to_poly_trait_predicate_negative_polarity ( ) ,
) ) ;
2018-04-12 09:58:34 +00:00
match result {
2020-09-24 17:22:36 +00:00
Ok ( Some ( ImplSource ::UserDefined ( _ ) ) ) = > {
2018-04-12 09:58:34 +00:00
debug! (
2019-04-22 19:52:51 +00:00
" find_auto_trait_generics({:?}): \
2018-03-09 21:49:37 +00:00
manual impl found , bailing out " ,
2019-04-22 19:52:51 +00:00
trait_ref
2018-04-12 09:58:34 +00:00
) ;
2018-09-12 14:57:19 +00:00
true
2018-04-12 09:58:34 +00:00
}
2018-09-12 14:57:19 +00:00
_ = > false ,
}
2018-04-12 09:58:34 +00:00
} ) ;
2018-03-09 21:49:37 +00:00
// If an explicit impl exists, it always takes priority over an auto impl
if bail_out {
return AutoTraitResult ::ExplicitImpl ;
}
2020-03-20 14:03:11 +00:00
tcx . infer_ctxt ( ) . enter ( | infcx | {
2018-10-16 08:44:26 +00:00
let mut fresh_preds = FxHashSet ::default ( ) ;
2018-03-09 21:49:37 +00:00
// Due to the way projections are handled by SelectionContext, we need to run
// evaluate_predicates twice: once on the original param env, and once on the result of
// the first evaluate_predicates call.
//
// The problem is this: most of rustc, including SelectionContext and traits::project,
2018-11-27 02:59:49 +00:00
// are designed to work with a concrete usage of a type (e.g., Vec<u8>
2018-03-09 21:49:37 +00:00
// fn<T>() { Vec<T> }. This information will generally never change - given
// the 'T' in fn<T>() { ... }, we'll never know anything else about 'T'.
// If we're unable to prove that 'T' implements a particular trait, we're done -
// there's nothing left to do but error out.
//
// However, synthesizing an auto trait impl works differently. Here, we start out with
// a set of initial conditions - the ParamEnv of the struct/enum/union we're dealing
// with - and progressively discover the conditions we need to fulfill for it to
// implement a certain auto trait. This ends up breaking two assumptions made by trait
// selection and projection:
//
// * We can always cache the result of a particular trait selection for the lifetime of
// an InfCtxt
// * Given a projection bound such as '<T as SomeTrait>::SomeItem = K', if 'T:
// SomeTrait' doesn't hold, then we don't need to care about the 'SomeItem = K'
//
// We fix the first assumption by manually clearing out all of the InferCtxt's caches
// in between calls to SelectionContext.select. This allows us to keep all of the
// intermediate types we create bound to the 'tcx lifetime, rather than needing to lift
// them between calls.
//
// We fix the second assumption by reprocessing the result of our first call to
// evaluate_predicates. Using the example of '<T as SomeTrait>::SomeItem = K', our first
// pass will pick up 'T: SomeTrait', but not 'SomeItem = K'. On our second pass,
// traits::project will see that 'T: SomeTrait' is in our ParamEnv, allowing
// SelectionContext to return it back to us.
2022-02-18 23:48:31 +00:00
let Some ( ( new_env , user_env ) ) = self . evaluate_predicates (
2020-03-05 13:54:19 +00:00
& infcx ,
2018-04-12 09:58:34 +00:00
trait_did ,
ty ,
2019-04-22 19:52:51 +00:00
orig_env ,
orig_env ,
2018-04-12 09:58:34 +00:00
& mut fresh_preds ,
false ,
2022-02-18 23:48:31 +00:00
) else {
return AutoTraitResult ::NegativeImpl ;
2018-04-12 09:58:34 +00:00
} ;
let ( full_env , full_user_env ) = self
. evaluate_predicates (
2020-03-06 23:19:25 +00:00
& infcx ,
2018-04-12 09:58:34 +00:00
trait_did ,
ty ,
2019-04-22 19:52:51 +00:00
new_env ,
2018-04-12 09:58:34 +00:00
user_env ,
& mut fresh_preds ,
true ,
)
. unwrap_or_else ( | | {
panic! ( " Failed to fully process: {:?} {:?} {:?} " , ty , trait_did , orig_env )
} ) ;
debug! (
2019-04-22 19:52:51 +00:00
" find_auto_trait_generics({:?}): fulfilling \
2018-03-09 21:49:37 +00:00
with { :? } " ,
2019-04-22 19:52:51 +00:00
trait_ref , full_env
2018-04-12 09:58:34 +00:00
) ;
2018-03-09 21:49:37 +00:00
infcx . clear_caches ( ) ;
// At this point, we already have all of the bounds we need. FulfillmentContext is used
// to store all of the necessary region/lifetime bounds in the InferContext, as well as
// an additional sanity check.
let mut fulfill = FulfillmentContext ::new ( ) ;
2020-04-12 17:42:45 +00:00
fulfill . register_bound ( & infcx , full_env , ty , trait_did , ObligationCause ::dummy ( ) ) ;
2021-11-08 15:35:23 +00:00
let errors = fulfill . select_all_or_error ( & infcx ) ;
2021-11-08 15:55:51 +00:00
2021-11-08 15:35:23 +00:00
if ! errors . is_empty ( ) {
panic! ( " Unable to fulfill trait {:?} for ' {:?} ': {:?} " , trait_did , ty , errors ) ;
}
2018-03-09 21:49:37 +00:00
2020-01-30 21:45:57 +00:00
let body_id_map : FxHashMap < _ , _ > = infcx
. inner
. borrow ( )
2020-02-25 13:45:07 +00:00
. region_obligations ( )
2020-01-30 21:45:57 +00:00
. iter ( )
. map ( | & ( id , _ ) | ( id , vec! [ ] ) )
. collect ( ) ;
2018-03-09 21:49:37 +00:00
2022-06-27 13:48:54 +00:00
infcx . process_registered_region_obligations ( & body_id_map , full_env ) ;
2018-03-09 21:49:37 +00:00
2020-01-30 21:45:57 +00:00
let region_data = infcx
. inner
. borrow_mut ( )
. unwrap_region_constraints ( )
. region_constraint_data ( )
. clone ( ) ;
2018-03-09 21:49:37 +00:00
let vid_to_region = self . map_vid_to_region ( & region_data ) ;
2018-04-06 22:25:25 +00:00
let info = AutoTraitInfo { full_user_env , region_data , vid_to_region } ;
2018-03-09 21:49:37 +00:00
2021-02-27 17:13:10 +00:00
AutoTraitResult ::PositiveImpl ( auto_trait_callback ( info ) )
2020-03-20 14:03:11 +00:00
} )
2018-03-09 21:49:37 +00:00
}
2018-04-05 18:10:15 +00:00
}
2018-03-09 21:49:37 +00:00
2021-12-14 09:44:49 +00:00
impl < ' tcx > AutoTraitFinder < ' tcx > {
2019-11-21 18:40:27 +00:00
/// The core logic responsible for computing the bounds for our synthesized impl.
///
/// To calculate the bounds, we call `SelectionContext.select` in a loop. Like
/// `FulfillmentContext`, we recursively select the nested obligations of predicates we
/// encounter. However, whenever we encounter an `UnimplementedError` involving a type
/// parameter, we add it to our `ParamEnv`. Since our goal is to determine when a particular
/// type implements an auto trait, Unimplemented errors tell us what conditions need to be met.
///
/// This method ends up working somewhat similarly to `FulfillmentContext`, but with a few key
/// differences. `FulfillmentContext` works under the assumption that it's dealing with concrete
/// user code. According, it considers all possible ways that a `Predicate` could be met, which
/// isn't always what we want for a synthesized impl. For example, given the predicate `T:
/// Iterator`, `FulfillmentContext` can end up reporting an Unimplemented error for `T:
/// IntoIterator` -- since there's an implementation of `Iterator` where `T: IntoIterator`,
/// `FulfillmentContext` will drive `SelectionContext` to consider that impl before giving up.
/// If we were to rely on `FulfillmentContext`s decision, we might end up synthesizing an impl
/// like this:
2022-04-15 22:04:34 +00:00
/// ```ignore (illustrative)
/// impl<T> Send for Foo<T> where T: IntoIterator
/// ```
2019-11-21 18:40:27 +00:00
/// While it might be technically true that Foo implements Send where `T: IntoIterator`,
/// the bound is overly restrictive - it's really only necessary that `T: Iterator`.
///
/// For this reason, `evaluate_predicates` handles predicates with type variables specially.
/// When we encounter an `Unimplemented` error for a bound such as `T: Iterator`, we immediately
/// add it to our `ParamEnv`, and add it to our stack for recursive evaluation. When we later
/// select it, we'll pick up any nested bounds, without ever inferring that `T: IntoIterator`
/// needs to hold.
///
/// One additional consideration is supertrait bounds. Normally, a `ParamEnv` is only ever
/// constructed once for a given type. As part of the construction process, the `ParamEnv` will
/// have any supertrait bounds normalized -- e.g., if we have a type `struct Foo<T: Copy>`, the
/// `ParamEnv` will contain `T: Copy` and `T: Clone`, since `Copy: Clone`. When we construct our
/// own `ParamEnv`, we need to do this ourselves, through `traits::elaborate_predicates`, or
/// else `SelectionContext` will choke on the missing predicates. However, this should never
/// show up in the final synthesized generics: we don't want our generated docs page to contain
/// something like `T: Copy + Clone`, as that's redundant. Therefore, we keep track of a
/// separate `user_env`, which only holds the predicates that will actually be displayed to the
/// user.
2019-06-13 21:48:52 +00:00
fn evaluate_predicates (
2018-04-12 09:58:34 +00:00
& self ,
2019-06-13 21:48:52 +00:00
infcx : & InferCtxt < '_ , ' tcx > ,
2018-04-12 09:58:34 +00:00
trait_did : DefId ,
2019-06-13 21:48:52 +00:00
ty : Ty < ' tcx > ,
param_env : ty ::ParamEnv < ' tcx > ,
user_env : ty ::ParamEnv < ' tcx > ,
fresh_preds : & mut FxHashSet < ty ::Predicate < ' tcx > > ,
2018-04-12 09:58:34 +00:00
only_projections : bool ,
2019-06-13 21:48:52 +00:00
) -> Option < ( ty ::ParamEnv < ' tcx > , ty ::ParamEnv < ' tcx > ) > {
2018-03-09 21:49:37 +00:00
let tcx = infcx . tcx ;
2022-03-30 05:39:38 +00:00
// Don't try to process any nested obligations involving predicates
2020-08-06 00:19:56 +00:00
// that are already in the `ParamEnv` (modulo regions): we already
// know that they must hold.
for predicate in param_env . caller_bounds ( ) {
fresh_preds . insert ( self . clean_pred ( infcx , predicate ) ) ;
}
2022-03-27 01:01:34 +00:00
let mut select = SelectionContext ::new ( & infcx ) ;
2018-03-09 21:49:37 +00:00
2018-10-16 08:44:26 +00:00
let mut already_visited = FxHashSet ::default ( ) ;
2018-03-09 21:49:37 +00:00
let mut predicates = VecDeque ::new ( ) ;
2021-01-07 05:41:55 +00:00
predicates . push_back ( ty ::Binder ::dummy ( ty ::TraitPredicate {
2018-04-12 09:58:34 +00:00
trait_ref : ty ::TraitRef {
def_id : trait_did ,
substs : infcx . tcx . mk_substs_trait ( ty , & [ ] ) ,
} ,
2021-08-27 05:02:23 +00:00
constness : ty ::BoundConstness ::NotConst ,
2021-10-11 21:10:35 +00:00
// Auto traits are positive
polarity : ty ::ImplPolarity ::Positive ,
2018-04-12 09:58:34 +00:00
} ) ) ;
2018-03-09 21:49:37 +00:00
2020-07-03 00:52:40 +00:00
let computed_preds = param_env . caller_bounds ( ) . iter ( ) ;
let mut user_computed_preds : FxHashSet < _ > = user_env . caller_bounds ( ) . iter ( ) . collect ( ) ;
2018-03-09 21:49:37 +00:00
2019-04-22 19:52:51 +00:00
let mut new_env = param_env ;
2020-04-12 17:42:45 +00:00
let dummy_cause = ObligationCause ::dummy ( ) ;
2018-03-09 21:49:37 +00:00
while let Some ( pred ) = predicates . pop_front ( ) {
infcx . clear_caches ( ) ;
2019-04-22 19:52:51 +00:00
if ! already_visited . insert ( pred ) {
2018-03-09 21:49:37 +00:00
continue ;
}
2019-05-17 01:20:14 +00:00
// Call `infcx.resolve_vars_if_possible` to see if we can
2018-10-24 04:57:09 +00:00
// get rid of any inference variables.
2020-10-24 00:21:18 +00:00
let obligation =
infcx . resolve_vars_if_possible ( Obligation ::new ( dummy_cause . clone ( ) , new_env , pred ) ) ;
2018-10-24 04:57:09 +00:00
let result = select . select ( & obligation ) ;
2018-03-09 21:49:37 +00:00
2021-01-02 19:09:17 +00:00
match result {
Ok ( Some ( ref impl_source ) ) = > {
2019-05-17 01:20:14 +00:00
// If we see an explicit negative impl (e.g., `impl !Send for MyStruct`),
2018-11-08 17:15:26 +00:00
// we immediately bail out, since it's impossible for us to continue.
2020-03-22 12:36:56 +00:00
2020-09-24 17:22:36 +00:00
if let ImplSource ::UserDefined ( ImplSourceUserDefinedData {
impl_def_id , ..
2020-06-02 15:54:24 +00:00
} ) = impl_source
2020-05-11 15:25:33 +00:00
{
2020-03-22 12:36:56 +00:00
// Blame 'tidy' for the weird bracket placement.
if infcx . tcx . impl_polarity ( * impl_def_id ) = = ty ::ImplPolarity ::Negative {
debug! (
" evaluate_nested_obligations: found explicit negative impl \
2018-10-25 19:14:32 +00:00
{ :? } , bailing out " ,
2020-03-22 12:36:56 +00:00
impl_def_id
) ;
return None ;
2018-10-25 19:14:32 +00:00
}
}
2020-05-11 15:25:33 +00:00
let obligations = impl_source . clone ( ) . nested_obligations ( ) . into_iter ( ) ;
2018-03-09 21:49:37 +00:00
2018-04-12 09:58:34 +00:00
if ! self . evaluate_nested_obligations (
ty ,
obligations ,
& mut user_computed_preds ,
fresh_preds ,
& mut predicates ,
& mut select ,
only_projections ,
) {
2018-03-09 21:49:37 +00:00
return None ;
}
}
2021-01-02 19:09:17 +00:00
Ok ( None ) = > { }
Err ( SelectionError ::Unimplemented ) = > {
2018-11-14 21:36:48 +00:00
if self . is_param_no_infer ( pred . skip_binder ( ) . trait_ref . substs ) {
2018-03-09 21:49:37 +00:00
already_visited . remove ( & pred ) ;
2021-07-22 13:56:07 +00:00
self . add_user_pred ( & mut user_computed_preds , pred . to_predicate ( self . tcx ) ) ;
2018-03-09 21:49:37 +00:00
predicates . push_back ( pred ) ;
} else {
2018-04-12 09:58:34 +00:00
debug! (
2019-05-17 01:20:14 +00:00
" evaluate_nested_obligations: `Unimplemented` found, bailing: \
2018-04-06 22:25:25 +00:00
{ :? } { :? } { :? } " ,
2018-04-12 09:58:34 +00:00
ty ,
pred ,
pred . skip_binder ( ) . trait_ref . substs
) ;
2018-03-09 21:49:37 +00:00
return None ;
}
}
_ = > panic! ( " Unexpected error for ' {:?} ': {:?} " , ty , result ) ,
} ;
2020-04-20 17:42:12 +00:00
let normalized_preds = elaborate_predicates (
tcx ,
computed_preds . clone ( ) . chain ( user_computed_preds . iter ( ) . cloned ( ) ) ,
)
. map ( | o | o . predicate ) ;
2021-12-12 04:34:46 +00:00
new_env = ty ::ParamEnv ::new (
tcx . mk_predicates ( normalized_preds ) ,
param_env . reveal ( ) ,
param_env . constness ( ) ,
) ;
2018-03-09 21:49:37 +00:00
}
2018-04-12 09:58:34 +00:00
let final_user_env = ty ::ParamEnv ::new (
tcx . mk_predicates ( user_computed_preds . into_iter ( ) ) ,
2020-07-03 00:52:40 +00:00
user_env . reveal ( ) ,
2021-12-12 04:34:46 +00:00
user_env . constness ( ) ,
2018-04-12 09:58:34 +00:00
) ;
debug! (
2019-04-20 15:27:44 +00:00
" evaluate_nested_obligations(ty={:?}, trait_did={:?}): succeeded with '{:?}' \
2018-03-09 21:49:37 +00:00
' { :? } ' " ,
2019-04-20 15:27:44 +00:00
ty , trait_did , new_env , final_user_env
2018-04-12 09:58:34 +00:00
) ;
2018-03-09 21:49:37 +00:00
2020-03-20 14:03:11 +00:00
Some ( ( new_env , final_user_env ) )
2018-03-09 21:49:37 +00:00
}
2019-11-21 18:40:27 +00:00
/// This method is designed to work around the following issue:
/// When we compute auto trait bounds, we repeatedly call `SelectionContext.select`,
/// progressively building a `ParamEnv` based on the results we get.
/// However, our usage of `SelectionContext` differs from its normal use within the compiler,
/// in that we capture and re-reprocess predicates from `Unimplemented` errors.
///
/// This can lead to a corner case when dealing with region parameters.
/// During our selection loop in `evaluate_predicates`, we might end up with
/// two trait predicates that differ only in their region parameters:
/// one containing a HRTB lifetime parameter, and one containing a 'normal'
/// lifetime parameter. For example:
2022-04-15 22:04:34 +00:00
/// ```ignore (illustrative)
/// T as MyTrait<'a>
/// T as MyTrait<'static>
/// ```
2019-11-21 18:40:27 +00:00
/// If we put both of these predicates in our computed `ParamEnv`, we'll
/// confuse `SelectionContext`, since it will (correctly) view both as being applicable.
///
/// To solve this, we pick the 'more strict' lifetime bound -- i.e., the HRTB
/// Our end goal is to generate a user-visible description of the conditions
/// under which a type implements an auto trait. A trait predicate involving
/// a HRTB means that the type needs to work with any choice of lifetime,
/// not just one specific lifetime (e.g., `'static`).
2020-06-18 18:41:43 +00:00
fn add_user_pred (
2018-09-12 21:34:08 +00:00
& self ,
2020-06-18 18:41:43 +00:00
user_computed_preds : & mut FxHashSet < ty ::Predicate < ' tcx > > ,
new_pred : ty ::Predicate < ' tcx > ,
2018-09-12 21:34:08 +00:00
) {
2018-08-02 17:59:16 +00:00
let mut should_add_new = true ;
user_computed_preds . retain ( | & old_pred | {
2021-07-22 13:56:07 +00:00
if let ( ty ::PredicateKind ::Trait ( new_trait ) , ty ::PredicateKind ::Trait ( old_trait ) ) =
( new_pred . kind ( ) . skip_binder ( ) , old_pred . kind ( ) . skip_binder ( ) )
2020-07-08 22:35:55 +00:00
{
2020-03-22 12:36:56 +00:00
if new_trait . def_id ( ) = = old_trait . def_id ( ) {
2020-06-18 18:41:43 +00:00
let new_substs = new_trait . trait_ref . substs ;
let old_substs = old_trait . trait_ref . substs ;
2020-03-22 12:36:56 +00:00
if ! new_substs . types ( ) . eq ( old_substs . types ( ) ) {
// We can't compare lifetimes if the types are different,
// so skip checking `old_pred`.
return true ;
}
2018-08-02 17:59:16 +00:00
2021-03-08 23:32:41 +00:00
for ( new_region , old_region ) in
iter ::zip ( new_substs . regions ( ) , old_substs . regions ( ) )
{
2022-01-28 00:25:15 +00:00
match ( * new_region , * old_region ) {
2020-03-22 12:36:56 +00:00
// If both predicates have an `ReLateBound` (a HRTB) in the
// same spot, we do nothing.
2022-02-01 01:57:04 +00:00
( ty ::ReLateBound ( _ , _ ) , ty ::ReLateBound ( _ , _ ) ) = > { }
2020-03-22 12:36:56 +00:00
2022-02-01 01:57:04 +00:00
( ty ::ReLateBound ( _ , _ ) , _ ) | ( _ , ty ::ReVar ( _ ) ) = > {
2020-03-22 12:36:56 +00:00
// One of these is true:
// The new predicate has a HRTB in a spot where the old
// predicate does not (if they both had a HRTB, the previous
// match arm would have executed). A HRBT is a 'stricter'
// bound than anything else, so we want to keep the newer
// predicate (with the HRBT) in place of the old predicate.
//
// OR
//
// The old predicate has a region variable where the new
// predicate has some other kind of region. An region
// variable isn't something we can actually display to a user,
// so we choose their new predicate (which doesn't have a region
// variable).
//
// In both cases, we want to remove the old predicate,
// from `user_computed_preds`, and replace it with the new
// one. Having both the old and the new
// predicate in a `ParamEnv` would confuse `SelectionContext`.
//
// We're currently in the predicate passed to 'retain',
// so we return `false` to remove the old predicate from
// `user_computed_preds`.
return false ;
}
2022-02-01 01:57:04 +00:00
( _ , ty ::ReLateBound ( _ , _ ) ) | ( ty ::ReVar ( _ ) , _ ) = > {
2020-03-22 12:36:56 +00:00
// This is the opposite situation as the previous arm.
// One of these is true:
//
// The old predicate has a HRTB lifetime in a place where the
// new predicate does not.
//
// OR
//
// The new predicate has a region variable where the old
// predicate has some other type of region.
//
// We want to leave the old
// predicate in `user_computed_preds`, and skip adding
// new_pred to `user_computed_params`.
should_add_new = false
2018-08-02 17:59:16 +00:00
}
2020-03-22 12:36:56 +00:00
_ = > { }
2018-08-02 17:59:16 +00:00
}
}
2018-09-12 21:34:08 +00:00
}
2018-08-02 17:59:16 +00:00
}
2020-03-20 14:03:11 +00:00
true
2018-08-02 17:59:16 +00:00
} ) ;
if should_add_new {
user_computed_preds . insert ( new_pred ) ;
}
}
2019-11-21 18:40:27 +00:00
/// This is very similar to `handle_lifetimes`. However, instead of matching `ty::Region`s
/// to each other, we match `ty::RegionVid`s to `ty::Region`s.
2019-04-22 19:52:51 +00:00
fn map_vid_to_region < ' cx > (
2018-04-12 09:58:34 +00:00
& self ,
regions : & RegionConstraintData < ' cx > ,
) -> FxHashMap < ty ::RegionVid , ty ::Region < ' cx > > {
2018-10-16 08:44:26 +00:00
let mut vid_map : FxHashMap < RegionTarget < ' cx > , RegionDeps < ' cx > > = FxHashMap ::default ( ) ;
let mut finished_map = FxHashMap ::default ( ) ;
2018-03-09 21:49:37 +00:00
for constraint in regions . constraints . keys ( ) {
match constraint {
& Constraint ::VarSubVar ( r1 , r2 ) = > {
{
2018-09-12 21:34:08 +00:00
let deps1 = vid_map . entry ( RegionTarget ::RegionVid ( r1 ) ) . or_default ( ) ;
2018-03-09 21:49:37 +00:00
deps1 . larger . insert ( RegionTarget ::RegionVid ( r2 ) ) ;
}
2018-09-12 21:34:08 +00:00
let deps2 = vid_map . entry ( RegionTarget ::RegionVid ( r2 ) ) . or_default ( ) ;
2018-03-09 21:49:37 +00:00
deps2 . smaller . insert ( RegionTarget ::RegionVid ( r1 ) ) ;
}
& Constraint ::RegSubVar ( region , vid ) = > {
{
2018-09-12 21:34:08 +00:00
let deps1 = vid_map . entry ( RegionTarget ::Region ( region ) ) . or_default ( ) ;
2018-03-09 21:49:37 +00:00
deps1 . larger . insert ( RegionTarget ::RegionVid ( vid ) ) ;
}
2018-09-12 21:34:08 +00:00
let deps2 = vid_map . entry ( RegionTarget ::RegionVid ( vid ) ) . or_default ( ) ;
2018-03-09 21:49:37 +00:00
deps2 . smaller . insert ( RegionTarget ::Region ( region ) ) ;
}
& Constraint ::VarSubReg ( vid , region ) = > {
finished_map . insert ( vid , region ) ;
}
& Constraint ::RegSubReg ( r1 , r2 ) = > {
{
2018-09-12 21:34:08 +00:00
let deps1 = vid_map . entry ( RegionTarget ::Region ( r1 ) ) . or_default ( ) ;
2018-03-09 21:49:37 +00:00
deps1 . larger . insert ( RegionTarget ::Region ( r2 ) ) ;
}
2018-09-12 21:34:08 +00:00
let deps2 = vid_map . entry ( RegionTarget ::Region ( r2 ) ) . or_default ( ) ;
2018-03-09 21:49:37 +00:00
deps2 . smaller . insert ( RegionTarget ::Region ( r1 ) ) ;
}
}
}
while ! vid_map . is_empty ( ) {
2020-01-22 15:30:15 +00:00
let target = * vid_map . keys ( ) . next ( ) . expect ( " Keys somehow empty " ) ;
2018-03-09 21:49:37 +00:00
let deps = vid_map . remove ( & target ) . expect ( " Entry somehow missing " ) ;
for smaller in deps . smaller . iter ( ) {
for larger in deps . larger . iter ( ) {
match ( smaller , larger ) {
( & RegionTarget ::Region ( _ ) , & RegionTarget ::Region ( _ ) ) = > {
if let Entry ::Occupied ( v ) = vid_map . entry ( * smaller ) {
let smaller_deps = v . into_mut ( ) ;
smaller_deps . larger . insert ( * larger ) ;
smaller_deps . larger . remove ( & target ) ;
}
if let Entry ::Occupied ( v ) = vid_map . entry ( * larger ) {
let larger_deps = v . into_mut ( ) ;
larger_deps . smaller . insert ( * smaller ) ;
larger_deps . smaller . remove ( & target ) ;
}
}
( & RegionTarget ::RegionVid ( v1 ) , & RegionTarget ::Region ( r1 ) ) = > {
finished_map . insert ( v1 , r1 ) ;
}
( & RegionTarget ::Region ( _ ) , & RegionTarget ::RegionVid ( _ ) ) = > {
2019-05-17 01:20:14 +00:00
// Do nothing; we don't care about regions that are smaller than vids.
2018-03-09 21:49:37 +00:00
}
( & RegionTarget ::RegionVid ( _ ) , & RegionTarget ::RegionVid ( _ ) ) = > {
if let Entry ::Occupied ( v ) = vid_map . entry ( * smaller ) {
let smaller_deps = v . into_mut ( ) ;
smaller_deps . larger . insert ( * larger ) ;
smaller_deps . larger . remove ( & target ) ;
}
if let Entry ::Occupied ( v ) = vid_map . entry ( * larger ) {
let larger_deps = v . into_mut ( ) ;
larger_deps . smaller . insert ( * smaller ) ;
larger_deps . smaller . remove ( & target ) ;
}
}
}
}
}
}
finished_map
}
2019-02-26 01:30:34 +00:00
fn is_param_no_infer ( & self , substs : SubstsRef < '_ > ) -> bool {
2020-03-20 14:03:11 +00:00
self . is_of_param ( substs . type_at ( 0 ) ) & & ! substs . types ( ) . any ( | t | t . has_infer_types ( ) )
2018-11-14 21:36:48 +00:00
}
2018-10-24 04:57:09 +00:00
pub fn is_of_param ( & self , ty : Ty < '_ > ) -> bool {
2020-08-02 22:49:11 +00:00
match ty . kind ( ) {
2018-08-22 00:35:29 +00:00
ty ::Param ( _ ) = > true ,
2018-10-24 04:57:09 +00:00
ty ::Projection ( p ) = > self . is_of_param ( p . self_ty ( ) ) ,
2018-04-12 09:58:34 +00:00
_ = > false ,
2020-03-20 14:03:11 +00:00
}
2018-03-09 21:49:37 +00:00
}
2018-11-29 02:15:06 +00:00
fn is_self_referential_projection ( & self , p : ty ::PolyProjectionPredicate < '_ > ) -> bool {
2022-01-10 23:39:21 +00:00
if let Term ::Ty ( ty ) = p . term ( ) . skip_binder ( ) {
matches! ( ty . kind ( ) , ty ::Projection ( proj ) if proj = = & p . skip_binder ( ) . projection_ty )
} else {
false
}
2018-11-29 02:15:06 +00:00
}
2019-06-13 21:48:52 +00:00
fn evaluate_nested_obligations (
2018-04-12 09:58:34 +00:00
& self ,
2019-04-25 20:54:19 +00:00
ty : Ty < '_ > ,
2019-06-13 21:48:52 +00:00
nested : impl Iterator < Item = Obligation < ' tcx , ty ::Predicate < ' tcx > > > ,
computed_preds : & mut FxHashSet < ty ::Predicate < ' tcx > > ,
fresh_preds : & mut FxHashSet < ty ::Predicate < ' tcx > > ,
predicates : & mut VecDeque < ty ::PolyTraitPredicate < ' tcx > > ,
select : & mut SelectionContext < '_ , ' tcx > ,
2018-04-12 09:58:34 +00:00
only_projections : bool ,
) -> bool {
2020-04-12 17:42:45 +00:00
let dummy_cause = ObligationCause ::dummy ( ) ;
2018-03-09 21:49:37 +00:00
2020-06-18 18:41:43 +00:00
for obligation in nested {
let is_new_pred =
fresh_preds . insert ( self . clean_pred ( select . infcx ( ) , obligation . predicate ) ) ;
2018-03-09 21:49:37 +00:00
2018-10-24 04:57:09 +00:00
// Resolve any inference variables that we can, to help selection succeed
2020-10-24 00:21:18 +00:00
let predicate = select . infcx ( ) . resolve_vars_if_possible ( obligation . predicate ) ;
2018-10-24 04:57:09 +00:00
// We only add a predicate as a user-displayable bound if
// it involves a generic parameter, and doesn't contain
// any inference variables.
//
// Displaying a bound involving a concrete type (instead of a generic
// parameter) would be pointless, since it's always true
// (e.g. u8: Copy)
// Displaying an inference variable is impossible, since they're
// an internal compiler detail without a defined visual representation
//
// We check this by calling is_of_param on the relevant types
// from the various possible predicates
2020-06-18 18:41:43 +00:00
2021-01-07 16:20:28 +00:00
let bound_predicate = predicate . kind ( ) ;
2020-10-08 00:02:06 +00:00
match bound_predicate . skip_binder ( ) {
2021-07-22 13:56:07 +00:00
ty ::PredicateKind ::Trait ( p ) = > {
2020-12-21 02:07:13 +00:00
// Add this to `predicates` so that we end up calling `select`
// with it. If this predicate ends up being unimplemented,
// then `evaluate_predicates` will handle adding it the `ParamEnv`
// if possible.
2020-10-16 18:04:11 +00:00
predicates . push_back ( bound_predicate . rebind ( p ) ) ;
2018-03-09 21:49:37 +00:00
}
2021-01-07 16:20:28 +00:00
ty ::PredicateKind ::Projection ( p ) = > {
2020-10-16 18:04:11 +00:00
let p = bound_predicate . rebind ( p ) ;
2018-10-24 04:57:09 +00:00
debug! (
" evaluate_nested_obligations: examining projection predicate {:?} " ,
predicate
) ;
// As described above, we only want to display
// bounds which include a generic parameter but don't include
// an inference variable.
// Additionally, we check if we've seen this predicate before,
// to avoid rendering duplicate bounds to the user.
2018-11-14 21:36:48 +00:00
if self . is_param_no_infer ( p . skip_binder ( ) . projection_ty . substs )
2022-01-10 23:39:21 +00:00
& & ! p . term ( ) . skip_binder ( ) . has_infer_types ( )
2018-10-24 04:57:09 +00:00
& & is_new_pred
{
debug! (
2022-03-30 05:42:10 +00:00
" evaluate_nested_obligations: adding projection predicate \
2018-10-24 04:57:09 +00:00
to computed_preds : { :? } " ,
predicate
) ;
2019-12-22 22:42:04 +00:00
2022-03-30 05:39:38 +00:00
// Under unusual circumstances, we can end up with a self-referential
2018-11-29 02:15:06 +00:00
// projection predicate. For example:
// <T as MyType>::Value == <T as MyType>::Value
// Not only is displaying this to the user pointless,
// having it in the ParamEnv will cause an issue if we try to call
// poly_project_and_unify_type on the predicate, since this kind of
// predicate will normally never end up in a ParamEnv.
//
// For these reasons, we ignore these weird predicates,
// ensuring that we're able to properly synthesize an auto trait impl
if self . is_self_referential_projection ( p ) {
debug! (
" evaluate_nested_obligations: encountered a projection
predicate equating a type with itself ! Skipping "
) ;
} else {
self . add_user_pred ( computed_preds , predicate ) ;
}
2018-10-24 04:57:09 +00:00
}
Always try to project predicates when finding auto traits in rustdoc
Fixes #60726
Previous, AutoTraitFinder would only try to project predicates when the
predicate type contained an inference variable. When finding auto
traits, we only project to try to unify inference variables - we don't
otherwise learn any new information about the required bounds.
However, this lead to failing to properly generate a negative auto trait
impl (indicating that a type never implements a certain auto trait) in
the following unusual scenario:
In almost all cases, a type has an (implicit) negative impl of an auto
trait due some other type having an explicit *negative* impl of that
auto trait. For example:
struct MyType<T> {
field: *const T
}
has an implicit 'impl<T> !Send for MyType<T>', due to the explicit
negative impl (in libcore) 'impl<T: ?Sized> !Send for *const T'.
However, as exposed by the 'abi_stable' crate, this isn't always the
case. This minimzed example shows how a type can never implement
'Send', due to a projection error:
```
pub struct True;
pub struct False;
pub trait MyTrait {
type Project;
}
pub struct MyStruct<T> {
field: T
}
impl MyTrait for u8 {
type Project = False;
}
unsafe impl<T> Send for MyStruct<T>
where T: MyTrait<Project=True> {}
pub struct Wrapper {
inner: MyStruct<u8>
}
```
In this example, `<u8 as MyTrait>::Project == True'
must hold for 'MyStruct<u8>: Send' to hold.
However, '<u8 as MyTrait>::Project == False' holds instead
To properly account for this unusual case, we need to call
'poly_project_and_unify' on *all* predicates, not just those with
inference variables. This ensures that we catch the projection error
that occurs above, and don't incorrectly determine that 'Wrapper: Send'
holds.
2019-05-13 05:37:04 +00:00
// There are three possible cases when we project a predicate:
//
// 1. We encounter an error. This means that it's impossible for
// our current type to implement the auto trait - there's bound
// that we could add to our ParamEnv that would 'fix' this kind
// of error, as it's not caused by an unimplemented type.
//
2019-11-27 03:19:54 +00:00
// 2. We successfully project the predicate (Ok(Some(_))), generating
Always try to project predicates when finding auto traits in rustdoc
Fixes #60726
Previous, AutoTraitFinder would only try to project predicates when the
predicate type contained an inference variable. When finding auto
traits, we only project to try to unify inference variables - we don't
otherwise learn any new information about the required bounds.
However, this lead to failing to properly generate a negative auto trait
impl (indicating that a type never implements a certain auto trait) in
the following unusual scenario:
In almost all cases, a type has an (implicit) negative impl of an auto
trait due some other type having an explicit *negative* impl of that
auto trait. For example:
struct MyType<T> {
field: *const T
}
has an implicit 'impl<T> !Send for MyType<T>', due to the explicit
negative impl (in libcore) 'impl<T: ?Sized> !Send for *const T'.
However, as exposed by the 'abi_stable' crate, this isn't always the
case. This minimzed example shows how a type can never implement
'Send', due to a projection error:
```
pub struct True;
pub struct False;
pub trait MyTrait {
type Project;
}
pub struct MyStruct<T> {
field: T
}
impl MyTrait for u8 {
type Project = False;
}
unsafe impl<T> Send for MyStruct<T>
where T: MyTrait<Project=True> {}
pub struct Wrapper {
inner: MyStruct<u8>
}
```
In this example, `<u8 as MyTrait>::Project == True'
must hold for 'MyStruct<u8>: Send' to hold.
However, '<u8 as MyTrait>::Project == False' holds instead
To properly account for this unusual case, we need to call
'poly_project_and_unify' on *all* predicates, not just those with
inference variables. This ensures that we catch the projection error
that occurs above, and don't incorrectly determine that 'Wrapper: Send'
holds.
2019-05-13 05:37:04 +00:00
// some subobligations. We then process these subobligations
// like any other generated sub-obligations.
//
2020-03-06 11:13:55 +00:00
// 3. We receive an 'ambiguous' result (Ok(None))
Always try to project predicates when finding auto traits in rustdoc
Fixes #60726
Previous, AutoTraitFinder would only try to project predicates when the
predicate type contained an inference variable. When finding auto
traits, we only project to try to unify inference variables - we don't
otherwise learn any new information about the required bounds.
However, this lead to failing to properly generate a negative auto trait
impl (indicating that a type never implements a certain auto trait) in
the following unusual scenario:
In almost all cases, a type has an (implicit) negative impl of an auto
trait due some other type having an explicit *negative* impl of that
auto trait. For example:
struct MyType<T> {
field: *const T
}
has an implicit 'impl<T> !Send for MyType<T>', due to the explicit
negative impl (in libcore) 'impl<T: ?Sized> !Send for *const T'.
However, as exposed by the 'abi_stable' crate, this isn't always the
case. This minimzed example shows how a type can never implement
'Send', due to a projection error:
```
pub struct True;
pub struct False;
pub trait MyTrait {
type Project;
}
pub struct MyStruct<T> {
field: T
}
impl MyTrait for u8 {
type Project = False;
}
unsafe impl<T> Send for MyStruct<T>
where T: MyTrait<Project=True> {}
pub struct Wrapper {
inner: MyStruct<u8>
}
```
In this example, `<u8 as MyTrait>::Project == True'
must hold for 'MyStruct<u8>: Send' to hold.
However, '<u8 as MyTrait>::Project == False' holds instead
To properly account for this unusual case, we need to call
'poly_project_and_unify' on *all* predicates, not just those with
inference variables. This ensures that we catch the projection error
that occurs above, and don't incorrectly determine that 'Wrapper: Send'
holds.
2019-05-13 05:37:04 +00:00
// If we were actually trying to compile a crate,
// we would need to re-process this obligation later.
// However, all we care about is finding out what bounds
// are needed for our type to implement a particular auto trait.
// We've already added this obligation to our computed ParamEnv
// above (if it was necessary). Therefore, we don't need
// to do any further processing of the obligation.
//
// Note that we *must* try to project *all* projection predicates
// we encounter, even ones without inference variable.
// This ensures that we detect any projection errors,
// which indicate that our type can *never* implement the given
// auto trait. In that case, we will generate an explicit negative
// impl (e.g. 'impl !Send for MyType'). However, we don't
// try to process any of the generated subobligations -
// they contain no new information, since we already know
// that our type implements the projected-through trait,
// and can lead to weird region issues.
//
// Normally, we'll generate a negative impl as a result of encountering
// a type with an explicit negative impl of an auto trait
// (for example, raw pointers have !Send and !Sync impls)
// However, through some **interesting** manipulations of the type
// system, it's actually possible to write a type that never
// implements an auto trait due to a projection error, not a normal
// negative impl error. To properly handle this case, we need
// to ensure that we catch any potential projection errors,
// and turn them into an explicit negative impl for our type.
debug! ( " Projecting and unifying projection predicate {:?} " , predicate ) ;
2020-08-13 19:45:08 +00:00
match project ::poly_project_and_unify_type ( select , & obligation . with ( p ) ) {
2022-03-11 23:46:49 +00:00
ProjectAndUnifyResult ::MismatchedProjectionTypes ( e ) = > {
Always try to project predicates when finding auto traits in rustdoc
Fixes #60726
Previous, AutoTraitFinder would only try to project predicates when the
predicate type contained an inference variable. When finding auto
traits, we only project to try to unify inference variables - we don't
otherwise learn any new information about the required bounds.
However, this lead to failing to properly generate a negative auto trait
impl (indicating that a type never implements a certain auto trait) in
the following unusual scenario:
In almost all cases, a type has an (implicit) negative impl of an auto
trait due some other type having an explicit *negative* impl of that
auto trait. For example:
struct MyType<T> {
field: *const T
}
has an implicit 'impl<T> !Send for MyType<T>', due to the explicit
negative impl (in libcore) 'impl<T: ?Sized> !Send for *const T'.
However, as exposed by the 'abi_stable' crate, this isn't always the
case. This minimzed example shows how a type can never implement
'Send', due to a projection error:
```
pub struct True;
pub struct False;
pub trait MyTrait {
type Project;
}
pub struct MyStruct<T> {
field: T
}
impl MyTrait for u8 {
type Project = False;
}
unsafe impl<T> Send for MyStruct<T>
where T: MyTrait<Project=True> {}
pub struct Wrapper {
inner: MyStruct<u8>
}
```
In this example, `<u8 as MyTrait>::Project == True'
must hold for 'MyStruct<u8>: Send' to hold.
However, '<u8 as MyTrait>::Project == False' holds instead
To properly account for this unusual case, we need to call
'poly_project_and_unify' on *all* predicates, not just those with
inference variables. This ensures that we catch the projection error
that occurs above, and don't incorrectly determine that 'Wrapper: Send'
holds.
2019-05-13 05:37:04 +00:00
debug! (
" evaluate_nested_obligations: Unable to unify predicate \
' { :? } ' ' { :? } ' , bailing out " ,
ty , e
) ;
return false ;
}
2022-03-11 23:46:49 +00:00
ProjectAndUnifyResult ::Recursive = > {
2020-08-13 19:45:08 +00:00
debug! ( " evaluate_nested_obligations: recursive projection predicate " ) ;
return false ;
}
2022-03-11 23:46:49 +00:00
ProjectAndUnifyResult ::Holds ( v ) = > {
Always try to project predicates when finding auto traits in rustdoc
Fixes #60726
Previous, AutoTraitFinder would only try to project predicates when the
predicate type contained an inference variable. When finding auto
traits, we only project to try to unify inference variables - we don't
otherwise learn any new information about the required bounds.
However, this lead to failing to properly generate a negative auto trait
impl (indicating that a type never implements a certain auto trait) in
the following unusual scenario:
In almost all cases, a type has an (implicit) negative impl of an auto
trait due some other type having an explicit *negative* impl of that
auto trait. For example:
struct MyType<T> {
field: *const T
}
has an implicit 'impl<T> !Send for MyType<T>', due to the explicit
negative impl (in libcore) 'impl<T: ?Sized> !Send for *const T'.
However, as exposed by the 'abi_stable' crate, this isn't always the
case. This minimzed example shows how a type can never implement
'Send', due to a projection error:
```
pub struct True;
pub struct False;
pub trait MyTrait {
type Project;
}
pub struct MyStruct<T> {
field: T
}
impl MyTrait for u8 {
type Project = False;
}
unsafe impl<T> Send for MyStruct<T>
where T: MyTrait<Project=True> {}
pub struct Wrapper {
inner: MyStruct<u8>
}
```
In this example, `<u8 as MyTrait>::Project == True'
must hold for 'MyStruct<u8>: Send' to hold.
However, '<u8 as MyTrait>::Project == False' holds instead
To properly account for this unusual case, we need to call
'poly_project_and_unify' on *all* predicates, not just those with
inference variables. This ensures that we catch the projection error
that occurs above, and don't incorrectly determine that 'Wrapper: Send'
holds.
2019-05-13 05:37:04 +00:00
// We only care about sub-obligations
// when we started out trying to unify
// some inference variables. See the comment above
2022-03-30 05:39:38 +00:00
// for more information
2022-01-14 19:01:35 +00:00
if p . term ( ) . skip_binder ( ) . has_infer_types ( ) {
2018-04-12 09:58:34 +00:00
if ! self . evaluate_nested_obligations (
ty ,
2020-04-20 17:42:12 +00:00
v . into_iter ( ) ,
2018-04-12 09:58:34 +00:00
computed_preds ,
fresh_preds ,
predicates ,
select ,
only_projections ,
) {
2018-03-09 21:49:37 +00:00
return false ;
}
}
Always try to project predicates when finding auto traits in rustdoc
Fixes #60726
Previous, AutoTraitFinder would only try to project predicates when the
predicate type contained an inference variable. When finding auto
traits, we only project to try to unify inference variables - we don't
otherwise learn any new information about the required bounds.
However, this lead to failing to properly generate a negative auto trait
impl (indicating that a type never implements a certain auto trait) in
the following unusual scenario:
In almost all cases, a type has an (implicit) negative impl of an auto
trait due some other type having an explicit *negative* impl of that
auto trait. For example:
struct MyType<T> {
field: *const T
}
has an implicit 'impl<T> !Send for MyType<T>', due to the explicit
negative impl (in libcore) 'impl<T: ?Sized> !Send for *const T'.
However, as exposed by the 'abi_stable' crate, this isn't always the
case. This minimzed example shows how a type can never implement
'Send', due to a projection error:
```
pub struct True;
pub struct False;
pub trait MyTrait {
type Project;
}
pub struct MyStruct<T> {
field: T
}
impl MyTrait for u8 {
type Project = False;
}
unsafe impl<T> Send for MyStruct<T>
where T: MyTrait<Project=True> {}
pub struct Wrapper {
inner: MyStruct<u8>
}
```
In this example, `<u8 as MyTrait>::Project == True'
must hold for 'MyStruct<u8>: Send' to hold.
However, '<u8 as MyTrait>::Project == False' holds instead
To properly account for this unusual case, we need to call
'poly_project_and_unify' on *all* predicates, not just those with
inference variables. This ensures that we catch the projection error
that occurs above, and don't incorrectly determine that 'Wrapper: Send'
holds.
2019-05-13 05:37:04 +00:00
}
2022-03-11 23:46:49 +00:00
ProjectAndUnifyResult ::FailedNormalization = > {
2020-06-19 17:19:21 +00:00
// It's ok not to make progress when have no inference variables -
2022-03-30 05:39:38 +00:00
// in that case, we were only performing unification to check if an
2019-11-27 03:19:54 +00:00
// error occurred (which would indicate that it's impossible for our
Always try to project predicates when finding auto traits in rustdoc
Fixes #60726
Previous, AutoTraitFinder would only try to project predicates when the
predicate type contained an inference variable. When finding auto
traits, we only project to try to unify inference variables - we don't
otherwise learn any new information about the required bounds.
However, this lead to failing to properly generate a negative auto trait
impl (indicating that a type never implements a certain auto trait) in
the following unusual scenario:
In almost all cases, a type has an (implicit) negative impl of an auto
trait due some other type having an explicit *negative* impl of that
auto trait. For example:
struct MyType<T> {
field: *const T
}
has an implicit 'impl<T> !Send for MyType<T>', due to the explicit
negative impl (in libcore) 'impl<T: ?Sized> !Send for *const T'.
However, as exposed by the 'abi_stable' crate, this isn't always the
case. This minimzed example shows how a type can never implement
'Send', due to a projection error:
```
pub struct True;
pub struct False;
pub trait MyTrait {
type Project;
}
pub struct MyStruct<T> {
field: T
}
impl MyTrait for u8 {
type Project = False;
}
unsafe impl<T> Send for MyStruct<T>
where T: MyTrait<Project=True> {}
pub struct Wrapper {
inner: MyStruct<u8>
}
```
In this example, `<u8 as MyTrait>::Project == True'
must hold for 'MyStruct<u8>: Send' to hold.
However, '<u8 as MyTrait>::Project == False' holds instead
To properly account for this unusual case, we need to call
'poly_project_and_unify' on *all* predicates, not just those with
inference variables. This ensures that we catch the projection error
that occurs above, and don't incorrectly determine that 'Wrapper: Send'
holds.
2019-05-13 05:37:04 +00:00
// type to implement the auto trait).
// However, we should always make progress (either by generating
// subobligations or getting an error) when we started off with
// inference variables
2022-01-13 07:39:58 +00:00
if p . term ( ) . skip_binder ( ) . has_infer_types ( ) {
2018-03-09 21:49:37 +00:00
panic! ( " Unexpected result when selecting {:?} {:?} " , ty , obligation )
}
}
}
}
2021-01-07 16:20:28 +00:00
ty ::PredicateKind ::RegionOutlives ( binder ) = > {
2020-10-16 18:04:11 +00:00
let binder = bound_predicate . rebind ( binder ) ;
2019-02-20 10:22:23 +00:00
if select . infcx ( ) . region_outlives_predicate ( & dummy_cause , binder ) . is_err ( ) {
return false ;
}
2018-03-09 21:49:37 +00:00
}
2021-01-07 16:20:28 +00:00
ty ::PredicateKind ::TypeOutlives ( binder ) = > {
2020-10-16 18:04:11 +00:00
let binder = bound_predicate . rebind ( binder ) ;
2018-04-12 09:58:34 +00:00
match (
2018-10-24 20:30:34 +00:00
binder . no_bound_vars ( ) ,
binder . map_bound_ref ( | pred | pred . 0 ) . no_bound_vars ( ) ,
2018-04-12 09:58:34 +00:00
) {
2018-03-09 21:49:37 +00:00
( None , Some ( t_a ) ) = > {
2018-09-12 21:28:47 +00:00
select . infcx ( ) . register_region_obligation_with_cause (
t_a ,
2019-04-25 21:05:04 +00:00
select . infcx ( ) . tcx . lifetimes . re_static ,
2018-09-12 21:28:47 +00:00
& dummy_cause ,
2018-04-12 09:58:34 +00:00
) ;
2018-03-09 21:49:37 +00:00
}
( Some ( ty ::OutlivesPredicate ( t_a , r_b ) ) , _ ) = > {
2018-09-12 21:28:47 +00:00
select . infcx ( ) . register_region_obligation_with_cause (
t_a ,
r_b ,
& dummy_cause ,
2018-04-12 09:58:34 +00:00
) ;
2018-03-09 21:49:37 +00:00
}
_ = > { }
} ;
}
2021-01-07 16:20:28 +00:00
ty ::PredicateKind ::ConstEquate ( c1 , c2 ) = > {
2022-02-02 03:24:45 +00:00
let evaluate = | c : ty ::Const < ' tcx > | {
2022-06-10 01:18:06 +00:00
if let ty ::ConstKind ::Unevaluated ( unevaluated ) = c . kind ( ) {
2020-07-28 22:00:55 +00:00
match select . infcx ( ) . const_eval_resolve (
obligation . param_env ,
2021-03-13 15:31:38 +00:00
unevaluated ,
2020-07-28 22:00:55 +00:00
Some ( obligation . cause . span ) ,
) {
2022-02-16 09:56:01 +00:00
Ok ( Some ( valtree ) ) = > {
Ok ( ty ::Const ::from_value ( select . tcx ( ) , valtree , c . ty ( ) ) )
}
Ok ( None ) = > {
let tcx = self . tcx ;
let def_id = unevaluated . def . did ;
let reported = tcx . sess . struct_span_err ( tcx . def_span ( def_id ) , & format! ( " unable to construct a constant value for the unevaluated constant {:?} " , unevaluated ) ) . emit ( ) ;
Err ( ErrorHandled ::Reported ( reported ) )
}
2020-07-28 22:00:55 +00:00
Err ( err ) = > Err ( err ) ,
}
} else {
Ok ( c )
}
} ;
match ( evaluate ( c1 ) , evaluate ( c2 ) ) {
( Ok ( c1 ) , Ok ( c2 ) ) = > {
match select
. infcx ( )
. at ( & obligation . cause , obligation . param_env )
. eq ( c1 , c2 )
{
Ok ( _ ) = > ( ) ,
Err ( _ ) = > return false ,
}
}
_ = > return false ,
}
}
2021-12-18 16:25:05 +00:00
// There's not really much we can do with these predicates -
// we start out with a `ParamEnv` with no inference variables,
// and these don't correspond to adding any new bounds to
// the `ParamEnv`.
ty ::PredicateKind ::WellFormed ( .. )
| ty ::PredicateKind ::ObjectSafe ( .. )
| ty ::PredicateKind ::ClosureKind ( .. )
| ty ::PredicateKind ::Subtype ( .. )
| ty ::PredicateKind ::ConstEvaluatable ( .. )
| ty ::PredicateKind ::Coerce ( .. )
| ty ::PredicateKind ::TypeWellFormedFromEnv ( .. ) = > { }
2018-03-09 21:49:37 +00:00
} ;
}
2020-03-20 14:03:11 +00:00
true
2018-03-09 21:49:37 +00:00
}
2019-06-13 21:48:52 +00:00
pub fn clean_pred (
2018-04-12 09:58:34 +00:00
& self ,
2019-06-13 21:48:52 +00:00
infcx : & InferCtxt < '_ , ' tcx > ,
p : ty ::Predicate < ' tcx > ,
) -> ty ::Predicate < ' tcx > {
2018-03-09 21:49:37 +00:00
infcx . freshen ( p )
}
}
// Replaces all ReVars in a type with ty::Region's, using the provided map
2019-06-13 21:48:52 +00:00
pub struct RegionReplacer < ' a , ' tcx > {
2018-03-09 21:49:37 +00:00
vid_to_region : & ' a FxHashMap < ty ::RegionVid , ty ::Region < ' tcx > > ,
2019-06-13 21:48:52 +00:00
tcx : TyCtxt < ' tcx > ,
2018-03-09 21:49:37 +00:00
}
2019-06-13 21:48:52 +00:00
impl < ' a , ' tcx > TypeFolder < ' tcx > for RegionReplacer < ' a , ' tcx > {
fn tcx < ' b > ( & ' b self ) -> TyCtxt < ' tcx > {
2018-03-09 21:49:37 +00:00
self . tcx
}
2021-12-01 00:55:57 +00:00
fn fold_region ( & mut self , r : ty ::Region < ' tcx > ) -> ty ::Region < ' tcx > {
2022-01-28 00:25:15 +00:00
( match * r {
ty ::ReVar ( vid ) = > self . vid_to_region . get ( & vid ) . cloned ( ) ,
2018-04-12 09:58:34 +00:00
_ = > None ,
} )
2021-12-01 00:55:57 +00:00
. unwrap_or_else ( | | r . super_fold_with ( self ) )
2018-03-09 21:49:37 +00:00
}
}