Auto merge of #86700 - lqd:matthews-nll-hrtb-errors, r=nikomatsakis
Matthew's work on improving NLL's "higher-ranked subtype error"s This PR rebases `@matthewjasper's` [branch](https://github.com/matthewjasper/rust/tree/nll-hrtb-errors) which has great work to fix the obscure higher-ranked subtype errors that are tracked in #57374. These are a blocker to turning full NLLs on, and doing some internal cleanups to remove some of the old region code. The goal is so `@nikomatsakis` can take a look at this early, and I'll then do my best to help do the changes and followup work to land this work, and move closer to turning off the migration mode. I've only updated the branch and made it compile, removed a warning or two. r? `@nikomatsakis` (Here's the [zulip topic to discuss this](https://rust-lang.zulipchat.com/#narrow/stream/122657-t-compiler.2Fwg-nll/topic/.2357374.3A.20improving.20higher-ranked.20subtype.20errors.20via.20.2386700) that Niko wanted)
This commit is contained in:
commit
3d0774d0dc
63 changed files with 1043 additions and 345 deletions
|
@ -27,6 +27,7 @@ rustc_serialize = { path = "../rustc_serialize" }
|
|||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
rustc_trait_selection = { path = "../rustc_trait_selection" }
|
||||
rustc_traits = { path = "../rustc_traits" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_apfloat = { path = "../rustc_apfloat" }
|
||||
|
|
|
@ -0,0 +1,341 @@
|
|||
use rustc_errors::DiagnosticBuilder;
|
||||
use rustc_infer::infer::canonical::Canonical;
|
||||
use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError;
|
||||
use rustc_infer::infer::region_constraints::Constraint;
|
||||
use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _};
|
||||
use rustc_infer::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt};
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::query::type_op;
|
||||
use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _};
|
||||
use rustc_traits::type_op_prove_predicate_with_span;
|
||||
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::borrow_check::region_infer::values::RegionElement;
|
||||
use crate::borrow_check::MirBorrowckCtxt;
|
||||
|
||||
#[derive(Clone)]
|
||||
crate struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>);
|
||||
|
||||
/// What operation a universe was created for.
|
||||
#[derive(Clone)]
|
||||
enum UniverseInfoInner<'tcx> {
|
||||
/// Relating two types which have binders.
|
||||
RelateTys { expected: Ty<'tcx>, found: Ty<'tcx> },
|
||||
/// Created from performing a `TypeOp`.
|
||||
TypeOp(Rc<dyn TypeOpInfo<'tcx> + 'tcx>),
|
||||
/// Any other reason.
|
||||
Other,
|
||||
}
|
||||
|
||||
impl UniverseInfo<'tcx> {
|
||||
crate fn other() -> UniverseInfo<'tcx> {
|
||||
UniverseInfo(UniverseInfoInner::Other)
|
||||
}
|
||||
|
||||
crate fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> {
|
||||
UniverseInfo(UniverseInfoInner::RelateTys { expected, found })
|
||||
}
|
||||
|
||||
crate fn report_error(
|
||||
&self,
|
||||
mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
|
||||
placeholder: ty::PlaceholderRegion,
|
||||
error_element: RegionElement,
|
||||
span: Span,
|
||||
) {
|
||||
match self.0 {
|
||||
UniverseInfoInner::RelateTys { expected, found } => {
|
||||
let body_id = mbcx.infcx.tcx.hir().local_def_id_to_hir_id(mbcx.mir_def_id());
|
||||
let err = mbcx.infcx.report_mismatched_types(
|
||||
&ObligationCause::misc(span, body_id),
|
||||
expected,
|
||||
found,
|
||||
TypeError::RegionsPlaceholderMismatch,
|
||||
);
|
||||
err.buffer(&mut mbcx.errors_buffer);
|
||||
}
|
||||
UniverseInfoInner::TypeOp(ref type_op_info) => {
|
||||
type_op_info.report_error(mbcx, placeholder, error_element, span);
|
||||
}
|
||||
UniverseInfoInner::Other => {
|
||||
// FIXME: This error message isn't great, but it doesn't show
|
||||
// up in the existing UI tests. Consider investigating this
|
||||
// some more.
|
||||
mbcx.infcx
|
||||
.tcx
|
||||
.sess
|
||||
.struct_span_err(span, "higher-ranked subtype error")
|
||||
.buffer(&mut mbcx.errors_buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crate trait ToUniverseInfo<'tcx> {
|
||||
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>;
|
||||
}
|
||||
|
||||
impl<'tcx> ToUniverseInfo<'tcx>
|
||||
for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>
|
||||
{
|
||||
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
||||
UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(PredicateQuery {
|
||||
canonical_query: self,
|
||||
base_universe,
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'tcx>
|
||||
for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>
|
||||
{
|
||||
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
||||
UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(NormalizeQuery {
|
||||
canonical_query: self,
|
||||
base_universe,
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToUniverseInfo<'tcx>
|
||||
for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>
|
||||
{
|
||||
fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
||||
// Ascribe user type isn't usually called on types that have different
|
||||
// bound regions.
|
||||
UniverseInfo::other()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp<F, G>> {
|
||||
fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
||||
// We can't rerun custom type ops.
|
||||
UniverseInfo::other()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_lifetimes)]
|
||||
trait TypeOpInfo<'tcx> {
|
||||
/// Returns an error to be reported if rerunning the type op fails to
|
||||
/// recover the error's cause.
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
|
||||
|
||||
fn base_universe(&self) -> ty::UniverseIndex;
|
||||
|
||||
fn nice_error(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: Span,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx>>;
|
||||
|
||||
fn report_error(
|
||||
&self,
|
||||
mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
|
||||
placeholder: ty::PlaceholderRegion,
|
||||
error_element: RegionElement,
|
||||
span: Span,
|
||||
) {
|
||||
let tcx = mbcx.infcx.tcx;
|
||||
let base_universe = self.base_universe();
|
||||
|
||||
let adjusted_universe = if let Some(adjusted) =
|
||||
placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
|
||||
{
|
||||
adjusted
|
||||
} else {
|
||||
self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer);
|
||||
return;
|
||||
};
|
||||
|
||||
let placeholder_region = tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
|
||||
name: placeholder.name,
|
||||
universe: adjusted_universe.into(),
|
||||
}));
|
||||
|
||||
let error_region =
|
||||
if let RegionElement::PlaceholderRegion(error_placeholder) = error_element {
|
||||
let adjusted_universe =
|
||||
error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32());
|
||||
adjusted_universe.map(|adjusted| {
|
||||
tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
|
||||
name: error_placeholder.name,
|
||||
universe: adjusted.into(),
|
||||
}))
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
debug!(?placeholder_region);
|
||||
|
||||
let nice_error = self.nice_error(tcx, span, placeholder_region, error_region);
|
||||
|
||||
if let Some(nice_error) = nice_error {
|
||||
nice_error.buffer(&mut mbcx.errors_buffer);
|
||||
} else {
|
||||
self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct PredicateQuery<'tcx> {
|
||||
canonical_query:
|
||||
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>,
|
||||
base_universe: ty::UniverseIndex,
|
||||
}
|
||||
|
||||
impl TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
|
||||
err.note(&format!("could not prove {}", self.canonical_query.value.value.predicate));
|
||||
err
|
||||
}
|
||||
|
||||
fn base_universe(&self) -> ty::UniverseIndex {
|
||||
self.base_universe
|
||||
}
|
||||
|
||||
fn nice_error(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: Span,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
|
||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
|
||||
type_op_prove_predicate_with_span(infcx, &mut *fulfill_cx, key, Some(span));
|
||||
try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct NormalizeQuery<'tcx, T> {
|
||||
canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>,
|
||||
base_universe: ty::UniverseIndex,
|
||||
}
|
||||
|
||||
impl<T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
|
||||
where
|
||||
T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx,
|
||||
{
|
||||
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
|
||||
err.note(&format!("could not normalize `{}`", self.canonical_query.value.value.value));
|
||||
err
|
||||
}
|
||||
|
||||
fn base_universe(&self) -> ty::UniverseIndex {
|
||||
self.base_universe
|
||||
}
|
||||
|
||||
fn nice_error(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: Span,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
|
||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
|
||||
|
||||
let mut selcx = SelectionContext::new(infcx);
|
||||
|
||||
// FIXME(lqd): Unify and de-duplicate the following with the actual
|
||||
// `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
|
||||
// `ObligationCause`. The normalization results are currently different between
|
||||
// `AtExt::normalize` used in the query and `normalize` called below: the former fails
|
||||
// to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
|
||||
// after #85499 lands to see if its fixes have erased this difference.
|
||||
let (param_env, value) = key.into_parts();
|
||||
let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize(
|
||||
&mut selcx,
|
||||
param_env,
|
||||
ObligationCause::dummy_with_span(span),
|
||||
value.value,
|
||||
);
|
||||
fulfill_cx.register_predicate_obligations(infcx, obligations);
|
||||
|
||||
try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn try_extract_error_from_fulfill_cx<'tcx>(
|
||||
mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
placeholder_region: ty::Region<'tcx>,
|
||||
error_region: Option<ty::Region<'tcx>>,
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
let tcx = infcx.tcx;
|
||||
|
||||
// We generally shouldn't have errors here because the query was
|
||||
// already run, but there's no point using `delay_span_bug`
|
||||
// when we're going to emit an error here anyway.
|
||||
let _errors = fulfill_cx.select_all_or_error(infcx).err().unwrap_or_else(Vec::new);
|
||||
|
||||
let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| {
|
||||
debug!(?region_constraints);
|
||||
region_constraints.constraints.iter().find_map(|(constraint, cause)| {
|
||||
match *constraint {
|
||||
Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => {
|
||||
Some((sub, cause.clone()))
|
||||
}
|
||||
// FIXME: Should this check the universe of the var?
|
||||
Constraint::VarSubReg(vid, sup) if sup == placeholder_region => {
|
||||
Some((tcx.mk_region(ty::ReVar(vid)), cause.clone()))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
})?;
|
||||
|
||||
debug!(?sub_region, ?cause);
|
||||
let nice_error = match (error_region, sub_region) {
|
||||
(Some(error_region), &ty::ReVar(vid)) => NiceRegionError::new(
|
||||
infcx,
|
||||
RegionResolutionError::SubSupConflict(
|
||||
vid,
|
||||
infcx.region_var_origin(vid),
|
||||
cause.clone(),
|
||||
error_region,
|
||||
cause.clone(),
|
||||
placeholder_region,
|
||||
),
|
||||
),
|
||||
(Some(error_region), _) => NiceRegionError::new(
|
||||
infcx,
|
||||
RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region),
|
||||
),
|
||||
// Note universe here is wrong...
|
||||
(None, &ty::ReVar(vid)) => NiceRegionError::new(
|
||||
infcx,
|
||||
RegionResolutionError::UpperBoundUniverseConflict(
|
||||
vid,
|
||||
infcx.region_var_origin(vid),
|
||||
infcx.universe_of_region(sub_region),
|
||||
cause.clone(),
|
||||
placeholder_region,
|
||||
),
|
||||
),
|
||||
(None, _) => NiceRegionError::new(
|
||||
infcx,
|
||||
RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region),
|
||||
),
|
||||
};
|
||||
nice_error.try_report_from_nll().or_else(|| {
|
||||
if let SubregionOrigin::Subtype(trace) = cause {
|
||||
Some(
|
||||
infcx.report_and_explain_type_error(*trace, &TypeError::RegionsPlaceholderMismatch),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
|
@ -28,12 +28,14 @@ mod outlives_suggestion;
|
|||
mod region_name;
|
||||
mod var_name;
|
||||
|
||||
mod bound_region_errors;
|
||||
mod conflict_errors;
|
||||
mod explain_borrow;
|
||||
mod move_errors;
|
||||
mod mutability_errors;
|
||||
mod region_errors;
|
||||
|
||||
crate use bound_region_errors::{ToUniverseInfo, UniverseInfo};
|
||||
crate use mutability_errors::AccessKind;
|
||||
crate use outlives_suggestion::OutlivesSuggestionBuilder;
|
||||
crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
|
||||
|
|
|
@ -75,8 +75,8 @@ crate enum RegionErrorKind<'tcx> {
|
|||
longer_fr: RegionVid,
|
||||
/// The region element that erroneously must be outlived by `longer_fr`.
|
||||
error_element: RegionElement,
|
||||
/// The origin of the placeholder region.
|
||||
fr_origin: NllRegionVariableOrigin,
|
||||
/// The placeholder region.
|
||||
placeholder: ty::PlaceholderRegion,
|
||||
},
|
||||
|
||||
/// Any other lifetime error.
|
||||
|
@ -210,25 +210,23 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
|
||||
RegionErrorKind::BoundUniversalRegionError {
|
||||
longer_fr,
|
||||
fr_origin,
|
||||
placeholder,
|
||||
error_element,
|
||||
} => {
|
||||
let error_region = self.regioncx.region_from_element(longer_fr, error_element);
|
||||
let error_vid = self.regioncx.region_from_element(longer_fr, &error_element);
|
||||
|
||||
// Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
|
||||
let (_, span) = self.regioncx.find_outlives_blame_span(
|
||||
&self.body,
|
||||
longer_fr,
|
||||
fr_origin,
|
||||
error_region,
|
||||
NllRegionVariableOrigin::Placeholder(placeholder),
|
||||
error_vid,
|
||||
);
|
||||
|
||||
// FIXME: improve this error message
|
||||
self.infcx
|
||||
.tcx
|
||||
.sess
|
||||
.struct_span_err(span, "higher-ranked subtype error")
|
||||
.buffer(&mut self.errors_buffer);
|
||||
let universe = placeholder.universe;
|
||||
let universe_info = self.regioncx.universe_info(universe);
|
||||
|
||||
universe_info.report_error(self, placeholder, error_element, span);
|
||||
}
|
||||
|
||||
RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => {
|
||||
|
|
|
@ -241,6 +241,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
|
|||
outlives_constraints,
|
||||
member_constraints,
|
||||
closure_bounds_mapping,
|
||||
universe_causes,
|
||||
type_tests,
|
||||
} = constraints;
|
||||
let placeholder_indices = Rc::new(placeholder_indices);
|
||||
|
@ -262,6 +263,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
|
|||
outlives_constraints,
|
||||
member_constraints,
|
||||
closure_bounds_mapping,
|
||||
universe_causes,
|
||||
type_tests,
|
||||
liveness_constraints,
|
||||
elements,
|
||||
|
|
|
@ -21,7 +21,7 @@ use crate::borrow_check::{
|
|||
constraints::{
|
||||
graph::NormalConstraintGraph, ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet,
|
||||
},
|
||||
diagnostics::{RegionErrorKind, RegionErrors},
|
||||
diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo},
|
||||
member_constraints::{MemberConstraintSet, NllMemberConstraintIndex},
|
||||
nll::{PoloniusOutput, ToRegionVid},
|
||||
region_infer::reverse_sccs::ReverseSccGraph,
|
||||
|
@ -84,6 +84,9 @@ pub struct RegionInferenceContext<'tcx> {
|
|||
closure_bounds_mapping:
|
||||
FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
|
||||
|
||||
/// Map universe indexes to information on why we created it.
|
||||
universe_causes: IndexVec<ty::UniverseIndex, UniverseInfo<'tcx>>,
|
||||
|
||||
/// Contains the minimum universe of any variable within the same
|
||||
/// SCC. We will ensure that no SCC contains values that are not
|
||||
/// visible from this index.
|
||||
|
@ -253,6 +256,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
Location,
|
||||
FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
|
||||
>,
|
||||
universe_causes: IndexVec<ty::UniverseIndex, UniverseInfo<'tcx>>,
|
||||
type_tests: Vec<TypeTest<'tcx>>,
|
||||
liveness_constraints: LivenessValues<RegionVid>,
|
||||
elements: &Rc<RegionValueElements>,
|
||||
|
@ -293,6 +297,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
member_constraints,
|
||||
member_constraints_applied: Vec::new(),
|
||||
closure_bounds_mapping,
|
||||
universe_causes,
|
||||
scc_universes,
|
||||
scc_representatives,
|
||||
scc_values,
|
||||
|
@ -1632,7 +1637,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
errors_buffer.push(RegionErrorKind::BoundUniversalRegionError {
|
||||
longer_fr,
|
||||
error_element,
|
||||
fr_origin: NllRegionVariableOrigin::Placeholder(placeholder),
|
||||
placeholder,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1918,8 +1923,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
}
|
||||
|
||||
/// Get the region outlived by `longer_fr` and live at `element`.
|
||||
crate fn region_from_element(&self, longer_fr: RegionVid, element: RegionElement) -> RegionVid {
|
||||
match element {
|
||||
crate fn region_from_element(
|
||||
&self,
|
||||
longer_fr: RegionVid,
|
||||
element: &RegionElement,
|
||||
) -> RegionVid {
|
||||
match *element {
|
||||
RegionElement::Location(l) => self.find_sub_region_live_at(longer_fr, l),
|
||||
RegionElement::RootUniversalRegion(r) => r,
|
||||
RegionElement::PlaceholderRegion(error_placeholder) => self
|
||||
|
@ -2138,6 +2147,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
|
||||
categorized_path.remove(0)
|
||||
}
|
||||
|
||||
crate fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
||||
self.universe_causes[universe].clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> RegionDefinition<'tcx> {
|
||||
|
|
158
compiler/rustc_mir/src/borrow_check/type_check/canonical.rs
Normal file
158
compiler/rustc_mir/src/borrow_check/type_check/canonical.rs
Normal file
|
@ -0,0 +1,158 @@
|
|||
use std::fmt;
|
||||
|
||||
use rustc_hir as hir;
|
||||
use rustc_infer::infer::canonical::Canonical;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::ty::{self, ToPredicate, TypeFoldable};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
|
||||
use rustc_trait_selection::traits::query::Fallible;
|
||||
|
||||
use crate::borrow_check::diagnostics::{ToUniverseInfo, UniverseInfo};
|
||||
|
||||
use super::{Locations, NormalizeLocation, TypeChecker};
|
||||
|
||||
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
/// Given some operation `op` that manipulates types, proves
|
||||
/// predicates, or otherwise uses the inference context, executes
|
||||
/// `op` and then executes all the further obligations that `op`
|
||||
/// returns. This will yield a set of outlives constraints amongst
|
||||
/// regions which are extracted and stored as having occurred at
|
||||
/// `locations`.
|
||||
///
|
||||
/// **Any `rustc_infer::infer` operations that might generate region
|
||||
/// constraints should occur within this method so that those
|
||||
/// constraints can be properly localized!**
|
||||
pub(super) fn fully_perform_op<R, Op>(
|
||||
&mut self,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
op: Op,
|
||||
) -> Fallible<R>
|
||||
where
|
||||
Op: type_op::TypeOp<'tcx, Output = R>,
|
||||
Canonical<'tcx, Op>: ToUniverseInfo<'tcx>,
|
||||
{
|
||||
let old_universe = self.infcx.universe();
|
||||
|
||||
let TypeOpOutput { output, constraints, canonicalized_query } =
|
||||
op.fully_perform(self.infcx)?;
|
||||
|
||||
if let Some(data) = &constraints {
|
||||
self.push_region_constraints(locations, category, data);
|
||||
}
|
||||
|
||||
let universe = self.infcx.universe();
|
||||
|
||||
if old_universe != universe {
|
||||
let universe_info = match canonicalized_query {
|
||||
Some(canonicalized_query) => canonicalized_query.to_universe_info(old_universe),
|
||||
None => UniverseInfo::other(),
|
||||
};
|
||||
for u in old_universe..universe {
|
||||
let info_universe =
|
||||
self.borrowck_context.constraints.universe_causes.push(universe_info.clone());
|
||||
assert_eq!(u.as_u32() + 1, info_universe.as_u32());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
pub(super) fn instantiate_canonical_with_fresh_inference_vars<T>(
|
||||
&mut self,
|
||||
span: Span,
|
||||
canonical: &Canonical<'tcx, T>,
|
||||
) -> T
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
let (instantiated, _) =
|
||||
self.infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
|
||||
|
||||
for _ in 0..canonical.max_universe.as_u32() {
|
||||
let info = UniverseInfo::other();
|
||||
self.borrowck_context.constraints.universe_causes.push(info);
|
||||
}
|
||||
|
||||
instantiated
|
||||
}
|
||||
|
||||
pub(super) fn prove_trait_ref(
|
||||
&mut self,
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
) {
|
||||
self.prove_predicates(
|
||||
Some(ty::PredicateKind::Trait(ty::TraitPredicate {
|
||||
trait_ref,
|
||||
constness: hir::Constness::NotConst,
|
||||
})),
|
||||
locations,
|
||||
category,
|
||||
);
|
||||
}
|
||||
|
||||
pub(super) fn normalize_and_prove_instantiated_predicates(
|
||||
&mut self,
|
||||
instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
|
||||
locations: Locations,
|
||||
) {
|
||||
for predicate in instantiated_predicates.predicates {
|
||||
let predicate = self.normalize(predicate, locations);
|
||||
self.prove_predicate(predicate, locations, ConstraintCategory::Boring);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn prove_predicates(
|
||||
&mut self,
|
||||
predicates: impl IntoIterator<Item = impl ToPredicate<'tcx>>,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
) {
|
||||
for predicate in predicates {
|
||||
let predicate = predicate.to_predicate(self.tcx());
|
||||
debug!("prove_predicates(predicate={:?}, locations={:?})", predicate, locations,);
|
||||
|
||||
self.prove_predicate(predicate, locations, category);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn prove_predicate(
|
||||
&mut self,
|
||||
predicate: ty::Predicate<'tcx>,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
) {
|
||||
debug!("prove_predicate(predicate={:?}, location={:?})", predicate, locations,);
|
||||
|
||||
let param_env = self.param_env;
|
||||
self.fully_perform_op(
|
||||
locations,
|
||||
category,
|
||||
param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)),
|
||||
)
|
||||
.unwrap_or_else(|NoSolution| {
|
||||
span_mirbug!(self, NoSolution, "could not prove {:?}", predicate);
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
|
||||
where
|
||||
T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
|
||||
{
|
||||
debug!("normalize(value={:?}, location={:?})", value, location);
|
||||
let param_env = self.param_env;
|
||||
self.fully_perform_op(
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
param_env.and(type_op::normalize::Normalize::new(value)),
|
||||
)
|
||||
.unwrap_or_else(|NoSolution| {
|
||||
span_mirbug!(self, NoSolution, "failed to normalize `{:?}`", value);
|
||||
value
|
||||
})
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
|
|||
use rustc_span::DUMMY_SP;
|
||||
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
|
||||
use std::rc::Rc;
|
||||
use type_op::TypeOpOutput;
|
||||
|
||||
use crate::borrow_check::{
|
||||
nll::ToRegionVid,
|
||||
|
@ -255,7 +256,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
|
|||
let constraint_sets: Vec<_> = unnormalized_input_output_tys
|
||||
.flat_map(|ty| {
|
||||
debug!("build: input_or_output={:?}", ty);
|
||||
let (ty, constraints1) = self
|
||||
let TypeOpOutput { output: ty, constraints: constraints1, .. } = self
|
||||
.param_env
|
||||
.and(type_op::normalize::Normalize::new(ty))
|
||||
.fully_perform(self.infcx)
|
||||
|
@ -264,7 +265,11 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
|
|||
.tcx
|
||||
.sess
|
||||
.delay_span_bug(DUMMY_SP, &format!("failed to normalize {:?}", ty));
|
||||
(self.infcx.tcx.ty_error(), None)
|
||||
TypeOpOutput {
|
||||
output: self.infcx.tcx.ty_error(),
|
||||
constraints: None,
|
||||
canonicalized_query: None,
|
||||
}
|
||||
});
|
||||
let constraints2 = self.add_implied_bounds(ty);
|
||||
normalized_inputs_and_output.push(ty);
|
||||
|
@ -317,7 +322,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
|
|||
/// from this local.
|
||||
fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option<Rc<QueryRegionConstraints<'tcx>>> {
|
||||
debug!("add_implied_bounds(ty={:?})", ty);
|
||||
let (bounds, constraints) = self
|
||||
let TypeOpOutput { output: bounds, constraints, .. } = self
|
||||
.param_env
|
||||
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
|
||||
.fully_perform(self.infcx)
|
||||
|
|
|
@ -44,7 +44,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
// Instantiate the canonicalized variables from
|
||||
// user-provided signature (e.g., the `_` in the code
|
||||
// above) with fresh variables.
|
||||
let (poly_sig, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
|
||||
let poly_sig = self.instantiate_canonical_with_fresh_inference_vars(
|
||||
body.span,
|
||||
&user_provided_poly_sig,
|
||||
);
|
||||
|
|
|
@ -5,7 +5,7 @@ use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
|
|||
use rustc_middle::ty::{Ty, TypeFoldable};
|
||||
use rustc_trait_selection::traits::query::dropck_outlives::DropckOutlivesResult;
|
||||
use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives;
|
||||
use rustc_trait_selection::traits::query::type_op::TypeOp;
|
||||
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::dataflow::impls::MaybeInitializedPlaces;
|
||||
|
@ -519,9 +519,9 @@ impl LivenessContext<'_, '_, '_, 'tcx> {
|
|||
debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,);
|
||||
|
||||
let param_env = typeck.param_env;
|
||||
let (dropck_result, region_constraint_data) =
|
||||
let TypeOpOutput { output, constraints, .. } =
|
||||
param_env.and(DropckOutlives::new(dropped_ty)).fully_perform(typeck.infcx).unwrap();
|
||||
|
||||
DropData { dropck_result, region_constraint_data }
|
||||
DropData { dropck_result: output, region_constraint_data: constraints }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ use rustc_trait_selection::opaque_types::{GenerateMemberConstraints, InferCtxtEx
|
|||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::query::type_op;
|
||||
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
|
||||
use rustc_trait_selection::traits::query::{Fallible, NoSolution};
|
||||
use rustc_trait_selection::traits::query::Fallible;
|
||||
use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations};
|
||||
|
||||
use crate::dataflow::impls::MaybeInitializedPlaces;
|
||||
|
@ -51,6 +51,7 @@ use crate::transform::{
|
|||
use crate::borrow_check::{
|
||||
borrow_set::BorrowSet,
|
||||
constraints::{OutlivesConstraint, OutlivesConstraintSet},
|
||||
diagnostics::UniverseInfo,
|
||||
facts::AllFacts,
|
||||
location::LocationTable,
|
||||
member_constraints::MemberConstraintSet,
|
||||
|
@ -89,6 +90,7 @@ macro_rules! span_mirbug_and_err {
|
|||
})
|
||||
}
|
||||
|
||||
mod canonical;
|
||||
mod constraint_conversion;
|
||||
pub mod free_region_relations;
|
||||
mod input_output;
|
||||
|
@ -142,6 +144,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
|||
member_constraints: MemberConstraintSet::default(),
|
||||
closure_bounds_mapping: Default::default(),
|
||||
type_tests: Vec::default(),
|
||||
universe_causes: IndexVec::from_elem_n(UniverseInfo::other(), 1),
|
||||
};
|
||||
|
||||
let CreateResult {
|
||||
|
@ -156,6 +159,11 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
|||
&mut constraints,
|
||||
);
|
||||
|
||||
for _ in ty::UniverseIndex::ROOT..infcx.universe() {
|
||||
let info = UniverseInfo::other();
|
||||
constraints.universe_causes.push(info);
|
||||
}
|
||||
|
||||
let mut borrowck_context = BorrowCheckContext {
|
||||
universal_regions,
|
||||
location_table,
|
||||
|
@ -376,8 +384,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||
ty,
|
||||
san_ty| {
|
||||
if let Err(terr) = verifier.cx.eq_types(
|
||||
san_ty,
|
||||
ty,
|
||||
san_ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
) {
|
||||
|
@ -425,8 +433,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||
let literal_ty = constant.literal.ty().builtin_deref(true).unwrap().ty;
|
||||
|
||||
if let Err(terr) = self.cx.eq_types(
|
||||
normalized_ty,
|
||||
literal_ty,
|
||||
normalized_ty,
|
||||
locations,
|
||||
ConstraintCategory::Boring,
|
||||
) {
|
||||
|
@ -542,7 +550,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
return PlaceTy::from_ty(self.tcx().ty_error());
|
||||
}
|
||||
}
|
||||
place_ty = self.sanitize_projection(place_ty, elem, place, location)
|
||||
place_ty = self.sanitize_projection(place_ty, elem, place, location);
|
||||
}
|
||||
|
||||
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
|
||||
|
@ -916,6 +924,8 @@ crate struct MirTypeckRegionConstraints<'tcx> {
|
|||
crate closure_bounds_mapping:
|
||||
FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
|
||||
|
||||
crate universe_causes: IndexVec<ty::UniverseIndex, UniverseInfo<'tcx>>,
|
||||
|
||||
crate type_tests: Vec<TypeTest<'tcx>>,
|
||||
}
|
||||
|
||||
|
@ -1043,8 +1053,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
);
|
||||
for user_annotation in self.user_type_annotations {
|
||||
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
|
||||
let (annotation, _) =
|
||||
self.infcx.instantiate_canonical_with_fresh_inference_vars(span, user_ty);
|
||||
let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty);
|
||||
match annotation {
|
||||
UserType::Ty(mut ty) => {
|
||||
ty = self.normalize(ty, Locations::All(span));
|
||||
|
@ -1097,31 +1106,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Given some operation `op` that manipulates types, proves
|
||||
/// predicates, or otherwise uses the inference context, executes
|
||||
/// `op` and then executes all the further obligations that `op`
|
||||
/// returns. This will yield a set of outlives constraints amongst
|
||||
/// regions which are extracted and stored as having occurred at
|
||||
/// `locations`.
|
||||
///
|
||||
/// **Any `rustc_infer::infer` operations that might generate region
|
||||
/// constraints should occur within this method so that those
|
||||
/// constraints can be properly localized!**
|
||||
fn fully_perform_op<R>(
|
||||
&mut self,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
op: impl type_op::TypeOp<'tcx, Output = R>,
|
||||
) -> Fallible<R> {
|
||||
let (r, opt_data) = op.fully_perform(self.infcx)?;
|
||||
|
||||
if let Some(data) = &opt_data {
|
||||
self.push_region_constraints(locations, category, data);
|
||||
}
|
||||
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
fn push_region_constraints(
|
||||
&mut self,
|
||||
locations: Locations,
|
||||
|
@ -1161,7 +1145,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
b,
|
||||
locations,
|
||||
category,
|
||||
Some(self.borrowck_context),
|
||||
self.borrowck_context,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1173,17 +1157,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
) -> Fallible<()> {
|
||||
self.relate_types(sub, ty::Variance::Covariant, sup, locations, category)
|
||||
// Use this order of parameters because the sup type is usually the
|
||||
// "expected" type in diagnostics.
|
||||
self.relate_types(sup, ty::Variance::Contravariant, sub, locations, category)
|
||||
}
|
||||
|
||||
fn eq_types(
|
||||
&mut self,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
found: Ty<'tcx>,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
) -> Fallible<()> {
|
||||
self.relate_types(a, ty::Variance::Invariant, b, locations, category)
|
||||
self.relate_types(expected, ty::Variance::Invariant, found, locations, category)
|
||||
}
|
||||
|
||||
fn relate_type_and_user_type(
|
||||
|
@ -1222,7 +1208,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
);
|
||||
|
||||
let ty = curr_projected_ty.ty;
|
||||
self.relate_types(a, v, ty, locations, category)?;
|
||||
self.relate_types(ty, v.xform(ty::Variance::Contravariant), a, locations, category)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -2053,8 +2039,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig);
|
||||
|
||||
if let Err(terr) = self.eq_types(
|
||||
ty_fn_ptr_from,
|
||||
ty,
|
||||
ty_fn_ptr_from,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
) {
|
||||
|
@ -2077,8 +2063,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
let ty_fn_ptr_from = tcx.mk_fn_ptr(tcx.signature_unclosure(sig, *unsafety));
|
||||
|
||||
if let Err(terr) = self.eq_types(
|
||||
ty_fn_ptr_from,
|
||||
ty,
|
||||
ty_fn_ptr_from,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
) {
|
||||
|
@ -2106,8 +2092,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig);
|
||||
|
||||
if let Err(terr) = self.eq_types(
|
||||
ty_fn_ptr_from,
|
||||
ty,
|
||||
ty_fn_ptr_from,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
) {
|
||||
|
@ -2294,20 +2280,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
span: body.source_info(location).span,
|
||||
});
|
||||
self.relate_types(
|
||||
common_ty,
|
||||
ty::Variance::Contravariant,
|
||||
self.sub_types(
|
||||
ty_left,
|
||||
common_ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
)
|
||||
.unwrap_or_else(|err| {
|
||||
bug!("Could not equate type variable with {:?}: {:?}", ty_left, err)
|
||||
});
|
||||
if let Err(terr) = self.relate_types(
|
||||
common_ty,
|
||||
ty::Variance::Contravariant,
|
||||
if let Err(terr) = self.sub_types(
|
||||
ty_right,
|
||||
common_ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
) {
|
||||
|
@ -2682,66 +2666,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
tcx.predicates_of(def_id).instantiate(tcx, substs)
|
||||
}
|
||||
|
||||
fn prove_trait_ref(
|
||||
&mut self,
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
) {
|
||||
self.prove_predicates(
|
||||
Some(ty::PredicateKind::Trait(ty::TraitPredicate {
|
||||
trait_ref,
|
||||
constness: hir::Constness::NotConst,
|
||||
})),
|
||||
locations,
|
||||
category,
|
||||
);
|
||||
}
|
||||
|
||||
fn normalize_and_prove_instantiated_predicates(
|
||||
&mut self,
|
||||
instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
|
||||
locations: Locations,
|
||||
) {
|
||||
for predicate in instantiated_predicates.predicates {
|
||||
let predicate = self.normalize(predicate, locations);
|
||||
self.prove_predicate(predicate, locations, ConstraintCategory::Boring);
|
||||
}
|
||||
}
|
||||
|
||||
fn prove_predicates(
|
||||
&mut self,
|
||||
predicates: impl IntoIterator<Item = impl ToPredicate<'tcx>>,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
) {
|
||||
for predicate in predicates {
|
||||
let predicate = predicate.to_predicate(self.tcx());
|
||||
debug!("prove_predicates(predicate={:?}, locations={:?})", predicate, locations,);
|
||||
|
||||
self.prove_predicate(predicate, locations, category);
|
||||
}
|
||||
}
|
||||
|
||||
fn prove_predicate(
|
||||
&mut self,
|
||||
predicate: ty::Predicate<'tcx>,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
) {
|
||||
debug!("prove_predicate(predicate={:?}, location={:?})", predicate, locations,);
|
||||
|
||||
let param_env = self.param_env;
|
||||
self.fully_perform_op(
|
||||
locations,
|
||||
category,
|
||||
param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)),
|
||||
)
|
||||
.unwrap_or_else(|NoSolution| {
|
||||
span_mirbug!(self, NoSolution, "could not prove {:?}", predicate);
|
||||
})
|
||||
}
|
||||
|
||||
fn typeck_mir(&mut self, body: &Body<'tcx>) {
|
||||
self.last_span = body.span;
|
||||
debug!("run_on_mir: {:?}", body.span);
|
||||
|
@ -2764,23 +2688,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
self.check_iscleanup(&body, block_data);
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
|
||||
where
|
||||
T: type_op::normalize::Normalizable<'tcx> + Copy + 'tcx,
|
||||
{
|
||||
debug!("normalize(value={:?}, location={:?})", value, location);
|
||||
let param_env = self.param_env;
|
||||
self.fully_perform_op(
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
param_env.and(type_op::normalize::Normalize::new(value)),
|
||||
)
|
||||
.unwrap_or_else(|NoSolution| {
|
||||
span_mirbug!(self, NoSolution, "failed to normalize `{:?}`", value);
|
||||
value
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
trait NormalizeLocation: fmt::Debug + Copy {
|
||||
|
|
|
@ -6,6 +6,7 @@ use rustc_middle::ty::{self, Const, Ty};
|
|||
use rustc_trait_selection::traits::query::Fallible;
|
||||
|
||||
use crate::borrow_check::constraints::OutlivesConstraint;
|
||||
use crate::borrow_check::diagnostics::UniverseInfo;
|
||||
use crate::borrow_check::type_check::{BorrowCheckContext, Locations};
|
||||
|
||||
/// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
|
||||
|
@ -24,12 +25,19 @@ pub(super) fn relate_types<'tcx>(
|
|||
b: Ty<'tcx>,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
|
||||
borrowck_context: &mut BorrowCheckContext<'_, 'tcx>,
|
||||
) -> Fallible<()> {
|
||||
debug!("relate_types(a={:?}, v={:?}, b={:?}, locations={:?})", a, v, b, locations);
|
||||
TypeRelating::new(
|
||||
infcx,
|
||||
NllTypeRelatingDelegate::new(infcx, borrowck_context, param_env, locations, category),
|
||||
NllTypeRelatingDelegate::new(
|
||||
infcx,
|
||||
borrowck_context,
|
||||
param_env,
|
||||
locations,
|
||||
category,
|
||||
UniverseInfo::relate(a, b),
|
||||
),
|
||||
v,
|
||||
)
|
||||
.relate(a, b)?;
|
||||
|
@ -38,7 +46,7 @@ pub(super) fn relate_types<'tcx>(
|
|||
|
||||
struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
|
||||
infcx: &'me InferCtxt<'me, 'tcx>,
|
||||
borrowck_context: Option<&'me mut BorrowCheckContext<'bccx, 'tcx>>,
|
||||
borrowck_context: &'me mut BorrowCheckContext<'bccx, 'tcx>,
|
||||
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
|
||||
|
@ -47,17 +55,22 @@ struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
|
|||
|
||||
/// What category do we assign the resulting `'a: 'b` relationships?
|
||||
category: ConstraintCategory,
|
||||
|
||||
/// Information so that error reporting knows what types we are relating
|
||||
/// when reporting a bound region error.
|
||||
universe_info: UniverseInfo<'tcx>,
|
||||
}
|
||||
|
||||
impl NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
|
||||
fn new(
|
||||
infcx: &'me InferCtxt<'me, 'tcx>,
|
||||
borrowck_context: Option<&'me mut BorrowCheckContext<'bccx, 'tcx>>,
|
||||
borrowck_context: &'me mut BorrowCheckContext<'bccx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
universe_info: UniverseInfo<'tcx>,
|
||||
) -> Self {
|
||||
Self { infcx, borrowck_context, param_env, locations, category }
|
||||
Self { infcx, borrowck_context, param_env, locations, category, universe_info }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,24 +80,20 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
|
|||
}
|
||||
|
||||
fn create_next_universe(&mut self) -> ty::UniverseIndex {
|
||||
self.infcx.create_next_universe()
|
||||
let info_universe =
|
||||
self.borrowck_context.constraints.universe_causes.push(self.universe_info.clone());
|
||||
let universe = self.infcx.create_next_universe();
|
||||
assert_eq!(info_universe, universe);
|
||||
universe
|
||||
}
|
||||
|
||||
fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> {
|
||||
if self.borrowck_context.is_some() {
|
||||
let origin = NllRegionVariableOrigin::Existential { from_forall };
|
||||
self.infcx.next_nll_region_var(origin)
|
||||
} else {
|
||||
self.infcx.tcx.lifetimes.re_erased
|
||||
}
|
||||
let origin = NllRegionVariableOrigin::Existential { from_forall };
|
||||
self.infcx.next_nll_region_var(origin)
|
||||
}
|
||||
|
||||
fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> {
|
||||
if let Some(borrowck_context) = &mut self.borrowck_context {
|
||||
borrowck_context.constraints.placeholder_region(self.infcx, placeholder)
|
||||
} else {
|
||||
self.infcx.tcx.lifetimes.re_erased
|
||||
}
|
||||
self.borrowck_context.constraints.placeholder_region(self.infcx, placeholder)
|
||||
}
|
||||
|
||||
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
|
||||
|
@ -100,17 +109,15 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
|
|||
sub: ty::Region<'tcx>,
|
||||
info: ty::VarianceDiagInfo<'tcx>,
|
||||
) {
|
||||
if let Some(borrowck_context) = &mut self.borrowck_context {
|
||||
let sub = borrowck_context.universal_regions.to_region_vid(sub);
|
||||
let sup = borrowck_context.universal_regions.to_region_vid(sup);
|
||||
borrowck_context.constraints.outlives_constraints.push(OutlivesConstraint {
|
||||
sup,
|
||||
sub,
|
||||
locations: self.locations,
|
||||
category: self.category,
|
||||
variance_info: info,
|
||||
});
|
||||
}
|
||||
let sub = self.borrowck_context.universal_regions.to_region_vid(sub);
|
||||
let sup = self.borrowck_context.universal_regions.to_region_vid(sup);
|
||||
self.borrowck_context.constraints.outlives_constraints.push(OutlivesConstraint {
|
||||
sup,
|
||||
sub,
|
||||
locations: self.locations,
|
||||
category: self.category,
|
||||
variance_info: info,
|
||||
});
|
||||
}
|
||||
|
||||
// We don't have to worry about the equality of consts during borrow checking
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue