mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Correctly handle normalization in implied bounds
Special-case Bevy dependents to not error
This commit is contained in:
parent
6ae4cfbbb0
commit
d96003dd2a
@ -368,7 +368,7 @@ fn check_opaque_meets_bounds<'tcx>(
|
||||
// Can have different predicates to their defining use
|
||||
hir::OpaqueTyOrigin::TyAlias { .. } => {
|
||||
let wf_tys = ocx.assumed_wf_types_and_report_errors(param_env, def_id)?;
|
||||
let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, wf_tys);
|
||||
let implied_bounds = infcx.implied_bounds_tys_compat(param_env, def_id, &wf_tys);
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||
ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?;
|
||||
}
|
||||
|
@ -378,7 +378,7 @@ fn compare_method_predicate_entailment<'tcx>(
|
||||
// lifetime parameters.
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(
|
||||
param_env,
|
||||
infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys),
|
||||
infcx.implied_bounds_tys_compat(param_env, impl_m_def_id, &wf_tys),
|
||||
);
|
||||
let errors = infcx.resolve_regions(&outlives_env);
|
||||
if !errors.is_empty() {
|
||||
@ -702,7 +702,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
||||
// lifetime parameters.
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(
|
||||
param_env,
|
||||
infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys),
|
||||
infcx.implied_bounds_tys_compat(param_env, impl_m_def_id, &wf_tys),
|
||||
);
|
||||
ocx.resolve_regions_and_report_errors(impl_m_def_id, &outlives_env)?;
|
||||
|
||||
@ -2070,7 +2070,8 @@ pub(super) fn check_type_bounds<'tcx>(
|
||||
|
||||
// Finally, resolve all regions. This catches wily misuses of
|
||||
// lifetime parameters.
|
||||
let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_def_id, assumed_wf_types);
|
||||
let implied_bounds =
|
||||
infcx.implied_bounds_tys_compat(param_env, impl_ty_def_id, &assumed_wf_types);
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||
ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env)
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
|
||||
}
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(
|
||||
param_env,
|
||||
infcx.implied_bounds_tys(param_env, impl_m.def_id.expect_local(), implied_wf_types),
|
||||
infcx.implied_bounds_tys_compat(param_env, impl_m.def_id.expect_local(), &implied_wf_types),
|
||||
);
|
||||
let errors = infcx.resolve_regions(&outlives_env);
|
||||
if !errors.is_empty() {
|
||||
|
@ -15,6 +15,7 @@ use rustc_infer::infer::outlives::obligations::TypeOutlives;
|
||||
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::trait_def::TraitSpecializationKind;
|
||||
use rustc_middle::ty::{
|
||||
self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
|
||||
@ -112,8 +113,6 @@ where
|
||||
|
||||
let assumed_wf_types = wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)?;
|
||||
|
||||
let implied_bounds = infcx.implied_bounds_tys(param_env, body_def_id, assumed_wf_types);
|
||||
|
||||
let errors = wfcx.select_all_or_error();
|
||||
if !errors.is_empty() {
|
||||
let err = infcx.err_ctxt().report_fulfillment_errors(errors);
|
||||
@ -128,10 +127,58 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
let infcx_compat = infcx.fork();
|
||||
|
||||
debug!(?assumed_wf_types);
|
||||
let implied_bounds = infcx.implied_bounds_tys(param_env, body_def_id, &assumed_wf_types);
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||
|
||||
wfcx.ocx.resolve_regions_and_report_errors(body_def_id, &outlives_env)?;
|
||||
infcx.tainted_by_errors().error_reported()
|
||||
let errors = infcx.resolve_regions(&outlives_env);
|
||||
if errors.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let is_bevy = 'is_bevy: {
|
||||
// We don't want to emit this for dependents of Bevy, for now.
|
||||
// See #119956
|
||||
let is_bevy_paramset = |def: ty::AdtDef<'_>| {
|
||||
let adt_did = with_no_trimmed_paths!(infcx.tcx.def_path_str(def.0.did));
|
||||
adt_did.contains("ParamSet")
|
||||
};
|
||||
for ty in assumed_wf_types.iter() {
|
||||
match ty.kind() {
|
||||
ty::Adt(def, _) => {
|
||||
if is_bevy_paramset(*def) {
|
||||
break 'is_bevy true;
|
||||
}
|
||||
}
|
||||
ty::Ref(_, ty, _) => match ty.kind() {
|
||||
ty::Adt(def, _) => {
|
||||
if is_bevy_paramset(*def) {
|
||||
break 'is_bevy true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
false
|
||||
};
|
||||
|
||||
if is_bevy {
|
||||
let implied_bounds =
|
||||
infcx_compat.implied_bounds_tys_compat(param_env, body_def_id, &assumed_wf_types);
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||
let errors_compat = infcx_compat.resolve_regions(&outlives_env);
|
||||
if errors_compat.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(infcx_compat.err_ctxt().report_region_errors(body_def_id, &errors_compat))
|
||||
}
|
||||
} else {
|
||||
Err(infcx.err_ctxt().report_region_errors(body_def_id, &errors))
|
||||
}
|
||||
}
|
||||
|
||||
fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) -> Result<(), ErrorGuaranteed> {
|
||||
@ -723,7 +770,7 @@ fn resolve_regions_with_wf_tys<'tcx>(
|
||||
let infcx = tcx.infer_ctxt().build();
|
||||
let outlives_environment = OutlivesEnvironment::with_bounds(
|
||||
param_env,
|
||||
infcx.implied_bounds_tys(param_env, id, wf_tys.clone()),
|
||||
infcx.implied_bounds_tys_compat(param_env, id, wf_tys),
|
||||
);
|
||||
let region_bound_pairs = outlives_environment.region_bound_pairs();
|
||||
|
||||
|
@ -202,7 +202,8 @@ fn get_impl_args(
|
||||
return Err(guar);
|
||||
}
|
||||
|
||||
let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, assumed_wf_types);
|
||||
let implied_bounds =
|
||||
infcx.implied_bounds_tys_compat(param_env, impl1_def_id, &assumed_wf_types);
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||
let _ = ocx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env);
|
||||
let Ok(impl2_args) = infcx.fully_resolve(impl2_args) else {
|
||||
|
@ -74,6 +74,10 @@ impl<T> EraseType for Result<&'_ T, traits::query::NoSolution> {
|
||||
type Result = [u8; size_of::<Result<&'static (), traits::query::NoSolution>>()];
|
||||
}
|
||||
|
||||
impl<T> EraseType for Result<&'_ [T], traits::query::NoSolution> {
|
||||
type Result = [u8; size_of::<Result<&'static [()], traits::query::NoSolution>>()];
|
||||
}
|
||||
|
||||
impl<T> EraseType for Result<&'_ T, rustc_errors::ErrorGuaranteed> {
|
||||
type Result = [u8; size_of::<Result<&'static (), rustc_errors::ErrorGuaranteed>>()];
|
||||
}
|
||||
|
@ -1949,7 +1949,7 @@ rustc_queries! {
|
||||
desc { "normalizing `{}`", goal.value }
|
||||
}
|
||||
|
||||
query implied_outlives_bounds(
|
||||
query implied_outlives_bounds_compat(
|
||||
goal: CanonicalTyGoal<'tcx>
|
||||
) -> Result<
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
|
||||
@ -1958,6 +1958,15 @@ rustc_queries! {
|
||||
desc { "computing implied outlives bounds for `{}`", goal.value.value }
|
||||
}
|
||||
|
||||
query implied_outlives_bounds(
|
||||
goal: CanonicalTyGoal<'tcx>
|
||||
) -> Result<
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
|
||||
NoSolution,
|
||||
> {
|
||||
desc { "computing implied outlives bounds v2 for `{}`", goal.value.value }
|
||||
}
|
||||
|
||||
/// Do not call this query directly:
|
||||
/// invoke `DropckOutlives::new(dropped_ty)).fully_perform(typeck.infcx)` instead.
|
||||
query dropck_outlives(
|
||||
|
@ -191,7 +191,7 @@ pub struct NormalizationResult<'tcx> {
|
||||
/// case they are called implied bounds). They are fed to the
|
||||
/// `OutlivesEnv` which in turn is supplied to the region checker and
|
||||
/// other parts of the inference system.
|
||||
#[derive(Clone, Debug, TypeFoldable, TypeVisitable, HashStable)]
|
||||
#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, HashStable)]
|
||||
pub enum OutlivesBound<'tcx> {
|
||||
RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
|
||||
RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
|
||||
|
@ -191,10 +191,10 @@ pub fn all_fields_implement_trait<'tcx>(
|
||||
// Check regions assuming the self type of the impl is WF
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(
|
||||
param_env,
|
||||
infcx.implied_bounds_tys(
|
||||
infcx.implied_bounds_tys_compat(
|
||||
param_env,
|
||||
parent_cause.body_id,
|
||||
FxIndexSet::from_iter([self_type]),
|
||||
&FxIndexSet::from_iter([self_type]),
|
||||
),
|
||||
);
|
||||
let errors = infcx.resolve_regions(&outlives_env);
|
||||
|
@ -9,24 +9,24 @@ use rustc_span::def_id::LocalDefId;
|
||||
|
||||
pub use rustc_middle::traits::query::OutlivesBound;
|
||||
|
||||
pub type BoundsCompat<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
|
||||
pub type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
|
||||
pub trait InferCtxtExt<'a, 'tcx> {
|
||||
fn implied_outlives_bounds(
|
||||
&self,
|
||||
fn implied_bounds_tys_compat(
|
||||
&'a self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
body_id: LocalDefId,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Vec<OutlivesBound<'tcx>>;
|
||||
tys: &'a FxIndexSet<Ty<'tcx>>,
|
||||
) -> BoundsCompat<'a, 'tcx>;
|
||||
|
||||
fn implied_bounds_tys(
|
||||
&'a self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
body_id: LocalDefId,
|
||||
tys: FxIndexSet<Ty<'tcx>>,
|
||||
tys: &'a FxIndexSet<Ty<'tcx>>,
|
||||
) -> Bounds<'a, 'tcx>;
|
||||
}
|
||||
|
||||
impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
|
||||
/// Implied bounds are region relationships that we deduce
|
||||
/// automatically. The idea is that (e.g.) a caller must check that a
|
||||
/// function's argument types are well-formed immediately before
|
||||
@ -46,15 +46,16 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
|
||||
/// Note that this may cause outlives obligations to be injected
|
||||
/// into the inference context with this body-id.
|
||||
/// - `ty`, the type that we are supposed to assume is WF.
|
||||
#[instrument(level = "debug", skip(self, param_env, body_id), ret)]
|
||||
fn implied_outlives_bounds(
|
||||
&self,
|
||||
#[instrument(level = "debug", skip(infcx, param_env, body_id), ret)]
|
||||
fn implied_outlives_bounds<'a, 'tcx>(
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
body_id: LocalDefId,
|
||||
ty: Ty<'tcx>,
|
||||
compat: bool,
|
||||
) -> Vec<OutlivesBound<'tcx>> {
|
||||
let ty = self.resolve_vars_if_possible(ty);
|
||||
let ty = OpportunisticRegionResolver::new(self).fold_ty(ty);
|
||||
let ty = infcx.resolve_vars_if_possible(ty);
|
||||
let ty = OpportunisticRegionResolver::new(infcx).fold_ty(ty);
|
||||
|
||||
// We do not expect existential variables in implied bounds.
|
||||
// We may however encounter unconstrained lifetime variables
|
||||
@ -65,13 +66,18 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
|
||||
assert!(!ty.has_non_region_infer());
|
||||
|
||||
let mut canonical_var_values = OriginalQueryValues::default();
|
||||
let canonical_ty = self.canonicalize_query(param_env.and(ty), &mut canonical_var_values);
|
||||
let Ok(canonical_result) = self.tcx.implied_outlives_bounds(canonical_ty) else {
|
||||
let canonical_ty = infcx.canonicalize_query(param_env.and(ty), &mut canonical_var_values);
|
||||
let implied_bounds_result = if compat {
|
||||
infcx.tcx.implied_outlives_bounds_compat(canonical_ty)
|
||||
} else {
|
||||
infcx.tcx.implied_outlives_bounds(canonical_ty)
|
||||
};
|
||||
let Ok(canonical_result) = implied_bounds_result else {
|
||||
return vec![];
|
||||
};
|
||||
|
||||
let mut constraints = QueryRegionConstraints::default();
|
||||
let Ok(InferOk { value: mut bounds, obligations }) = self
|
||||
let Ok(InferOk { value: mut bounds, obligations }) = infcx
|
||||
.instantiate_nll_query_response_and_region_obligations(
|
||||
&ObligationCause::dummy(),
|
||||
param_env,
|
||||
@ -89,7 +95,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
|
||||
bounds.retain(|bound| !bound.has_placeholders());
|
||||
|
||||
if !constraints.is_empty() {
|
||||
let span = self.tcx.def_span(body_id);
|
||||
let span = infcx.tcx.def_span(body_id);
|
||||
|
||||
debug!(?constraints);
|
||||
if !constraints.member_constraints.is_empty() {
|
||||
@ -98,10 +104,10 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
|
||||
|
||||
// Instantiation may have produced new inference variables and constraints on those
|
||||
// variables. Process these constraints.
|
||||
let ocx = ObligationCtxt::new(self);
|
||||
let ocx = ObligationCtxt::new(infcx);
|
||||
let cause = ObligationCause::misc(span, body_id);
|
||||
for &constraint in &constraints.outlives {
|
||||
ocx.register_obligation(self.query_outlives_constraint_to_obligation(
|
||||
ocx.register_obligation(infcx.query_outlives_constraint_to_obligation(
|
||||
constraint,
|
||||
cause.clone(),
|
||||
param_env,
|
||||
@ -110,7 +116,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
|
||||
|
||||
let errors = ocx.select_all_or_error();
|
||||
if !errors.is_empty() {
|
||||
self.dcx().span_delayed_bug(
|
||||
infcx.dcx().span_delayed_bug(
|
||||
span,
|
||||
"implied_outlives_bounds failed to solve obligations from instantiation",
|
||||
);
|
||||
@ -120,12 +126,22 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
|
||||
bounds
|
||||
}
|
||||
|
||||
impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
|
||||
fn implied_bounds_tys_compat(
|
||||
&'a self,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
body_id: LocalDefId,
|
||||
tys: &'a FxIndexSet<Ty<'tcx>>,
|
||||
) -> BoundsCompat<'a, 'tcx> {
|
||||
tys.iter().flat_map(move |ty| implied_outlives_bounds(self, param_env, body_id, *ty, true))
|
||||
}
|
||||
|
||||
fn implied_bounds_tys(
|
||||
&'a self,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
body_id: LocalDefId,
|
||||
tys: FxIndexSet<Ty<'tcx>>,
|
||||
tys: &'a FxIndexSet<Ty<'tcx>>,
|
||||
) -> Bounds<'a, 'tcx> {
|
||||
tys.into_iter().flat_map(move |ty| self.implied_outlives_bounds(param_env, body_id, ty))
|
||||
tys.iter().flat_map(move |ty| implied_outlives_bounds(self, param_env, body_id, *ty, false))
|
||||
}
|
||||
}
|
||||
|
@ -5,10 +5,11 @@ use crate::traits::ObligationCtxt;
|
||||
|
||||
use rustc_infer::infer::canonical::Canonical;
|
||||
use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
|
||||
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
|
||||
use rustc_infer::traits::query::OutlivesBound;
|
||||
use rustc_middle::infer::canonical::CanonicalQueryResponse;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFolder, TypeVisitableExt};
|
||||
use rustc_span::def_id::CRATE_DEF_ID;
|
||||
use rustc_span::DUMMY_SP;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
@ -47,14 +48,14 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> {
|
||||
param_env.and(ty)
|
||||
});
|
||||
|
||||
tcx.implied_outlives_bounds(canonicalized)
|
||||
tcx.implied_outlives_bounds_compat(canonicalized)
|
||||
}
|
||||
|
||||
fn perform_locally_with_next_solver(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
key: ParamEnvAnd<'tcx, Self>,
|
||||
) -> Result<Self::QueryResponse, NoSolution> {
|
||||
compute_implied_outlives_bounds_inner(ocx, key.param_env, key.value.ty)
|
||||
compute_implied_outlives_bounds_compat_inner(ocx, key.param_env, key.value.ty)
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,6 +63,85 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<Vec<OutlivesBound<'tcx>>, NoSolution> {
|
||||
let normalize_op = |ty| {
|
||||
let ty = ocx.normalize(&ObligationCause::dummy(), param_env, ty);
|
||||
if !ocx.select_all_or_error().is_empty() {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
let ty = ocx.infcx.resolve_vars_if_possible(ty);
|
||||
let ty = OpportunisticRegionResolver::new(&ocx.infcx).fold_ty(ty);
|
||||
Ok(ty)
|
||||
};
|
||||
|
||||
// Sometimes when we ask what it takes for T: WF, we get back that
|
||||
// U: WF is required; in that case, we push U onto this stack and
|
||||
// process it next. Because the resulting predicates aren't always
|
||||
// guaranteed to be a subset of the original type, so we need to store the
|
||||
// WF args we've computed in a set.
|
||||
let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default();
|
||||
let mut wf_args = vec![ty.into(), normalize_op(ty)?.into()];
|
||||
|
||||
let mut outlives_bounds: Vec<OutlivesBound<'tcx>> = vec![];
|
||||
|
||||
while let Some(arg) = wf_args.pop() {
|
||||
if !checked_wf_args.insert(arg) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// From the full set of obligations, just filter down to the region relationships.
|
||||
for obligation in
|
||||
wf::unnormalized_obligations(ocx.infcx, param_env, arg).into_iter().flatten()
|
||||
{
|
||||
assert!(!obligation.has_escaping_bound_vars());
|
||||
let Some(pred) = obligation.predicate.kind().no_bound_vars() else {
|
||||
continue;
|
||||
};
|
||||
match pred {
|
||||
// FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound
|
||||
// if we ever support that
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(..))
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::Projection(..))
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::Ambiguous
|
||||
| ty::PredicateKind::NormalizesTo(..)
|
||||
| ty::PredicateKind::AliasRelate(..) => {}
|
||||
|
||||
// We need to search through *all* WellFormed predicates
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
|
||||
wf_args.push(arg);
|
||||
}
|
||||
|
||||
// We need to register region relationships
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
|
||||
ty::OutlivesPredicate(r_a, r_b),
|
||||
)) => outlives_bounds.push(OutlivesBound::RegionSubRegion(r_b, r_a)),
|
||||
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
|
||||
ty_a,
|
||||
r_b,
|
||||
))) => {
|
||||
let ty_a = normalize_op(ty_a)?;
|
||||
let mut components = smallvec![];
|
||||
push_outlives_components(ocx.infcx.tcx, ty_a, &mut components);
|
||||
outlives_bounds.extend(implied_bounds_from_components(r_b, components))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(outlives_bounds)
|
||||
}
|
||||
|
||||
pub fn compute_implied_outlives_bounds_compat_inner<'tcx>(
|
||||
ocx: &ObligationCtxt<'_, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<Vec<OutlivesBound<'tcx>>, NoSolution> {
|
||||
let tcx = ocx.infcx.tcx;
|
||||
|
||||
|
@ -8,13 +8,29 @@ use rustc_infer::traits::query::OutlivesBound;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_trait_selection::infer::InferCtxtBuilderExt;
|
||||
use rustc_trait_selection::traits::query::type_op::implied_outlives_bounds::compute_implied_outlives_bounds_inner;
|
||||
use rustc_trait_selection::traits::query::type_op::implied_outlives_bounds::{
|
||||
compute_implied_outlives_bounds_compat_inner, compute_implied_outlives_bounds_inner,
|
||||
};
|
||||
use rustc_trait_selection::traits::query::{CanonicalTyGoal, NoSolution};
|
||||
|
||||
pub(crate) fn provide(p: &mut Providers) {
|
||||
*p = Providers { implied_outlives_bounds_compat, ..*p };
|
||||
*p = Providers { implied_outlives_bounds, ..*p };
|
||||
}
|
||||
|
||||
fn implied_outlives_bounds_compat<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
goal: CanonicalTyGoal<'tcx>,
|
||||
) -> Result<
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
|
||||
NoSolution,
|
||||
> {
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| {
|
||||
let (param_env, ty) = key.into_parts();
|
||||
compute_implied_outlives_bounds_compat_inner(ocx, param_env, ty)
|
||||
})
|
||||
}
|
||||
|
||||
fn implied_outlives_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
goal: CanonicalTyGoal<'tcx>,
|
||||
|
@ -1,18 +0,0 @@
|
||||
// Related to Bevy regression #118553
|
||||
|
||||
pub trait WorldQuery {}
|
||||
impl WorldQuery for &u8 {}
|
||||
|
||||
pub struct Query<Q: WorldQuery>(Q);
|
||||
|
||||
pub trait SystemParam {
|
||||
type State;
|
||||
}
|
||||
impl<Q: WorldQuery + 'static> SystemParam for Query<Q> {
|
||||
type State = ();
|
||||
// `Q: 'static` is required because we need the TypeId of Q ...
|
||||
}
|
||||
|
||||
pub struct ParamSet<T: SystemParam>(T)
|
||||
where
|
||||
T::State: Sized;
|
@ -1,11 +1,26 @@
|
||||
// aux-crate:bevy_ecs=bevy_ecs.rs
|
||||
// check-pass
|
||||
// Related to Bevy regression #118553
|
||||
|
||||
extern crate bevy_ecs;
|
||||
// We currently special case bevy from erroring on incorrect implied bounds
|
||||
// from normalization (issue #109628).
|
||||
// Otherwise, we would expect this to hit that error.
|
||||
|
||||
use bevy_ecs::*;
|
||||
pub trait WorldQuery {}
|
||||
impl WorldQuery for &u8 {}
|
||||
|
||||
pub struct Query<Q: WorldQuery>(Q);
|
||||
|
||||
pub trait SystemParam {
|
||||
type State;
|
||||
}
|
||||
impl<Q: WorldQuery + 'static> SystemParam for Query<Q> {
|
||||
type State = ();
|
||||
// `Q: 'static` is required because we need the TypeId of Q ...
|
||||
}
|
||||
|
||||
pub struct ParamSet<T: SystemParam>(T) where T::State: Sized;
|
||||
|
||||
fn handler<'a>(_: ParamSet<Query<&'a u8>>) {}
|
||||
|
||||
fn ref_handler<'a>(_: &ParamSet<Query<&'a u8>>) {}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,6 +1,3 @@
|
||||
// check-pass
|
||||
// known-bug: #109628
|
||||
|
||||
trait Trait {
|
||||
type Assoc;
|
||||
}
|
||||
@ -14,11 +11,13 @@ where
|
||||
T::Assoc: Clone; // any predicate using `T::Assoc` works here
|
||||
|
||||
fn func1(foo: Foo<(&str,)>) {
|
||||
//~^ ERROR `&str` does not fulfill the required lifetime
|
||||
let _: &'static str = foo.0.0;
|
||||
}
|
||||
|
||||
trait TestTrait {}
|
||||
|
||||
impl<X> TestTrait for [Foo<(X,)>; 1] {}
|
||||
//~^ ERROR `X` may not live long enough
|
||||
|
||||
fn main() {}
|
||||
|
26
tests/ui/implied-bounds/from-trait-impl.stderr
Normal file
26
tests/ui/implied-bounds/from-trait-impl.stderr
Normal file
@ -0,0 +1,26 @@
|
||||
error[E0477]: the type `&str` does not fulfill the required lifetime
|
||||
--> $DIR/from-trait-impl.rs:13:15
|
||||
|
|
||||
LL | fn func1(foo: Foo<(&str,)>) {
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: type must satisfy the static lifetime
|
||||
|
||||
error[E0310]: the parameter type `X` may not live long enough
|
||||
--> $DIR/from-trait-impl.rs:20:23
|
||||
|
|
||||
LL | impl<X> TestTrait for [Foo<(X,)>; 1] {}
|
||||
| ^^^^^^^^^^^^^^
|
||||
| |
|
||||
| the parameter type `X` must be valid for the static lifetime...
|
||||
| ...so that the type `X` will meet its required lifetime bounds
|
||||
|
|
||||
help: consider adding an explicit lifetime bound
|
||||
|
|
||||
LL | impl<X: 'static> TestTrait for [Foo<(X,)>; 1] {}
|
||||
| +++++++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0310, E0477.
|
||||
For more information about an error, try `rustc --explain E0310`.
|
@ -1,5 +1,5 @@
|
||||
// check-pass
|
||||
// Related to Bevy regression #118553
|
||||
// Found in a crater run on #118553
|
||||
|
||||
pub trait QueryBase {
|
||||
type Db;
|
||||
@ -17,8 +17,7 @@ pub struct QueryTable<'me, Q, DB> {
|
||||
_marker: Option<&'me ()>,
|
||||
}
|
||||
|
||||
impl<'me, Q> QueryTable<'me, Q, <Q as QueryBase>::Db>
|
||||
// projection is important
|
||||
impl<'me, Q> QueryTable<'me, Q, <Q as QueryBase>::Db> // projection is important
|
||||
// ^^^ removing 'me (and in QueryTable) gives a different error
|
||||
where
|
||||
Q: for<'f> AsyncQueryFunction<'f>,
|
||||
|
@ -1,33 +1,10 @@
|
||||
error[E0759]: `fn` parameter has lifetime `'x` but it needs to satisfy a `'static` lifetime requirement
|
||||
--> $DIR/normalization-nested.rs:35:28
|
||||
|
|
||||
LL | pub fn test_wfcheck<'x>(_: Map<Vec<&'x ()>>) {}
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| this data with lifetime `'x`...
|
||||
| ...is used and required to live as long as `'static` here
|
||||
|
|
||||
note: `'static` lifetime requirement introduced by this bound
|
||||
--> $DIR/normalization-nested.rs:33:14
|
||||
|
|
||||
LL | I::Item: 'static;
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0759]: `fn` parameter has lifetime `'x` but it needs to satisfy a `'static` lifetime requirement
|
||||
--> $DIR/normalization-nested.rs:37:29
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/normalization-nested.rs:38:5
|
||||
|
|
||||
LL | pub fn test_borrowck<'x>(_: Map<Vec<&'x ()>>, s: &'x str) -> &'static str {
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| this data with lifetime `'x`...
|
||||
| ...is used and required to live as long as `'static` here
|
||||
|
|
||||
note: `'static` lifetime requirement introduced by this bound
|
||||
--> $DIR/normalization-nested.rs:33:14
|
||||
|
|
||||
LL | I::Item: 'static;
|
||||
| ^^^^^^^
|
||||
| -- lifetime `'x` defined here
|
||||
LL | s
|
||||
| ^ returning this value requires that `'x` must outlive `'static`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0759`.
|
||||
|
@ -1,5 +1,4 @@
|
||||
// check-pass
|
||||
// Related to crater regressions on #118553
|
||||
// Found in a crater run on #118553
|
||||
|
||||
pub trait Debug {}
|
||||
|
||||
@ -30,6 +29,9 @@ impl<P: Service, S: Service<Input = P::Output>> ServiceChainBuilder<P, S> {
|
||||
pub fn next<NS: Service<Input = S::Output>>(
|
||||
self,
|
||||
) -> ServiceChainBuilder<ServiceChain<P, S>, NS> {
|
||||
//~^ the associated type
|
||||
//~| the associated type
|
||||
//~| the associated type
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
|
31
tests/ui/implied-bounds/sod_service_chain.stderr
Normal file
31
tests/ui/implied-bounds/sod_service_chain.stderr
Normal file
@ -0,0 +1,31 @@
|
||||
error[E0310]: the associated type `<P as Service>::Error` may not live long enough
|
||||
--> $DIR/sod_service_chain.rs:31:10
|
||||
|
|
||||
LL | ) -> ServiceChainBuilder<ServiceChain<P, S>, NS> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| the associated type `<P as Service>::Error` must be valid for the static lifetime...
|
||||
| ...so that the type `<P as Service>::Error` will meet its required lifetime bounds
|
||||
|
|
||||
help: consider adding an explicit lifetime bound
|
||||
|
|
||||
LL | ) -> ServiceChainBuilder<ServiceChain<P, S>, NS> where <P as Service>::Error: 'static {
|
||||
| ++++++++++++++++++++++++++++++++++++
|
||||
|
||||
error[E0310]: the associated type `<S as Service>::Error` may not live long enough
|
||||
--> $DIR/sod_service_chain.rs:31:10
|
||||
|
|
||||
LL | ) -> ServiceChainBuilder<ServiceChain<P, S>, NS> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| the associated type `<S as Service>::Error` must be valid for the static lifetime...
|
||||
| ...so that the type `<S as Service>::Error` will meet its required lifetime bounds
|
||||
|
|
||||
help: consider adding an explicit lifetime bound
|
||||
|
|
||||
LL | ) -> ServiceChainBuilder<ServiceChain<P, S>, NS> where <S as Service>::Error: 'static {
|
||||
| ++++++++++++++++++++++++++++++++++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0310`.
|
Loading…
Reference in New Issue
Block a user