Auto merge of #101924 - jackh726:revert-static-hrtb-error, r=compiler-errors
Re-add HRTB implied static bug note r? `@compiler-errors` since you reviewed it previously I deleted a `normalize` call and forgot about it. Whoops.
This commit is contained in:
commit
efa717bc2d
33 changed files with 500 additions and 110 deletions
|
@ -21,10 +21,7 @@ pub(crate) struct OutlivesConstraintSet<'tcx> {
|
||||||
|
|
||||||
impl<'tcx> OutlivesConstraintSet<'tcx> {
|
impl<'tcx> OutlivesConstraintSet<'tcx> {
|
||||||
pub(crate) fn push(&mut self, constraint: OutlivesConstraint<'tcx>) {
|
pub(crate) fn push(&mut self, constraint: OutlivesConstraint<'tcx>) {
|
||||||
debug!(
|
debug!("OutlivesConstraintSet::push({:?})", constraint);
|
||||||
"OutlivesConstraintSet::push({:?}: {:?} @ {:?}",
|
|
||||||
constraint.sup, constraint.sub, constraint.locations
|
|
||||||
);
|
|
||||||
if constraint.sup == constraint.sub {
|
if constraint.sup == constraint.sub {
|
||||||
// 'a: 'a is pretty uninteresting
|
// 'a: 'a is pretty uninteresting
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -15,7 +15,7 @@ use rustc_middle::ty::{self, RegionVid, TyCtxt};
|
||||||
use rustc_span::symbol::{kw, Symbol};
|
use rustc_span::symbol::{kw, Symbol};
|
||||||
use rustc_span::{sym, DesugaringKind, Span};
|
use rustc_span::{sym, DesugaringKind, Span};
|
||||||
|
|
||||||
use crate::region_infer::BlameConstraint;
|
use crate::region_infer::{BlameConstraint, ExtraConstraintInfo};
|
||||||
use crate::{
|
use crate::{
|
||||||
borrow_set::BorrowData, nll::ConstraintDescription, region_infer::Cause, MirBorrowckCtxt,
|
borrow_set::BorrowData, nll::ConstraintDescription, region_infer::Cause, MirBorrowckCtxt,
|
||||||
WriteKind,
|
WriteKind,
|
||||||
|
@ -38,6 +38,7 @@ pub(crate) enum BorrowExplanation<'tcx> {
|
||||||
span: Span,
|
span: Span,
|
||||||
region_name: RegionName,
|
region_name: RegionName,
|
||||||
opt_place_desc: Option<String>,
|
opt_place_desc: Option<String>,
|
||||||
|
extra_info: Vec<ExtraConstraintInfo>,
|
||||||
},
|
},
|
||||||
Unexplained,
|
Unexplained,
|
||||||
}
|
}
|
||||||
|
@ -243,6 +244,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||||
ref region_name,
|
ref region_name,
|
||||||
ref opt_place_desc,
|
ref opt_place_desc,
|
||||||
from_closure: _,
|
from_closure: _,
|
||||||
|
ref extra_info,
|
||||||
} => {
|
} => {
|
||||||
region_name.highlight_region_name(err);
|
region_name.highlight_region_name(err);
|
||||||
|
|
||||||
|
@ -268,6 +270,14 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
for extra in extra_info {
|
||||||
|
match extra {
|
||||||
|
ExtraConstraintInfo::PlaceholderFromPredicate(span) => {
|
||||||
|
err.span_note(*span, format!("due to current limitations in the borrow checker, this implies a `'static` lifetime"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name);
|
self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -309,16 +319,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
&self,
|
&self,
|
||||||
borrow_region: RegionVid,
|
borrow_region: RegionVid,
|
||||||
outlived_region: RegionVid,
|
outlived_region: RegionVid,
|
||||||
) -> (ConstraintCategory<'tcx>, bool, Span, Option<RegionName>) {
|
) -> (ConstraintCategory<'tcx>, bool, Span, Option<RegionName>, Vec<ExtraConstraintInfo>) {
|
||||||
let BlameConstraint { category, from_closure, cause, variance_info: _ } = self
|
let (blame_constraint, extra_info) = self.regioncx.best_blame_constraint(
|
||||||
.regioncx
|
borrow_region,
|
||||||
.best_blame_constraint(borrow_region, NllRegionVariableOrigin::FreeRegion, |r| {
|
NllRegionVariableOrigin::FreeRegion,
|
||||||
self.regioncx.provides_universal_region(r, borrow_region, outlived_region)
|
|r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region),
|
||||||
});
|
);
|
||||||
|
let BlameConstraint { category, from_closure, cause, .. } = blame_constraint;
|
||||||
|
|
||||||
let outlived_fr_name = self.give_region_a_name(outlived_region);
|
let outlived_fr_name = self.give_region_a_name(outlived_region);
|
||||||
|
|
||||||
(category, from_closure, cause.span, outlived_fr_name)
|
(category, from_closure, cause.span, outlived_fr_name, extra_info)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns structured explanation for *why* the borrow contains the
|
/// Returns structured explanation for *why* the borrow contains the
|
||||||
|
@ -390,7 +401,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
|
|
||||||
None => {
|
None => {
|
||||||
if let Some(region) = self.to_error_region_vid(borrow_region_vid) {
|
if let Some(region) = self.to_error_region_vid(borrow_region_vid) {
|
||||||
let (category, from_closure, span, region_name) =
|
let (category, from_closure, span, region_name, extra_info) =
|
||||||
self.free_region_constraint_info(borrow_region_vid, region);
|
self.free_region_constraint_info(borrow_region_vid, region);
|
||||||
if let Some(region_name) = region_name {
|
if let Some(region_name) = region_name {
|
||||||
let opt_place_desc = self.describe_place(borrow.borrowed_place.as_ref());
|
let opt_place_desc = self.describe_place(borrow.borrowed_place.as_ref());
|
||||||
|
@ -400,6 +411,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
span,
|
span,
|
||||||
region_name,
|
region_name,
|
||||||
opt_place_desc,
|
opt_place_desc,
|
||||||
|
extra_info,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
debug!("Could not generate a region name");
|
debug!("Could not generate a region name");
|
||||||
|
|
|
@ -31,7 +31,7 @@ use crate::session_diagnostics::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{OutlivesSuggestionBuilder, RegionName};
|
use super::{OutlivesSuggestionBuilder, RegionName};
|
||||||
use crate::region_infer::BlameConstraint;
|
use crate::region_infer::{BlameConstraint, ExtraConstraintInfo};
|
||||||
use crate::{
|
use crate::{
|
||||||
nll::ConstraintDescription,
|
nll::ConstraintDescription,
|
||||||
region_infer::{values::RegionElement, TypeTest},
|
region_infer::{values::RegionElement, TypeTest},
|
||||||
|
@ -354,10 +354,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
) {
|
) {
|
||||||
debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
|
debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
|
||||||
|
|
||||||
let BlameConstraint { category, cause, variance_info, from_closure: _ } =
|
let (blame_constraint, extra_info) =
|
||||||
self.regioncx.best_blame_constraint(fr, fr_origin, |r| {
|
self.regioncx.best_blame_constraint(fr, fr_origin, |r| {
|
||||||
self.regioncx.provides_universal_region(r, fr, outlived_fr)
|
self.regioncx.provides_universal_region(r, fr, outlived_fr)
|
||||||
});
|
});
|
||||||
|
let BlameConstraint { category, cause, variance_info, .. } = blame_constraint;
|
||||||
|
|
||||||
debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info);
|
debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info);
|
||||||
|
|
||||||
|
@ -466,6 +467,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for extra in extra_info {
|
||||||
|
match extra {
|
||||||
|
ExtraConstraintInfo::PlaceholderFromPredicate(span) => {
|
||||||
|
diag.span_note(span, format!("due to current limitations in the borrow checker, this implies a `'static` lifetime"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.buffer_error(diag);
|
self.buffer_error(diag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,6 +566,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
/// LL | ref_obj(x)
|
/// LL | ref_obj(x)
|
||||||
/// | ^^^^^^^^^^ `x` escapes the function body here
|
/// | ^^^^^^^^^^ `x` escapes the function body here
|
||||||
/// ```
|
/// ```
|
||||||
|
#[instrument(level = "debug", skip(self))]
|
||||||
fn report_escaping_data_error(
|
fn report_escaping_data_error(
|
||||||
&self,
|
&self,
|
||||||
errci: &ErrorConstraintInfo<'tcx>,
|
errci: &ErrorConstraintInfo<'tcx>,
|
||||||
|
|
|
@ -245,6 +245,11 @@ enum Trace<'tcx> {
|
||||||
NotVisited,
|
NotVisited,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
|
pub enum ExtraConstraintInfo {
|
||||||
|
PlaceholderFromPredicate(Span),
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> RegionInferenceContext<'tcx> {
|
impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
/// Creates a new region inference context with a total of
|
/// Creates a new region inference context with a total of
|
||||||
/// `num_region_variables` valid inference variables; the first N
|
/// `num_region_variables` valid inference variables; the first N
|
||||||
|
@ -1818,10 +1823,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
fr1_origin: NllRegionVariableOrigin,
|
fr1_origin: NllRegionVariableOrigin,
|
||||||
fr2: RegionVid,
|
fr2: RegionVid,
|
||||||
) -> (ConstraintCategory<'tcx>, ObligationCause<'tcx>) {
|
) -> (ConstraintCategory<'tcx>, ObligationCause<'tcx>) {
|
||||||
let BlameConstraint { category, cause, .. } =
|
let BlameConstraint { category, cause, .. } = self
|
||||||
self.best_blame_constraint(fr1, fr1_origin, |r| {
|
.best_blame_constraint(fr1, fr1_origin, |r| self.provides_universal_region(r, fr1, fr2))
|
||||||
self.provides_universal_region(r, fr1, fr2)
|
.0;
|
||||||
});
|
|
||||||
(category, cause)
|
(category, cause)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2010,7 +2014,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
from_region: RegionVid,
|
from_region: RegionVid,
|
||||||
from_region_origin: NllRegionVariableOrigin,
|
from_region_origin: NllRegionVariableOrigin,
|
||||||
target_test: impl Fn(RegionVid) -> bool,
|
target_test: impl Fn(RegionVid) -> bool,
|
||||||
) -> BlameConstraint<'tcx> {
|
) -> (BlameConstraint<'tcx>, Vec<ExtraConstraintInfo>) {
|
||||||
// Find all paths
|
// Find all paths
|
||||||
let (path, target_region) =
|
let (path, target_region) =
|
||||||
self.find_constraint_paths_between_regions(from_region, target_test).unwrap();
|
self.find_constraint_paths_between_regions(from_region, target_test).unwrap();
|
||||||
|
@ -2026,6 +2030,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let mut extra_info = vec![];
|
||||||
|
for constraint in path.iter() {
|
||||||
|
let outlived = constraint.sub;
|
||||||
|
let Some(origin) = self.var_infos.get(outlived) else { continue; };
|
||||||
|
let RegionVariableOrigin::Nll(NllRegionVariableOrigin::Placeholder(p)) = origin.origin else { continue; };
|
||||||
|
debug!(?constraint, ?p);
|
||||||
|
let ConstraintCategory::Predicate(span) = constraint.category else { continue; };
|
||||||
|
extra_info.push(ExtraConstraintInfo::PlaceholderFromPredicate(span));
|
||||||
|
// We only want to point to one
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint.
|
// We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint.
|
||||||
// Instead, we use it to produce an improved `ObligationCauseCode`.
|
// Instead, we use it to produce an improved `ObligationCauseCode`.
|
||||||
// FIXME - determine what we should do if we encounter multiple `ConstraintCategory::Predicate`
|
// FIXME - determine what we should do if we encounter multiple `ConstraintCategory::Predicate`
|
||||||
|
@ -2073,6 +2089,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
from_closure,
|
from_closure,
|
||||||
cause: ObligationCause::new(span, CRATE_HIR_ID, cause_code),
|
cause: ObligationCause::new(span, CRATE_HIR_ID, cause_code),
|
||||||
variance_info: constraint.variance_info,
|
variance_info: constraint.variance_info,
|
||||||
|
outlives_constraint: *constraint,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -2174,7 +2191,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
let best_choice =
|
let best_choice =
|
||||||
if blame_source { range.rev().find(find_region) } else { range.find(find_region) };
|
if blame_source { range.rev().find(find_region) } else { range.find(find_region) };
|
||||||
|
|
||||||
debug!(?best_choice, ?blame_source);
|
debug!(?best_choice, ?blame_source, ?extra_info);
|
||||||
|
|
||||||
if let Some(i) = best_choice {
|
if let Some(i) = best_choice {
|
||||||
if let Some(next) = categorized_path.get(i + 1) {
|
if let Some(next) = categorized_path.get(i + 1) {
|
||||||
|
@ -2183,7 +2200,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
{
|
{
|
||||||
// The return expression is being influenced by the return type being
|
// The return expression is being influenced by the return type being
|
||||||
// impl Trait, point at the return type and not the return expr.
|
// impl Trait, point at the return type and not the return expr.
|
||||||
return next.clone();
|
return (next.clone(), extra_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2203,7 +2220,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return categorized_path[i].clone();
|
return (categorized_path[i].clone(), extra_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If that search fails, that is.. unusual. Maybe everything
|
// If that search fails, that is.. unusual. Maybe everything
|
||||||
|
@ -2213,7 +2230,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
categorized_path.sort_by(|p0, p1| p0.category.cmp(&p1.category));
|
categorized_path.sort_by(|p0, p1| p0.category.cmp(&p1.category));
|
||||||
debug!("sorted_path={:#?}", categorized_path);
|
debug!("sorted_path={:#?}", categorized_path);
|
||||||
|
|
||||||
categorized_path.remove(0)
|
(categorized_path.remove(0), extra_info)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
||||||
|
@ -2295,7 +2312,13 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx
|
||||||
outlives_requirement={:?}",
|
outlives_requirement={:?}",
|
||||||
region, outlived_region, outlives_requirement,
|
region, outlived_region, outlives_requirement,
|
||||||
);
|
);
|
||||||
ty::Binder::dummy(ty::OutlivesPredicate(region.into(), outlived_region))
|
(
|
||||||
|
ty::Binder::dummy(ty::OutlivesPredicate(
|
||||||
|
region.into(),
|
||||||
|
outlived_region,
|
||||||
|
)),
|
||||||
|
ConstraintCategory::BoringNoLocation,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
ClosureOutlivesSubject::Ty(ty) => {
|
ClosureOutlivesSubject::Ty(ty) => {
|
||||||
|
@ -2305,7 +2328,10 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx
|
||||||
outlives_requirement={:?}",
|
outlives_requirement={:?}",
|
||||||
ty, outlived_region, outlives_requirement,
|
ty, outlived_region, outlives_requirement,
|
||||||
);
|
);
|
||||||
ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), outlived_region))
|
(
|
||||||
|
ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), outlived_region)),
|
||||||
|
ConstraintCategory::BoringNoLocation,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -2319,4 +2345,5 @@ pub struct BlameConstraint<'tcx> {
|
||||||
pub from_closure: bool,
|
pub from_closure: bool,
|
||||||
pub cause: ObligationCause<'tcx>,
|
pub cause: ObligationCause<'tcx>,
|
||||||
pub variance_info: ty::VarianceDiagInfo<'tcx>,
|
pub variance_info: ty::VarianceDiagInfo<'tcx>,
|
||||||
|
pub outlives_constraint: OutlivesConstraint<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
/// constraints should occur within this method so that those
|
/// constraints should occur within this method so that those
|
||||||
/// constraints can be properly localized!**
|
/// constraints can be properly localized!**
|
||||||
#[instrument(skip(self, op), level = "trace")]
|
#[instrument(skip(self, op), level = "trace")]
|
||||||
pub(super) fn fully_perform_op<R, Op>(
|
pub(super) fn fully_perform_op<R: fmt::Debug, Op>(
|
||||||
&mut self,
|
&mut self,
|
||||||
locations: Locations,
|
locations: Locations,
|
||||||
category: ConstraintCategory<'tcx>,
|
category: ConstraintCategory<'tcx>,
|
||||||
|
@ -39,6 +39,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
|
|
||||||
let TypeOpOutput { output, constraints, error_info } = op.fully_perform(self.infcx)?;
|
let TypeOpOutput { output, constraints, error_info } = op.fully_perform(self.infcx)?;
|
||||||
|
|
||||||
|
debug!(?output, ?constraints);
|
||||||
|
|
||||||
if let Some(data) = constraints {
|
if let Some(data) = constraints {
|
||||||
self.push_region_constraints(locations, category, data);
|
self.push_region_constraints(locations, category, data);
|
||||||
}
|
}
|
||||||
|
@ -102,6 +104,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(self))]
|
||||||
pub(super) fn normalize_and_prove_instantiated_predicates(
|
pub(super) fn normalize_and_prove_instantiated_predicates(
|
||||||
&mut self,
|
&mut self,
|
||||||
// Keep this parameter for now, in case we start using
|
// Keep this parameter for now, in case we start using
|
||||||
|
@ -116,8 +119,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
.zip(instantiated_predicates.spans.into_iter())
|
.zip(instantiated_predicates.spans.into_iter())
|
||||||
{
|
{
|
||||||
debug!(?predicate);
|
debug!(?predicate);
|
||||||
let predicate = self.normalize(predicate, locations);
|
let category = ConstraintCategory::Predicate(span);
|
||||||
self.prove_predicate(predicate, locations, ConstraintCategory::Predicate(span));
|
let predicate = self.normalize_with_category(predicate, locations, category);
|
||||||
|
self.prove_predicate(predicate, locations, category);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,15 +157,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
|
||||||
pub(super) fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
|
pub(super) fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
|
||||||
|
where
|
||||||
|
T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
|
||||||
|
{
|
||||||
|
self.normalize_with_category(value, location, ConstraintCategory::Boring)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self), level = "debug")]
|
||||||
|
pub(super) fn normalize_with_category<T>(
|
||||||
|
&mut self,
|
||||||
|
value: T,
|
||||||
|
location: impl NormalizeLocation,
|
||||||
|
category: ConstraintCategory<'tcx>,
|
||||||
|
) -> T
|
||||||
where
|
where
|
||||||
T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
|
T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
|
||||||
{
|
{
|
||||||
let param_env = self.param_env;
|
let param_env = self.param_env;
|
||||||
self.fully_perform_op(
|
self.fully_perform_op(
|
||||||
location.to_locations(),
|
location.to_locations(),
|
||||||
ConstraintCategory::Boring,
|
category,
|
||||||
param_env.and(type_op::normalize::Normalize::new(value)),
|
param_env.and(type_op::normalize::Normalize::new(value)),
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|NoSolution| {
|
.unwrap_or_else(|NoSolution| {
|
||||||
|
|
|
@ -86,7 +86,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx>) {
|
fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx>) {
|
||||||
debug!("generate: constraints at: {:#?}", self.locations);
|
debug!("generate: constraints at: {:#?}", self.locations);
|
||||||
|
|
||||||
// Extract out various useful fields we'll need below.
|
// Extract out various useful fields we'll need below.
|
||||||
|
@ -98,15 +98,18 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||||
// region constraints like `for<'a> 'a: 'b`. At some point
|
// region constraints like `for<'a> 'a: 'b`. At some point
|
||||||
// when we move to universes, we will, and this assertion
|
// when we move to universes, we will, and this assertion
|
||||||
// will start to fail.
|
// will start to fail.
|
||||||
let ty::OutlivesPredicate(k1, r2) = query_constraint.no_bound_vars().unwrap_or_else(|| {
|
let ty::OutlivesPredicate(k1, r2) =
|
||||||
bug!("query_constraint {:?} contained bound vars", query_constraint,);
|
query_constraint.0.no_bound_vars().unwrap_or_else(|| {
|
||||||
});
|
bug!("query_constraint {:?} contained bound vars", query_constraint,);
|
||||||
|
});
|
||||||
|
|
||||||
|
let constraint_category = query_constraint.1;
|
||||||
|
|
||||||
match k1.unpack() {
|
match k1.unpack() {
|
||||||
GenericArgKind::Lifetime(r1) => {
|
GenericArgKind::Lifetime(r1) => {
|
||||||
let r1_vid = self.to_region_vid(r1);
|
let r1_vid = self.to_region_vid(r1);
|
||||||
let r2_vid = self.to_region_vid(r2);
|
let r2_vid = self.to_region_vid(r2);
|
||||||
self.add_outlives(r1_vid, r2_vid);
|
self.add_outlives(r1_vid, r2_vid, constraint_category);
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericArgKind::Type(t1) => {
|
GenericArgKind::Type(t1) => {
|
||||||
|
@ -121,7 +124,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||||
Some(implicit_region_bound),
|
Some(implicit_region_bound),
|
||||||
param_env,
|
param_env,
|
||||||
)
|
)
|
||||||
.type_must_outlive(origin, t1, r2);
|
.type_must_outlive(origin, t1, r2, constraint_category);
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericArgKind::Const(_) => {
|
GenericArgKind::Const(_) => {
|
||||||
|
@ -168,10 +171,19 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) {
|
fn add_outlives(
|
||||||
|
&mut self,
|
||||||
|
sup: ty::RegionVid,
|
||||||
|
sub: ty::RegionVid,
|
||||||
|
category: ConstraintCategory<'tcx>,
|
||||||
|
) {
|
||||||
|
let category = match self.category {
|
||||||
|
ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation => category,
|
||||||
|
_ => self.category,
|
||||||
|
};
|
||||||
self.constraints.outlives_constraints.push(OutlivesConstraint {
|
self.constraints.outlives_constraints.push(OutlivesConstraint {
|
||||||
locations: self.locations,
|
locations: self.locations,
|
||||||
category: self.category,
|
category,
|
||||||
span: self.span,
|
span: self.span,
|
||||||
sub,
|
sub,
|
||||||
sup,
|
sup,
|
||||||
|
@ -191,10 +203,11 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'
|
||||||
_origin: SubregionOrigin<'tcx>,
|
_origin: SubregionOrigin<'tcx>,
|
||||||
a: ty::Region<'tcx>,
|
a: ty::Region<'tcx>,
|
||||||
b: ty::Region<'tcx>,
|
b: ty::Region<'tcx>,
|
||||||
|
constraint_category: ConstraintCategory<'tcx>,
|
||||||
) {
|
) {
|
||||||
let b = self.to_region_vid(b);
|
let b = self.to_region_vid(b);
|
||||||
let a = self.to_region_vid(a);
|
let a = self.to_region_vid(a);
|
||||||
self.add_outlives(b, a);
|
self.add_outlives(b, a, constraint_category);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_verify(
|
fn push_verify(
|
||||||
|
|
|
@ -312,6 +312,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
|
fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
|
||||||
|
debug!(?constant, ?location, "visit_constant");
|
||||||
|
|
||||||
self.super_constant(constant, location);
|
self.super_constant(constant, location);
|
||||||
let ty = self.sanitize_type(constant, constant.literal.ty());
|
let ty = self.sanitize_type(constant, constant.literal.ty());
|
||||||
|
|
||||||
|
@ -1815,6 +1817,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) {
|
fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) {
|
||||||
|
debug!(?op, ?location, "check_operand");
|
||||||
|
|
||||||
if let Operand::Constant(constant) = op {
|
if let Operand::Constant(constant) = op {
|
||||||
let maybe_uneval = match constant.literal {
|
let maybe_uneval = match constant.literal {
|
||||||
ConstantKind::Val(..) | ConstantKind::Ty(_) => None,
|
ConstantKind::Val(..) | ConstantKind::Ty(_) => None,
|
||||||
|
@ -2593,7 +2597,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter_map(|(idx, constraint)| {
|
.filter_map(|(idx, constraint)| {
|
||||||
let ty::OutlivesPredicate(k1, r2) =
|
let ty::OutlivesPredicate(k1, r2) =
|
||||||
constraint.no_bound_vars().unwrap_or_else(|| {
|
constraint.0.no_bound_vars().unwrap_or_else(|| {
|
||||||
bug!("query_constraint {:?} contained bound vars", constraint,);
|
bug!("query_constraint {:?} contained bound vars", constraint,);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,7 @@ infer_relate_param_bound = ...so that the type `{$name}` will meet its required
|
||||||
infer_relate_param_bound_2 = ...that is required by this bound
|
infer_relate_param_bound_2 = ...that is required by this bound
|
||||||
infer_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied
|
infer_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied
|
||||||
infer_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait
|
infer_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait
|
||||||
|
infer_ascribe_user_type_prove_predicate = ...so that the where clause holds
|
||||||
|
|
||||||
infer_nothing = {""}
|
infer_nothing = {""}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ use rustc_data_structures::captures::Captures;
|
||||||
use rustc_index::vec::Idx;
|
use rustc_index::vec::Idx;
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc_middle::arena::ArenaAllocatable;
|
use rustc_middle::arena::ArenaAllocatable;
|
||||||
|
use rustc_middle::mir::ConstraintCategory;
|
||||||
use rustc_middle::ty::error::TypeError;
|
use rustc_middle::ty::error::TypeError;
|
||||||
use rustc_middle::ty::fold::TypeFoldable;
|
use rustc_middle::ty::fold::TypeFoldable;
|
||||||
use rustc_middle::ty::relate::TypeRelation;
|
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| {
|
let region_constraints = self.with_region_constraints(|region_constraints| {
|
||||||
make_query_region_constraints(
|
make_query_region_constraints(
|
||||||
tcx,
|
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,
|
region_constraints,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
@ -248,6 +251,8 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||||
// the original values `v_o` that was canonicalized into a
|
// the original values `v_o` that was canonicalized into a
|
||||||
// variable...
|
// variable...
|
||||||
|
|
||||||
|
let constraint_category = cause.to_constraint_category();
|
||||||
|
|
||||||
for (index, original_value) in original_values.var_values.iter().enumerate() {
|
for (index, original_value) in original_values.var_values.iter().enumerate() {
|
||||||
// ...with the value `v_r` of that variable from the query.
|
// ...with the value `v_r` of that variable from the query.
|
||||||
let result_value = query_response.substitute_projected(self.tcx, &result_subst, |v| {
|
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)) => {
|
(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`.
|
// To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`.
|
||||||
if v_o != v_r {
|
if v_o != v_r {
|
||||||
output_query_region_constraints
|
output_query_region_constraints.outlives.push((
|
||||||
.outlives
|
ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r)),
|
||||||
.push(ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r)));
|
constraint_category,
|
||||||
output_query_region_constraints
|
));
|
||||||
.outlives
|
output_query_region_constraints.outlives.push((
|
||||||
.push(ty::Binder::dummy(ty::OutlivesPredicate(v_r.into(), v_o)));
|
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
|
// Screen out `'a: 'a` cases -- we skip the binder here but
|
||||||
// only compare the inner values to one another, so they are still at
|
// only compare the inner values to one another, so they are still at
|
||||||
// consistent binding levels.
|
// 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 }
|
if k1 != r2.into() { Some(r_c) } else { None }
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
@ -559,7 +566,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||||
cause: ObligationCause<'tcx>,
|
cause: ObligationCause<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
) -> Obligation<'tcx, ty::Predicate<'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() {
|
let atom = match k1.unpack() {
|
||||||
GenericArgKind::Lifetime(r1) => {
|
GenericArgKind::Lifetime(r1) => {
|
||||||
|
@ -574,7 +581,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||||
span_bug!(cause.span, "unexpected const outlives {:?}", predicate);
|
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)
|
Obligation::new(cause, param_env, predicate)
|
||||||
}
|
}
|
||||||
|
@ -625,7 +632,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||||
/// creates query region constraints.
|
/// creates query region constraints.
|
||||||
pub fn make_query_region_constraints<'tcx>(
|
pub fn make_query_region_constraints<'tcx>(
|
||||||
tcx: TyCtxt<'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>,
|
region_constraints: &RegionConstraintData<'tcx>,
|
||||||
) -> QueryRegionConstraints<'tcx> {
|
) -> QueryRegionConstraints<'tcx> {
|
||||||
let RegionConstraintData { constraints, verifys, givens, member_constraints } =
|
let RegionConstraintData { constraints, verifys, givens, member_constraints } =
|
||||||
|
@ -638,26 +645,31 @@ pub fn make_query_region_constraints<'tcx>(
|
||||||
|
|
||||||
let outlives: Vec<_> = constraints
|
let outlives: Vec<_> = constraints
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(k, _)| match *k {
|
.map(|(k, origin)| {
|
||||||
// Swap regions because we are going from sub (<=) to outlives
|
// no bound vars in the code above
|
||||||
// (>=).
|
let constraint = ty::Binder::dummy(match *k {
|
||||||
Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
|
// Swap regions because we are going from sub (<=) to outlives
|
||||||
tcx.mk_region(ty::ReVar(v2)).into(),
|
// (>=).
|
||||||
tcx.mk_region(ty::ReVar(v1)),
|
Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
|
||||||
),
|
tcx.mk_region(ty::ReVar(v2)).into(),
|
||||||
Constraint::VarSubReg(v1, r2) => {
|
tcx.mk_region(ty::ReVar(v1)),
|
||||||
ty::OutlivesPredicate(r2.into(), tcx.mk_region(ty::ReVar(v1)))
|
),
|
||||||
}
|
Constraint::VarSubReg(v1, r2) => {
|
||||||
Constraint::RegSubVar(r1, v2) => {
|
ty::OutlivesPredicate(r2.into(), tcx.mk_region(ty::ReVar(v1)))
|
||||||
ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1)
|
}
|
||||||
}
|
Constraint::RegSubVar(r1, v2) => {
|
||||||
Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1),
|
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(
|
.chain(
|
||||||
outlives_obligations
|
outlives_obligations
|
||||||
.map(|(ty, r)| ty::OutlivesPredicate(ty.into(), r))
|
// no bound vars in the code above
|
||||||
.map(ty::Binder::dummy), // no bound vars in the code above
|
.map(|(ty, r, constraint_category)| {
|
||||||
|
(ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), r)), constraint_category)
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
infer::CheckAssociatedTypeBounds { ref parent, .. } => {
|
infer::CheckAssociatedTypeBounds { ref parent, .. } => {
|
||||||
self.note_region_origin(err, &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
|
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::{ConstVarValue, ConstVariableValue};
|
||||||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
|
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
|
||||||
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
|
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
|
||||||
|
use rustc_middle::mir::ConstraintCategory;
|
||||||
use rustc_middle::traits::select;
|
use rustc_middle::traits::select;
|
||||||
use rustc_middle::ty::abstract_const::{AbstractConst, FailureKind};
|
use rustc_middle::ty::abstract_const::{AbstractConst, FailureKind};
|
||||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
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
|
/// Comparing the signature and requirements of an impl method against
|
||||||
/// the containing trait.
|
/// 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
|
/// Checking that the bounds of a trait's associated type hold for a given impl
|
||||||
CheckAssociatedTypeBounds {
|
CheckAssociatedTypeBounds {
|
||||||
|
@ -416,12 +421,24 @@ pub enum SubregionOrigin<'tcx> {
|
||||||
impl_item_def_id: LocalDefId,
|
impl_item_def_id: LocalDefId,
|
||||||
trait_item_def_id: DefId,
|
trait_item_def_id: DefId,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
AscribeUserTypeProvePredicate(Span),
|
||||||
}
|
}
|
||||||
|
|
||||||
// `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger.
|
// `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger.
|
||||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||||
static_assert_size!(SubregionOrigin<'_>, 32);
|
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:
|
/// Times when we replace late-bound regions with variables:
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum LateBoundRegionConversionTime {
|
pub enum LateBoundRegionConversionTime {
|
||||||
|
@ -1988,6 +2005,7 @@ impl<'tcx> SubregionOrigin<'tcx> {
|
||||||
DataBorrowed(_, a) => a,
|
DataBorrowed(_, a) => a,
|
||||||
ReferenceOutlivesReferent(_, a) => a,
|
ReferenceOutlivesReferent(_, a) => a,
|
||||||
CompareImplItemObligation { span, .. } => span,
|
CompareImplItemObligation { span, .. } => span,
|
||||||
|
AscribeUserTypeProvePredicate(span) => span,
|
||||||
CheckAssociatedTypeBounds { ref parent, .. } => parent.span(),
|
CheckAssociatedTypeBounds { ref parent, .. } => parent.span(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2020,6 +2038,10 @@ impl<'tcx> SubregionOrigin<'tcx> {
|
||||||
parent: Box::new(default()),
|
parent: Box::new(default()),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
traits::ObligationCauseCode::AscribeUserTypeProvePredicate(span) => {
|
||||||
|
SubregionOrigin::AscribeUserTypeProvePredicate(span)
|
||||||
|
}
|
||||||
|
|
||||||
_ => default(),
|
_ => default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,7 @@ use crate::infer::{
|
||||||
use crate::traits::{ObligationCause, ObligationCauseCode};
|
use crate::traits::{ObligationCause, ObligationCauseCode};
|
||||||
use rustc_data_structures::undo_log::UndoLogs;
|
use rustc_data_structures::undo_log::UndoLogs;
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
|
use rustc_middle::mir::ConstraintCategory;
|
||||||
use rustc_middle::ty::subst::GenericArgKind;
|
use rustc_middle::ty::subst::GenericArgKind;
|
||||||
use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeVisitable};
|
use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeVisitable};
|
||||||
use smallvec::smallvec;
|
use smallvec::smallvec;
|
||||||
|
@ -163,7 +164,8 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||||
|
|
||||||
let outlives =
|
let outlives =
|
||||||
&mut TypeOutlives::new(self, self.tcx, ®ion_bound_pairs, None, param_env);
|
&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>,
|
origin: SubregionOrigin<'tcx>,
|
||||||
a: ty::Region<'tcx>,
|
a: ty::Region<'tcx>,
|
||||||
b: ty::Region<'tcx>,
|
b: ty::Region<'tcx>,
|
||||||
|
constraint_category: ConstraintCategory<'tcx>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn push_verify(
|
fn push_verify(
|
||||||
|
@ -255,12 +258,13 @@ where
|
||||||
origin: infer::SubregionOrigin<'tcx>,
|
origin: infer::SubregionOrigin<'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
region: ty::Region<'tcx>,
|
region: ty::Region<'tcx>,
|
||||||
|
category: ConstraintCategory<'tcx>,
|
||||||
) {
|
) {
|
||||||
assert!(!ty.has_escaping_bound_vars());
|
assert!(!ty.has_escaping_bound_vars());
|
||||||
|
|
||||||
let mut components = smallvec![];
|
let mut components = smallvec![];
|
||||||
push_outlives_components(self.tcx, ty, &mut components);
|
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(
|
fn components_must_outlive(
|
||||||
|
@ -268,12 +272,13 @@ where
|
||||||
origin: infer::SubregionOrigin<'tcx>,
|
origin: infer::SubregionOrigin<'tcx>,
|
||||||
components: &[Component<'tcx>],
|
components: &[Component<'tcx>],
|
||||||
region: ty::Region<'tcx>,
|
region: ty::Region<'tcx>,
|
||||||
|
category: ConstraintCategory<'tcx>,
|
||||||
) {
|
) {
|
||||||
for component in components.iter() {
|
for component in components.iter() {
|
||||||
let origin = origin.clone();
|
let origin = origin.clone();
|
||||||
match component {
|
match component {
|
||||||
Component::Region(region1) => {
|
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) => {
|
Component::Param(param_ty) => {
|
||||||
self.param_ty_must_outlive(origin, region, *param_ty);
|
self.param_ty_must_outlive(origin, region, *param_ty);
|
||||||
|
@ -282,7 +287,7 @@ where
|
||||||
self.projection_must_outlive(origin, region, *projection_ty);
|
self.projection_must_outlive(origin, region, *projection_ty);
|
||||||
}
|
}
|
||||||
Component::EscapingProjection(subcomponents) => {
|
Component::EscapingProjection(subcomponents) => {
|
||||||
self.components_must_outlive(origin, &subcomponents, region);
|
self.components_must_outlive(origin, &subcomponents, region, category);
|
||||||
}
|
}
|
||||||
Component::UnresolvedInferenceVariable(v) => {
|
Component::UnresolvedInferenceVariable(v) => {
|
||||||
// ignore this, we presume it will yield an error
|
// ignore this, we presume it will yield an error
|
||||||
|
@ -389,13 +394,19 @@ where
|
||||||
if approx_env_bounds.is_empty() && trait_bounds.is_empty() && needs_infer {
|
if approx_env_bounds.is_empty() && trait_bounds.is_empty() && needs_infer {
|
||||||
debug!("projection_must_outlive: no declared bounds");
|
debug!("projection_must_outlive: no declared bounds");
|
||||||
|
|
||||||
|
let constraint = origin.to_constraint_category();
|
||||||
for k in projection_ty.substs {
|
for k in projection_ty.substs {
|
||||||
match k.unpack() {
|
match k.unpack() {
|
||||||
GenericArgKind::Lifetime(lt) => {
|
GenericArgKind::Lifetime(lt) => {
|
||||||
self.delegate.push_sub_region_constraint(origin.clone(), region, lt);
|
self.delegate.push_sub_region_constraint(
|
||||||
|
origin.clone(),
|
||||||
|
region,
|
||||||
|
lt,
|
||||||
|
constraint,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
GenericArgKind::Type(ty) => {
|
GenericArgKind::Type(ty) => {
|
||||||
self.type_must_outlive(origin.clone(), ty, region);
|
self.type_must_outlive(origin.clone(), ty, region, constraint);
|
||||||
}
|
}
|
||||||
GenericArgKind::Const(_) => {
|
GenericArgKind::Const(_) => {
|
||||||
// Const parameters don't impose constraints.
|
// Const parameters don't impose constraints.
|
||||||
|
@ -433,7 +444,8 @@ where
|
||||||
let unique_bound = trait_bounds[0];
|
let unique_bound = trait_bounds[0];
|
||||||
debug!("projection_must_outlive: unique trait bound = {:?}", unique_bound);
|
debug!("projection_must_outlive: unique trait bound = {:?}", unique_bound);
|
||||||
debug!("projection_must_outlive: unique declared bound appears in trait ref");
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,6 +467,7 @@ impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'tcx> {
|
||||||
origin: SubregionOrigin<'tcx>,
|
origin: SubregionOrigin<'tcx>,
|
||||||
a: ty::Region<'tcx>,
|
a: ty::Region<'tcx>,
|
||||||
b: ty::Region<'tcx>,
|
b: ty::Region<'tcx>,
|
||||||
|
_constraint_category: ConstraintCategory<'tcx>,
|
||||||
) {
|
) {
|
||||||
self.sub_regions(origin, a, b)
|
self.sub_regions(origin, a, b)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
|
//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
|
||||||
|
|
||||||
use crate::infer::MemberConstraint;
|
use crate::infer::MemberConstraint;
|
||||||
|
use crate::mir::ConstraintCategory;
|
||||||
use crate::ty::subst::GenericArg;
|
use crate::ty::subst::GenericArg;
|
||||||
use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
|
use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
|
@ -301,8 +302,10 @@ impl<'tcx, V> Canonical<'tcx, V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type QueryOutlivesConstraint<'tcx> =
|
pub type QueryOutlivesConstraint<'tcx> = (
|
||||||
ty::Binder<'tcx, ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>;
|
ty::Binder<'tcx, ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>,
|
||||||
|
ConstraintCategory<'tcx>,
|
||||||
|
);
|
||||||
|
|
||||||
TrivialTypeTraversalAndLiftImpls! {
|
TrivialTypeTraversalAndLiftImpls! {
|
||||||
for <'tcx> {
|
for <'tcx> {
|
||||||
|
|
|
@ -327,7 +327,7 @@ rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
|
||||||
///
|
///
|
||||||
/// See also `rustc_const_eval::borrow_check::constraints`.
|
/// See also `rustc_const_eval::borrow_check::constraints`.
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||||
#[derive(TyEncodable, TyDecodable, HashStable)]
|
#[derive(TyEncodable, TyDecodable, HashStable, Lift, TypeVisitable, TypeFoldable)]
|
||||||
pub enum ConstraintCategory<'tcx> {
|
pub enum ConstraintCategory<'tcx> {
|
||||||
Return(ReturnConstraint),
|
Return(ReturnConstraint),
|
||||||
Yield,
|
Yield,
|
||||||
|
@ -369,7 +369,7 @@ pub enum ConstraintCategory<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||||
#[derive(TyEncodable, TyDecodable, HashStable)]
|
#[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)]
|
||||||
pub enum ReturnConstraint {
|
pub enum ReturnConstraint {
|
||||||
Normal,
|
Normal,
|
||||||
ClosureUpvar(Field),
|
ClosureUpvar(Field),
|
||||||
|
|
|
@ -10,6 +10,7 @@ mod structural_impls;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
use crate::infer::canonical::Canonical;
|
use crate::infer::canonical::Canonical;
|
||||||
|
use crate::mir::ConstraintCategory;
|
||||||
use crate::ty::abstract_const::NotConstEvaluatable;
|
use crate::ty::abstract_const::NotConstEvaluatable;
|
||||||
use crate::ty::subst::SubstsRef;
|
use crate::ty::subst::SubstsRef;
|
||||||
use crate::ty::{self, AdtKind, Ty, TyCtxt};
|
use crate::ty::{self, AdtKind, Ty, TyCtxt};
|
||||||
|
@ -183,6 +184,16 @@ impl<'tcx> ObligationCause<'tcx> {
|
||||||
variant(DerivedObligationCause { parent_trait_pred, parent_code: self.code }).into();
|
variant(DerivedObligationCause { parent_trait_pred, parent_code: self.code }).into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> {
|
||||||
|
match self.code() {
|
||||||
|
MatchImpl(cause, _) => cause.to_constraint_category(),
|
||||||
|
AscribeUserTypeProvePredicate(predicate_span) => {
|
||||||
|
ConstraintCategory::Predicate(*predicate_span)
|
||||||
|
}
|
||||||
|
_ => ConstraintCategory::BoringNoLocation,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
|
||||||
|
@ -418,6 +429,8 @@ pub enum ObligationCauseCode<'tcx> {
|
||||||
is_lit: bool,
|
is_lit: bool,
|
||||||
output_ty: Option<Ty<'tcx>>,
|
output_ty: Option<Ty<'tcx>>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
AscribeUserTypeProvePredicate(Span),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The 'location' at which we try to perform HIR-based wf checking.
|
/// The 'location' at which we try to perform HIR-based wf checking.
|
||||||
|
|
|
@ -2256,7 +2256,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
| ObligationCauseCode::QuestionMark
|
| ObligationCauseCode::QuestionMark
|
||||||
| ObligationCauseCode::CheckAssociatedTypeBounds { .. }
|
| ObligationCauseCode::CheckAssociatedTypeBounds { .. }
|
||||||
| ObligationCauseCode::LetElse
|
| ObligationCauseCode::LetElse
|
||||||
| ObligationCauseCode::BinOp { .. } => {}
|
| ObligationCauseCode::BinOp { .. }
|
||||||
|
| ObligationCauseCode::AscribeUserTypeProvePredicate(..) => {}
|
||||||
ObligationCauseCode::SliceOrArrayElem => {
|
ObligationCauseCode::SliceOrArrayElem => {
|
||||||
err.note("slice and array elements must have `Sized` type");
|
err.note("slice and array elements must have `Sized` type");
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,10 +48,11 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
|
||||||
T: TypeFoldable<'tcx>,
|
T: TypeFoldable<'tcx>,
|
||||||
{
|
{
|
||||||
debug!(
|
debug!(
|
||||||
"normalize::<{}>(value={:?}, param_env={:?})",
|
"normalize::<{}>(value={:?}, param_env={:?}, cause={:?})",
|
||||||
std::any::type_name::<T>(),
|
std::any::type_name::<T>(),
|
||||||
value,
|
value,
|
||||||
self.param_env,
|
self.param_env,
|
||||||
|
self.cause,
|
||||||
);
|
);
|
||||||
if !needs_normalization(&value, self.param_env.reveal()) {
|
if !needs_normalization(&value, self.param_env.reveal()) {
|
||||||
return Ok(Normalized { value, obligations: vec![] });
|
return Ok(Normalized { value, obligations: vec![] });
|
||||||
|
|
|
@ -23,7 +23,7 @@ impl<F, G> CustomTypeOp<F, G> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, F, R, G> super::TypeOp<'tcx> for CustomTypeOp<F, G>
|
impl<'tcx, F, R: fmt::Debug, G> super::TypeOp<'tcx> for CustomTypeOp<F, G>
|
||||||
where
|
where
|
||||||
F: for<'a, 'cx> FnOnce(&'a InferCtxt<'cx, 'tcx>) -> Fallible<InferOk<'tcx, R>>,
|
F: for<'a, 'cx> FnOnce(&'a InferCtxt<'cx, 'tcx>) -> Fallible<InferOk<'tcx, R>>,
|
||||||
G: Fn() -> String,
|
G: Fn() -> String,
|
||||||
|
@ -89,8 +89,8 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
|
||||||
infcx.tcx,
|
infcx.tcx,
|
||||||
region_obligations
|
region_obligations
|
||||||
.iter()
|
.iter()
|
||||||
.map(|r_o| (r_o.sup_type, r_o.sub_region))
|
.map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category()))
|
||||||
.map(|(ty, r)| (infcx.resolve_vars_if_possible(ty), r)),
|
.map(|(ty, r, cc)| (infcx.resolve_vars_if_possible(ty), r, cc)),
|
||||||
®ion_constraint_data,
|
®ion_constraint_data,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ pub use rustc_middle::traits::query::type_op::*;
|
||||||
/// extract out the resulting region constraints (or an error if it
|
/// extract out the resulting region constraints (or an error if it
|
||||||
/// cannot be completed).
|
/// cannot be completed).
|
||||||
pub trait TypeOp<'tcx>: Sized + fmt::Debug {
|
pub trait TypeOp<'tcx>: Sized + fmt::Debug {
|
||||||
type Output;
|
type Output: fmt::Debug;
|
||||||
type ErrorInfo;
|
type ErrorInfo;
|
||||||
|
|
||||||
/// Processes the operation and all resulting obligations,
|
/// Processes the operation and all resulting obligations,
|
||||||
|
|
|
@ -3,7 +3,7 @@ use rustc_hir::def_id::DefId;
|
||||||
use rustc_infer::infer::at::ToTrace;
|
use rustc_infer::infer::at::ToTrace;
|
||||||
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
|
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
|
||||||
use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
|
use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
|
||||||
use rustc_infer::traits::TraitEngineExt as _;
|
use rustc_infer::traits::{ObligationCauseCode, TraitEngineExt as _};
|
||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
use rustc_middle::ty::subst::{GenericArg, Subst, UserSelfTy, UserSubsts};
|
use rustc_middle::ty::subst::{GenericArg, Subst, UserSelfTy, UserSubsts};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
|
@ -22,6 +22,7 @@ use rustc_trait_selection::traits::query::type_op::subtype::Subtype;
|
||||||
use rustc_trait_selection::traits::query::{Fallible, NoSolution};
|
use rustc_trait_selection::traits::query::{Fallible, NoSolution};
|
||||||
use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, TraitEngine};
|
use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, TraitEngine};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::iter::zip;
|
||||||
|
|
||||||
pub(crate) fn provide(p: &mut Providers) {
|
pub(crate) fn provide(p: &mut Providers) {
|
||||||
*p = Providers {
|
*p = Providers {
|
||||||
|
@ -61,28 +62,32 @@ pub fn type_op_ascribe_user_type_with_span<'a, 'tcx: 'a>(
|
||||||
mir_ty, def_id, user_substs
|
mir_ty, def_id, user_substs
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut cx = AscribeUserTypeCx { infcx, param_env, fulfill_cx };
|
let mut cx = AscribeUserTypeCx { infcx, param_env, span: span.unwrap_or(DUMMY_SP), fulfill_cx };
|
||||||
cx.relate_mir_and_user_ty(mir_ty, def_id, user_substs, span)?;
|
cx.relate_mir_and_user_ty(mir_ty, def_id, user_substs)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AscribeUserTypeCx<'me, 'tcx> {
|
struct AscribeUserTypeCx<'me, 'tcx> {
|
||||||
infcx: &'me InferCtxt<'me, 'tcx>,
|
infcx: &'me InferCtxt<'me, 'tcx>,
|
||||||
param_env: ParamEnv<'tcx>,
|
param_env: ParamEnv<'tcx>,
|
||||||
|
span: Span,
|
||||||
fulfill_cx: &'me mut dyn TraitEngine<'tcx>,
|
fulfill_cx: &'me mut dyn TraitEngine<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> {
|
impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> {
|
||||||
fn normalize<T>(&mut self, value: T) -> T
|
fn normalize<T>(&mut self, value: T) -> T
|
||||||
|
where
|
||||||
|
T: TypeFoldable<'tcx>,
|
||||||
|
{
|
||||||
|
self.normalize_with_cause(value, ObligationCause::misc(self.span, hir::CRATE_HIR_ID))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normalize_with_cause<T>(&mut self, value: T, cause: ObligationCause<'tcx>) -> T
|
||||||
where
|
where
|
||||||
T: TypeFoldable<'tcx>,
|
T: TypeFoldable<'tcx>,
|
||||||
{
|
{
|
||||||
self.infcx
|
self.infcx
|
||||||
.partially_normalize_associated_types_in(
|
.partially_normalize_associated_types_in(cause, self.param_env, value)
|
||||||
ObligationCause::misc(DUMMY_SP, hir::CRATE_HIR_ID),
|
|
||||||
self.param_env,
|
|
||||||
value,
|
|
||||||
)
|
|
||||||
.into_value_registering_obligations(self.infcx, self.fulfill_cx)
|
.into_value_registering_obligations(self.infcx, self.fulfill_cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,18 +96,13 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> {
|
||||||
T: ToTrace<'tcx>,
|
T: ToTrace<'tcx>,
|
||||||
{
|
{
|
||||||
self.infcx
|
self.infcx
|
||||||
.at(&ObligationCause::dummy(), self.param_env)
|
.at(&ObligationCause::dummy_with_span(self.span), self.param_env)
|
||||||
.relate(a, variance, b)?
|
.relate(a, variance, b)?
|
||||||
.into_value_registering_obligations(self.infcx, self.fulfill_cx);
|
.into_value_registering_obligations(self.infcx, self.fulfill_cx);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prove_predicate(&mut self, predicate: Predicate<'tcx>, span: Option<Span>) {
|
fn prove_predicate(&mut self, predicate: Predicate<'tcx>, cause: ObligationCause<'tcx>) {
|
||||||
let cause = if let Some(span) = span {
|
|
||||||
ObligationCause::dummy_with_span(span)
|
|
||||||
} else {
|
|
||||||
ObligationCause::dummy()
|
|
||||||
};
|
|
||||||
self.fulfill_cx.register_predicate_obligation(
|
self.fulfill_cx.register_predicate_obligation(
|
||||||
self.infcx,
|
self.infcx,
|
||||||
Obligation::new(cause, self.param_env, predicate),
|
Obligation::new(cause, self.param_env, predicate),
|
||||||
|
@ -126,7 +126,6 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> {
|
||||||
mir_ty: Ty<'tcx>,
|
mir_ty: Ty<'tcx>,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
user_substs: UserSubsts<'tcx>,
|
user_substs: UserSubsts<'tcx>,
|
||||||
span: Option<Span>,
|
|
||||||
) -> Result<(), NoSolution> {
|
) -> Result<(), NoSolution> {
|
||||||
let UserSubsts { user_self_ty, substs } = user_substs;
|
let UserSubsts { user_self_ty, substs } = user_substs;
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
|
@ -145,10 +144,22 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> {
|
||||||
// outlives" error messages.
|
// outlives" error messages.
|
||||||
let instantiated_predicates =
|
let instantiated_predicates =
|
||||||
self.tcx().predicates_of(def_id).instantiate(self.tcx(), substs);
|
self.tcx().predicates_of(def_id).instantiate(self.tcx(), substs);
|
||||||
|
|
||||||
|
let cause = ObligationCause::dummy_with_span(self.span);
|
||||||
|
|
||||||
debug!(?instantiated_predicates);
|
debug!(?instantiated_predicates);
|
||||||
for instantiated_predicate in instantiated_predicates.predicates {
|
for (instantiated_predicate, predicate_span) in
|
||||||
let instantiated_predicate = self.normalize(instantiated_predicate);
|
zip(instantiated_predicates.predicates, instantiated_predicates.spans)
|
||||||
self.prove_predicate(instantiated_predicate, span);
|
{
|
||||||
|
let span = if self.span == DUMMY_SP { predicate_span } else { self.span };
|
||||||
|
let cause = ObligationCause::new(
|
||||||
|
span,
|
||||||
|
hir::CRATE_HIR_ID,
|
||||||
|
ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span),
|
||||||
|
);
|
||||||
|
let instantiated_predicate =
|
||||||
|
self.normalize_with_cause(instantiated_predicate, cause.clone());
|
||||||
|
self.prove_predicate(instantiated_predicate, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
|
if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
|
||||||
|
@ -161,7 +172,7 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> {
|
||||||
self.prove_predicate(
|
self.prove_predicate(
|
||||||
ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into()))
|
ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into()))
|
||||||
.to_predicate(self.tcx()),
|
.to_predicate(self.tcx()),
|
||||||
span,
|
cause.clone(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +189,7 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> {
|
||||||
// which...could happen with normalization...
|
// which...could happen with normalization...
|
||||||
self.prove_predicate(
|
self.prove_predicate(
|
||||||
ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(self.tcx()),
|
ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(self.tcx()),
|
||||||
span,
|
cause,
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ use rustc_hir::ItemKind;
|
||||||
use rustc_infer::infer::outlives::env::{OutlivesEnvironment, RegionBoundPairs};
|
use rustc_infer::infer::outlives::env::{OutlivesEnvironment, RegionBoundPairs};
|
||||||
use rustc_infer::infer::outlives::obligations::TypeOutlives;
|
use rustc_infer::infer::outlives::obligations::TypeOutlives;
|
||||||
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
|
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
|
||||||
|
use rustc_middle::mir::ConstraintCategory;
|
||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
|
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
|
||||||
use rustc_middle::ty::trait_def::TraitSpecializationKind;
|
use rustc_middle::ty::trait_def::TraitSpecializationKind;
|
||||||
|
@ -663,7 +664,7 @@ fn ty_known_to_outlive<'tcx>(
|
||||||
resolve_regions_with_wf_tys(tcx, id, param_env, &wf_tys, |infcx, region_bound_pairs| {
|
resolve_regions_with_wf_tys(tcx, id, param_env, &wf_tys, |infcx, region_bound_pairs| {
|
||||||
let origin = infer::RelateParamBound(DUMMY_SP, ty, None);
|
let origin = infer::RelateParamBound(DUMMY_SP, ty, None);
|
||||||
let outlives = &mut TypeOutlives::new(infcx, tcx, region_bound_pairs, None, param_env);
|
let outlives = &mut TypeOutlives::new(infcx, tcx, region_bound_pairs, None, param_env);
|
||||||
outlives.type_must_outlive(origin, ty, region);
|
outlives.type_must_outlive(origin, ty, region, ConstraintCategory::BoringNoLocation);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -681,7 +682,12 @@ fn region_known_to_outlive<'tcx>(
|
||||||
use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
|
use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
|
||||||
let origin = infer::RelateRegionParamBound(DUMMY_SP);
|
let origin = infer::RelateRegionParamBound(DUMMY_SP);
|
||||||
// `region_a: region_b` -> `region_b <= region_a`
|
// `region_a: region_b` -> `region_b <= region_a`
|
||||||
infcx.push_sub_region_constraint(origin, region_b, region_a);
|
infcx.push_sub_region_constraint(
|
||||||
|
origin,
|
||||||
|
region_b,
|
||||||
|
region_a,
|
||||||
|
ConstraintCategory::BoringNoLocation,
|
||||||
|
);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
35
src/test/ui/generic-associated-types/bugs/hrtb-implied-1.rs
Normal file
35
src/test/ui/generic-associated-types/bugs/hrtb-implied-1.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// check-fail
|
||||||
|
// known-bug
|
||||||
|
|
||||||
|
// This gives us problems because `for<'a> I::Item<'a>: Debug` should mean "for
|
||||||
|
// all 'a where I::Item<'a> is WF", but really means "for all 'a possible"
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
pub trait LendingIterator {
|
||||||
|
type Item<'this>
|
||||||
|
where
|
||||||
|
Self: 'this;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WindowsMut<'x> {
|
||||||
|
slice: &'x (),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'y> LendingIterator for WindowsMut<'y> {
|
||||||
|
type Item<'this> = &'this mut () where 'y: 'this;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_items<I>(_iter: I)
|
||||||
|
where
|
||||||
|
I: LendingIterator,
|
||||||
|
for<'a> I::Item<'a>: Debug,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let slice = &mut ();
|
||||||
|
//~^ temporary value dropped while borrowed
|
||||||
|
let windows = WindowsMut { slice };
|
||||||
|
print_items::<WindowsMut<'_>>(windows);
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
error[E0716]: temporary value dropped while borrowed
|
||||||
|
--> $DIR/hrtb-implied-1.rs:31:22
|
||||||
|
|
|
||||||
|
LL | let slice = &mut ();
|
||||||
|
| ^^ creates a temporary which is freed while still in use
|
||||||
|
...
|
||||||
|
LL | print_items::<WindowsMut<'_>>(windows);
|
||||||
|
| -------------------------------------- argument requires that borrow lasts for `'static`
|
||||||
|
LL | }
|
||||||
|
| - temporary value is freed at the end of this statement
|
||||||
|
|
|
||||||
|
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
|
||||||
|
--> $DIR/hrtb-implied-1.rs:26:26
|
||||||
|
|
|
||||||
|
LL | for<'a> I::Item<'a>: Debug,
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0716`.
|
40
src/test/ui/generic-associated-types/bugs/hrtb-implied-2.rs
Normal file
40
src/test/ui/generic-associated-types/bugs/hrtb-implied-2.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// check-fail
|
||||||
|
// known-bug
|
||||||
|
|
||||||
|
// This gives us problems because `for<'a> I::Item<'a>: Debug` should mean "for
|
||||||
|
// all 'a where I::Item<'a> is WF", but really means "for all 'a possible"
|
||||||
|
|
||||||
|
trait LendingIterator: Sized {
|
||||||
|
type Item<'a>
|
||||||
|
where
|
||||||
|
Self: 'a;
|
||||||
|
fn next(&mut self) -> Self::Item<'_>;
|
||||||
|
}
|
||||||
|
fn fails<I: LendingIterator, F>(iter: &mut I, f: F) -> bool
|
||||||
|
where
|
||||||
|
F: FnMut(I::Item<'_>),
|
||||||
|
{
|
||||||
|
let mut iter2 = Eat(iter, f);
|
||||||
|
let _next = iter2.next();
|
||||||
|
//~^ borrowed data escapes
|
||||||
|
true
|
||||||
|
}
|
||||||
|
impl<I: LendingIterator> LendingIterator for &mut I {
|
||||||
|
type Item<'a> = I::Item<'a> where Self:'a;
|
||||||
|
fn next(&mut self) -> Self::Item<'_> {
|
||||||
|
(**self).next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Eat<I, F>(I, F);
|
||||||
|
impl<I: LendingIterator, F> Iterator for Eat<I, F>
|
||||||
|
where
|
||||||
|
F: FnMut(I::Item<'_>),
|
||||||
|
{
|
||||||
|
type Item = ();
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,22 @@
|
||||||
|
error[E0521]: borrowed data escapes outside of function
|
||||||
|
--> $DIR/hrtb-implied-2.rs:18:17
|
||||||
|
|
|
||||||
|
LL | fn fails<I: LendingIterator, F>(iter: &mut I, f: F) -> bool
|
||||||
|
| ---- - let's call the lifetime of this reference `'1`
|
||||||
|
| |
|
||||||
|
| `iter` is a reference that is only valid in the function body
|
||||||
|
...
|
||||||
|
LL | let _next = iter2.next();
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| `iter` escapes the function body here
|
||||||
|
| argument requires that `'1` must outlive `'static`
|
||||||
|
|
|
||||||
|
= note: requirement occurs because of a mutable reference to `Eat<&mut I, F>`
|
||||||
|
= note: mutable references are invariant over their type parameter
|
||||||
|
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
|
||||||
|
= note: due to current limitations in the borrow checker, this implies a `'static` lifetime
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0521`.
|
23
src/test/ui/generic-associated-types/bugs/hrtb-implied-3.rs
Normal file
23
src/test/ui/generic-associated-types/bugs/hrtb-implied-3.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
trait LendingIterator {
|
||||||
|
type Item<'a>
|
||||||
|
where
|
||||||
|
Self: 'a;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LendingIterator for &str {
|
||||||
|
type Item<'a> = () where Self:'a;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trivial_bound<I>(_: I)
|
||||||
|
where
|
||||||
|
I: LendingIterator,
|
||||||
|
for<'a> I::Item<'a>: Sized,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fails(iter: &str) {
|
||||||
|
trivial_bound(iter);
|
||||||
|
//~^ borrowed data escapes
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,22 @@
|
||||||
|
error[E0521]: borrowed data escapes outside of function
|
||||||
|
--> $DIR/hrtb-implied-3.rs:19:5
|
||||||
|
|
|
||||||
|
LL | fn fails(iter: &str) {
|
||||||
|
| ---- - let's call the lifetime of this reference `'1`
|
||||||
|
| |
|
||||||
|
| `iter` is a reference that is only valid in the function body
|
||||||
|
LL | trivial_bound(iter);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| `iter` escapes the function body here
|
||||||
|
| argument requires that `'1` must outlive `'static`
|
||||||
|
|
|
||||||
|
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
|
||||||
|
--> $DIR/hrtb-implied-3.rs:14:26
|
||||||
|
|
|
||||||
|
LL | for<'a> I::Item<'a>: Sized,
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0521`.
|
|
@ -11,6 +11,8 @@ LL | x.size_hint().0
|
||||||
| |
|
| |
|
||||||
| `x` escapes the function body here
|
| `x` escapes the function body here
|
||||||
| argument requires that `'1` must outlive `'static`
|
| argument requires that `'1` must outlive `'static`
|
||||||
|
|
|
||||||
|
= note: due to current limitations in the borrow checker, this implies a `'static` lifetime
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,12 @@ LL | fn give_some<'a>() {
|
||||||
| -- lifetime `'a` defined here
|
| -- lifetime `'a` defined here
|
||||||
LL | want_hrtb::<&'a u32>()
|
LL | want_hrtb::<&'a u32>()
|
||||||
| ^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
| ^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
||||||
|
|
|
||||||
|
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
|
||||||
|
--> $DIR/hrtb-just-for-static.rs:9:15
|
||||||
|
|
|
||||||
|
LL | where T : for<'a> Foo<&'a isize>
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: implementation of `Foo` is not general enough
|
error: implementation of `Foo` is not general enough
|
||||||
--> $DIR/hrtb-just-for-static.rs:30:5
|
--> $DIR/hrtb-just-for-static.rs:30:5
|
||||||
|
|
|
@ -46,6 +46,12 @@ LL | fn foo_hrtb_bar_not<'b, T>(mut t: T)
|
||||||
...
|
...
|
||||||
LL | foo_hrtb_bar_not(&mut t);
|
LL | foo_hrtb_bar_not(&mut t);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
|
||||||
|
|
|
||||||
|
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
|
||||||
|
--> $DIR/hrtb-perfect-forwarding.rs:37:8
|
||||||
|
|
|
||||||
|
LL | T: for<'a> Foo<&'a isize> + Bar<&'b isize>,
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: implementation of `Bar` is not general enough
|
error: implementation of `Bar` is not general enough
|
||||||
--> $DIR/hrtb-perfect-forwarding.rs:43:5
|
--> $DIR/hrtb-perfect-forwarding.rs:43:5
|
||||||
|
|
|
@ -5,6 +5,12 @@ LL | fn bar<'a>() {
|
||||||
| -- lifetime `'a` defined here
|
| -- lifetime `'a` defined here
|
||||||
LL | foo::<&'a i32>();
|
LL | foo::<&'a i32>();
|
||||||
| ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
| ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
||||||
|
|
|
||||||
|
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
|
||||||
|
--> $DIR/issue-26217.rs:1:30
|
||||||
|
|
|
||||||
|
LL | fn foo<T>() where for<'a> T: 'a {}
|
||||||
|
| ^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,12 @@ LL | assert_static_via_hrtb(&local);
|
||||||
LL | assert_static_via_hrtb_with_assoc_type(&&local);
|
LL | assert_static_via_hrtb_with_assoc_type(&&local);
|
||||||
LL | }
|
LL | }
|
||||||
| - `local` dropped here while still borrowed
|
| - `local` dropped here while still borrowed
|
||||||
|
|
|
||||||
|
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
|
||||||
|
--> $DIR/local-outlives-static-via-hrtb.rs:15:53
|
||||||
|
|
|
||||||
|
LL | fn assert_static_via_hrtb<G>(_: G) where for<'a> G: Outlives<'a> {}
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0597]: `local` does not live long enough
|
error[E0597]: `local` does not live long enough
|
||||||
--> $DIR/local-outlives-static-via-hrtb.rs:25:45
|
--> $DIR/local-outlives-static-via-hrtb.rs:25:45
|
||||||
|
@ -20,6 +26,12 @@ LL | assert_static_via_hrtb_with_assoc_type(&&local);
|
||||||
| argument requires that `local` is borrowed for `'static`
|
| argument requires that `local` is borrowed for `'static`
|
||||||
LL | }
|
LL | }
|
||||||
| - `local` dropped here while still borrowed
|
| - `local` dropped here while still borrowed
|
||||||
|
|
|
||||||
|
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
|
||||||
|
--> $DIR/local-outlives-static-via-hrtb.rs:19:20
|
||||||
|
|
|
||||||
|
LL | for<'a> &'a T: Reference<AssociatedType = &'a ()>,
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,12 @@ LL | fn test2<'a>() {
|
||||||
| -- lifetime `'a` defined here
|
| -- lifetime `'a` defined here
|
||||||
LL | outlives_forall::<Value<'a>>();
|
LL | outlives_forall::<Value<'a>>();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
||||||
|
|
|
||||||
|
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
|
||||||
|
--> $DIR/type-test-universe.rs:6:16
|
||||||
|
|
|
||||||
|
LL | for<'u> T: 'u,
|
||||||
|
| ^^
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue