mirror of
https://github.com/rust-lang/rust
synced 2024-11-05 20:45:15 +00:00
Try to use approximate placeholder regions when outputting an AscribeUserType error in borrowck
This commit is contained in:
parent
42ca6e4e57
commit
35dd0c9049
6 changed files with 80 additions and 13 deletions
|
@ -10,6 +10,8 @@
|
|||
use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::RePlaceholder;
|
||||
use rustc_middle::ty::Region;
|
||||
use rustc_middle::ty::RegionVid;
|
||||
use rustc_middle::ty::UniverseIndex;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
|
@ -205,6 +207,8 @@ fn report_error(
|
|||
let span = cause.span;
|
||||
let nice_error = self.nice_error(mbcx, cause, placeholder_region, error_region);
|
||||
|
||||
debug!(?nice_error);
|
||||
|
||||
if let Some(nice_error) = nice_error {
|
||||
mbcx.buffer_error(nice_error);
|
||||
} else {
|
||||
|
@ -404,19 +408,41 @@ fn try_extract_error_from_region_constraints<'tcx>(
|
|||
mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin,
|
||||
mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex,
|
||||
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
||||
let (sub_region, cause) =
|
||||
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((ty::Region::new_var(infcx.tcx, vid), cause.clone()))
|
||||
}
|
||||
_ => None,
|
||||
let matches =
|
||||
|a_region: Region<'tcx>, b_region: Region<'tcx>| match (a_region.kind(), b_region.kind()) {
|
||||
(RePlaceholder(a_p), RePlaceholder(b_p)) => a_p.bound == b_p.bound,
|
||||
_ => a_region == b_region,
|
||||
};
|
||||
let check = |constraint: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| {
|
||||
match *constraint {
|
||||
Constraint::RegSubReg(sub, sup)
|
||||
if ((exact && sup == placeholder_region)
|
||||
|| (!exact && matches(sup, placeholder_region)))
|
||||
&& sup != sub =>
|
||||
{
|
||||
Some((sub, cause.clone()))
|
||||
}
|
||||
})?;
|
||||
// FIXME: Should this check the universe of the var?
|
||||
Constraint::VarSubReg(vid, sup)
|
||||
if ((exact && sup == placeholder_region)
|
||||
|| (!exact && matches(sup, placeholder_region))) =>
|
||||
{
|
||||
Some((ty::Region::new_var(infcx.tcx, vid), cause.clone()))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
};
|
||||
let mut info = region_constraints
|
||||
.constraints
|
||||
.iter()
|
||||
.find_map(|(constraint, cause)| check(constraint, cause, true));
|
||||
if info.is_none() {
|
||||
info = region_constraints
|
||||
.constraints
|
||||
.iter()
|
||||
.find_map(|(constraint, cause)| check(constraint, cause, false));
|
||||
}
|
||||
let (sub_region, cause) = info?;
|
||||
|
||||
debug!(?sub_region, "cause = {:#?}", cause);
|
||||
let error = match (error_region, *sub_region) {
|
||||
|
|
|
@ -95,6 +95,12 @@ pub fn into_iter(self) -> impl Iterator<Item = RegionErrorKind<'tcx>> {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for RegionErrors<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_tuple("RegionErrors").field(&self.0).finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) enum RegionErrorKind<'tcx> {
|
||||
/// A generic bound failure for a type test (`T: 'a`).
|
||||
|
|
|
@ -147,6 +147,7 @@ pub(crate) struct AppliedMemberConstraint {
|
|||
pub(crate) member_constraint_index: NllMemberConstraintIndex,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct RegionDefinition<'tcx> {
|
||||
/// What kind of variable is this -- a free region? existential
|
||||
/// variable? etc. (See the `NllRegionVariableOrigin` for more
|
||||
|
@ -680,6 +681,9 @@ pub(super) fn solve(
|
|||
&mut errors_buffer,
|
||||
);
|
||||
|
||||
debug!(?errors_buffer);
|
||||
debug!(?outlives_requirements);
|
||||
|
||||
// In Polonius mode, the errors about missing universal region relations are in the output
|
||||
// and need to be emitted or propagated. Otherwise, we need to check whether the
|
||||
// constraints were too strong, and if so, emit or propagate those errors.
|
||||
|
@ -693,10 +697,14 @@ pub(super) fn solve(
|
|||
self.check_universal_regions(outlives_requirements.as_mut(), &mut errors_buffer);
|
||||
}
|
||||
|
||||
debug!(?errors_buffer);
|
||||
|
||||
if errors_buffer.is_empty() {
|
||||
self.check_member_constraints(infcx, &mut errors_buffer);
|
||||
}
|
||||
|
||||
debug!(?errors_buffer);
|
||||
|
||||
let outlives_requirements = outlives_requirements.unwrap_or_default();
|
||||
|
||||
if outlives_requirements.is_empty() {
|
||||
|
@ -1450,6 +1458,7 @@ fn check_universal_regions(
|
|||
errors_buffer: &mut RegionErrors<'tcx>,
|
||||
) {
|
||||
for (fr, fr_definition) in self.definitions.iter_enumerated() {
|
||||
debug!(?fr, ?fr_definition);
|
||||
match fr_definition.origin {
|
||||
NllRegionVariableOrigin::FreeRegion => {
|
||||
// Go through each of the universal regions `fr` and check that
|
||||
|
|
|
@ -1181,7 +1181,7 @@ fn tcx(&self) -> TyCtxt<'tcx> {
|
|||
self.infcx.tcx
|
||||
}
|
||||
|
||||
#[instrument(skip(self, body, location), level = "debug")]
|
||||
#[instrument(skip(self, body), level = "debug")]
|
||||
fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Location) {
|
||||
let tcx = self.tcx();
|
||||
debug!("stmt kind: {:?}", stmt.kind);
|
||||
|
|
14
tests/ui/higher-ranked/higher-ranked-lifetime-error.rs
Normal file
14
tests/ui/higher-ranked/higher-ranked-lifetime-error.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
fn assert_all<F, T>(_f: F)
|
||||
where
|
||||
F: FnMut(&String) -> T,
|
||||
{
|
||||
}
|
||||
|
||||
fn id(x: &String) -> &String {
|
||||
x
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_all::<_, &String>(id);
|
||||
//~^ mismatched types
|
||||
}
|
12
tests/ui/higher-ranked/higher-ranked-lifetime-error.stderr
Normal file
12
tests/ui/higher-ranked/higher-ranked-lifetime-error.stderr
Normal file
|
@ -0,0 +1,12 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/higher-ranked-lifetime-error.rs:12:5
|
||||
|
|
||||
LL | assert_all::<_, &String>(id);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
||||
|
|
||||
= note: expected reference `&String`
|
||||
found reference `&String`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Reference in a new issue