Rollup merge of #101433 - jackh726:better-static-placeholder-error, r=compiler-errors
Emit a note that static bounds from HRTBs are a bug This note isn't perfect, but opening this to either 1) land as is or 2) get some feedback on how to improve it Let r? `@compiler-errors` and cc. `@nikomatsakis`
This commit is contained in:
commit
430123164f
34 changed files with 543 additions and 173 deletions
|
@ -22,6 +22,7 @@ use rustc_data_structures::captures::Captures;
|
|||
use rustc_index::vec::Idx;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_middle::arena::ArenaAllocatable;
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
|
@ -129,7 +130,9 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
let region_constraints = self.with_region_constraints(|region_constraints| {
|
||||
make_query_region_constraints(
|
||||
tcx,
|
||||
region_obligations.iter().map(|r_o| (r_o.sup_type, r_o.sub_region)),
|
||||
region_obligations
|
||||
.iter()
|
||||
.map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())),
|
||||
region_constraints,
|
||||
)
|
||||
});
|
||||
|
@ -248,6 +251,8 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
// the original values `v_o` that was canonicalized into a
|
||||
// variable...
|
||||
|
||||
let constraint_category = cause.to_constraint_category();
|
||||
|
||||
for (index, original_value) in original_values.var_values.iter().enumerate() {
|
||||
// ...with the value `v_r` of that variable from the query.
|
||||
let result_value = query_response.substitute_projected(self.tcx, &result_subst, |v| {
|
||||
|
@ -263,12 +268,14 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
(GenericArgKind::Lifetime(v_o), GenericArgKind::Lifetime(v_r)) => {
|
||||
// To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`.
|
||||
if v_o != v_r {
|
||||
output_query_region_constraints
|
||||
.outlives
|
||||
.push(ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r)));
|
||||
output_query_region_constraints
|
||||
.outlives
|
||||
.push(ty::Binder::dummy(ty::OutlivesPredicate(v_r.into(), v_o)));
|
||||
output_query_region_constraints.outlives.push((
|
||||
ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r)),
|
||||
constraint_category,
|
||||
));
|
||||
output_query_region_constraints.outlives.push((
|
||||
ty::Binder::dummy(ty::OutlivesPredicate(v_r.into(), v_o)),
|
||||
constraint_category,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,7 +321,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
// Screen out `'a: 'a` cases -- we skip the binder here but
|
||||
// only compare the inner values to one another, so they are still at
|
||||
// consistent binding levels.
|
||||
let ty::OutlivesPredicate(k1, r2) = r_c.skip_binder();
|
||||
let ty::OutlivesPredicate(k1, r2) = r_c.0.skip_binder();
|
||||
if k1 != r2.into() { Some(r_c) } else { None }
|
||||
}),
|
||||
);
|
||||
|
@ -559,7 +566,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
cause: ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Obligation<'tcx, ty::Predicate<'tcx>> {
|
||||
let ty::OutlivesPredicate(k1, r2) = predicate.skip_binder();
|
||||
let ty::OutlivesPredicate(k1, r2) = predicate.0.skip_binder();
|
||||
|
||||
let atom = match k1.unpack() {
|
||||
GenericArgKind::Lifetime(r1) => {
|
||||
|
@ -574,7 +581,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
span_bug!(cause.span, "unexpected const outlives {:?}", predicate);
|
||||
}
|
||||
};
|
||||
let predicate = predicate.rebind(atom).to_predicate(self.tcx);
|
||||
let predicate = predicate.0.rebind(atom).to_predicate(self.tcx);
|
||||
|
||||
Obligation::new(cause, param_env, predicate)
|
||||
}
|
||||
|
@ -625,7 +632,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
/// creates query region constraints.
|
||||
pub fn make_query_region_constraints<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>)>,
|
||||
outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>, ConstraintCategory<'tcx>)>,
|
||||
region_constraints: &RegionConstraintData<'tcx>,
|
||||
) -> QueryRegionConstraints<'tcx> {
|
||||
let RegionConstraintData { constraints, verifys, givens, member_constraints } =
|
||||
|
@ -638,26 +645,31 @@ pub fn make_query_region_constraints<'tcx>(
|
|||
|
||||
let outlives: Vec<_> = constraints
|
||||
.iter()
|
||||
.map(|(k, _)| match *k {
|
||||
// Swap regions because we are going from sub (<=) to outlives
|
||||
// (>=).
|
||||
Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
|
||||
tcx.mk_region(ty::ReVar(v2)).into(),
|
||||
tcx.mk_region(ty::ReVar(v1)),
|
||||
),
|
||||
Constraint::VarSubReg(v1, r2) => {
|
||||
ty::OutlivesPredicate(r2.into(), tcx.mk_region(ty::ReVar(v1)))
|
||||
}
|
||||
Constraint::RegSubVar(r1, v2) => {
|
||||
ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1)
|
||||
}
|
||||
Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1),
|
||||
.map(|(k, origin)| {
|
||||
// no bound vars in the code above
|
||||
let constraint = ty::Binder::dummy(match *k {
|
||||
// Swap regions because we are going from sub (<=) to outlives
|
||||
// (>=).
|
||||
Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
|
||||
tcx.mk_region(ty::ReVar(v2)).into(),
|
||||
tcx.mk_region(ty::ReVar(v1)),
|
||||
),
|
||||
Constraint::VarSubReg(v1, r2) => {
|
||||
ty::OutlivesPredicate(r2.into(), tcx.mk_region(ty::ReVar(v1)))
|
||||
}
|
||||
Constraint::RegSubVar(r1, v2) => {
|
||||
ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1)
|
||||
}
|
||||
Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1),
|
||||
});
|
||||
(constraint, origin.to_constraint_category())
|
||||
})
|
||||
.map(ty::Binder::dummy) // no bound vars in the code above
|
||||
.chain(
|
||||
outlives_obligations
|
||||
.map(|(ty, r)| ty::OutlivesPredicate(ty.into(), r))
|
||||
.map(ty::Binder::dummy), // no bound vars in the code above
|
||||
// no bound vars in the code above
|
||||
.map(|(ty, r, constraint_category)| {
|
||||
(ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), r)), constraint_category)
|
||||
}),
|
||||
)
|
||||
.collect();
|
||||
|
||||
|
|
|
@ -77,6 +77,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
infer::CheckAssociatedTypeBounds { ref parent, .. } => {
|
||||
self.note_region_origin(err, &parent);
|
||||
}
|
||||
infer::AscribeUserTypeProvePredicate(span) => {
|
||||
RegionOriginNote::Plain {
|
||||
span,
|
||||
msg: fluent::infer::ascribe_user_type_prove_predicate,
|
||||
}
|
||||
.add_to_diagnostic(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -356,6 +363,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
|
||||
err
|
||||
}
|
||||
infer::AscribeUserTypeProvePredicate(span) => {
|
||||
let mut err =
|
||||
struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"lifetime instantiated with ",
|
||||
sup,
|
||||
"",
|
||||
None,
|
||||
);
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"but lifetime must outlive ",
|
||||
sub,
|
||||
"",
|
||||
None,
|
||||
);
|
||||
err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
|
|||
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
|
||||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
|
||||
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::traits::select;
|
||||
use rustc_middle::ty::abstract_const::{AbstractConst, FailureKind};
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
|
@ -408,7 +409,11 @@ pub enum SubregionOrigin<'tcx> {
|
|||
|
||||
/// Comparing the signature and requirements of an impl method against
|
||||
/// the containing trait.
|
||||
CompareImplItemObligation { span: Span, impl_item_def_id: LocalDefId, trait_item_def_id: DefId },
|
||||
CompareImplItemObligation {
|
||||
span: Span,
|
||||
impl_item_def_id: LocalDefId,
|
||||
trait_item_def_id: DefId,
|
||||
},
|
||||
|
||||
/// Checking that the bounds of a trait's associated type hold for a given impl
|
||||
CheckAssociatedTypeBounds {
|
||||
|
@ -416,12 +421,24 @@ pub enum SubregionOrigin<'tcx> {
|
|||
impl_item_def_id: LocalDefId,
|
||||
trait_item_def_id: DefId,
|
||||
},
|
||||
|
||||
AscribeUserTypeProvePredicate(Span),
|
||||
}
|
||||
|
||||
// `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger.
|
||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||
static_assert_size!(SubregionOrigin<'_>, 32);
|
||||
|
||||
impl<'tcx> SubregionOrigin<'tcx> {
|
||||
pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> {
|
||||
match self {
|
||||
Self::Subtype(type_trace) => type_trace.cause.to_constraint_category(),
|
||||
Self::AscribeUserTypeProvePredicate(span) => ConstraintCategory::Predicate(*span),
|
||||
_ => ConstraintCategory::BoringNoLocation,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Times when we replace late-bound regions with variables:
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum LateBoundRegionConversionTime {
|
||||
|
@ -1991,6 +2008,7 @@ impl<'tcx> SubregionOrigin<'tcx> {
|
|||
DataBorrowed(_, a) => a,
|
||||
ReferenceOutlivesReferent(_, a) => a,
|
||||
CompareImplItemObligation { span, .. } => span,
|
||||
AscribeUserTypeProvePredicate(span) => span,
|
||||
CheckAssociatedTypeBounds { ref parent, .. } => parent.span(),
|
||||
}
|
||||
}
|
||||
|
@ -2023,6 +2041,10 @@ impl<'tcx> SubregionOrigin<'tcx> {
|
|||
parent: Box::new(default()),
|
||||
},
|
||||
|
||||
traits::ObligationCauseCode::AscribeUserTypeProvePredicate(span) => {
|
||||
SubregionOrigin::AscribeUserTypeProvePredicate(span)
|
||||
}
|
||||
|
||||
_ => default(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,6 +69,7 @@ use crate::infer::{
|
|||
use crate::traits::{ObligationCause, ObligationCauseCode};
|
||||
use rustc_data_structures::undo_log::UndoLogs;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeVisitable};
|
||||
use smallvec::smallvec;
|
||||
|
@ -163,7 +164,8 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
|
||||
let outlives =
|
||||
&mut TypeOutlives::new(self, self.tcx, ®ion_bound_pairs, None, param_env);
|
||||
outlives.type_must_outlive(origin, sup_type, sub_region);
|
||||
let category = origin.to_constraint_category();
|
||||
outlives.type_must_outlive(origin, sup_type, sub_region, category);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,6 +209,7 @@ pub trait TypeOutlivesDelegate<'tcx> {
|
|||
origin: SubregionOrigin<'tcx>,
|
||||
a: ty::Region<'tcx>,
|
||||
b: ty::Region<'tcx>,
|
||||
constraint_category: ConstraintCategory<'tcx>,
|
||||
);
|
||||
|
||||
fn push_verify(
|
||||
|
@ -255,12 +258,13 @@ where
|
|||
origin: infer::SubregionOrigin<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
region: ty::Region<'tcx>,
|
||||
category: ConstraintCategory<'tcx>,
|
||||
) {
|
||||
assert!(!ty.has_escaping_bound_vars());
|
||||
|
||||
let mut components = smallvec![];
|
||||
push_outlives_components(self.tcx, ty, &mut components);
|
||||
self.components_must_outlive(origin, &components, region);
|
||||
self.components_must_outlive(origin, &components, region, category);
|
||||
}
|
||||
|
||||
fn components_must_outlive(
|
||||
|
@ -268,12 +272,13 @@ where
|
|||
origin: infer::SubregionOrigin<'tcx>,
|
||||
components: &[Component<'tcx>],
|
||||
region: ty::Region<'tcx>,
|
||||
category: ConstraintCategory<'tcx>,
|
||||
) {
|
||||
for component in components.iter() {
|
||||
let origin = origin.clone();
|
||||
match component {
|
||||
Component::Region(region1) => {
|
||||
self.delegate.push_sub_region_constraint(origin, region, *region1);
|
||||
self.delegate.push_sub_region_constraint(origin, region, *region1, category);
|
||||
}
|
||||
Component::Param(param_ty) => {
|
||||
self.param_ty_must_outlive(origin, region, *param_ty);
|
||||
|
@ -282,7 +287,7 @@ where
|
|||
self.projection_must_outlive(origin, region, *projection_ty);
|
||||
}
|
||||
Component::EscapingProjection(subcomponents) => {
|
||||
self.components_must_outlive(origin, &subcomponents, region);
|
||||
self.components_must_outlive(origin, &subcomponents, region, category);
|
||||
}
|
||||
Component::UnresolvedInferenceVariable(v) => {
|
||||
// ignore this, we presume it will yield an error
|
||||
|
@ -392,10 +397,20 @@ where
|
|||
for k in projection_ty.substs {
|
||||
match k.unpack() {
|
||||
GenericArgKind::Lifetime(lt) => {
|
||||
self.delegate.push_sub_region_constraint(origin.clone(), region, lt);
|
||||
self.delegate.push_sub_region_constraint(
|
||||
origin.clone(),
|
||||
region,
|
||||
lt,
|
||||
origin.to_constraint_category(),
|
||||
);
|
||||
}
|
||||
GenericArgKind::Type(ty) => {
|
||||
self.type_must_outlive(origin.clone(), ty, region);
|
||||
self.type_must_outlive(
|
||||
origin.clone(),
|
||||
ty,
|
||||
region,
|
||||
origin.to_constraint_category(),
|
||||
);
|
||||
}
|
||||
GenericArgKind::Const(_) => {
|
||||
// Const parameters don't impose constraints.
|
||||
|
@ -433,7 +448,8 @@ where
|
|||
let unique_bound = trait_bounds[0];
|
||||
debug!("projection_must_outlive: unique trait bound = {:?}", unique_bound);
|
||||
debug!("projection_must_outlive: unique declared bound appears in trait ref");
|
||||
self.delegate.push_sub_region_constraint(origin, region, unique_bound);
|
||||
let category = origin.to_constraint_category();
|
||||
self.delegate.push_sub_region_constraint(origin, region, unique_bound, category);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -455,6 +471,7 @@ impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'tcx> {
|
|||
origin: SubregionOrigin<'tcx>,
|
||||
a: ty::Region<'tcx>,
|
||||
b: ty::Region<'tcx>,
|
||||
_constraint_category: ConstraintCategory<'tcx>,
|
||||
) {
|
||||
self.sub_regions(origin, a, b)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue