Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Track causes for universes created during borrowck
- Loading branch information
1 parent
e271383
commit 5e6027c
Showing
9 changed files
with
329 additions
and
129 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
compiler/rustc_mir/src/borrow_check/diagnostics/bound_region_errors.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
use rustc_infer::infer::canonical::Canonical; | ||
use rustc_middle::ty::{self, Ty, TypeFoldable}; | ||
use rustc_span::Span; | ||
use rustc_trait_selection::traits::query::type_op; | ||
|
||
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, | ||
) { | ||
todo!(); | ||
} | ||
} | ||
|
||
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: 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: 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> { | ||
// TODO: Methods for rerunning type op and reporting an error | ||
} | ||
|
||
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> {} | ||
|
||
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 | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
158 changes: 158 additions & 0 deletions
158
compiler/rustc_mir/src/borrow_check/type_check/canonical.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.