Skip to content

Commit 35dd0c9

Browse files
committed
Try to use approximate placeholder regions when outputting an AscribeUserType error in borrowck
1 parent 42ca6e4 commit 35dd0c9

File tree

6 files changed

+80
-13
lines changed

6 files changed

+80
-13
lines changed

compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs

+38-12
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ use rustc_infer::infer::RegionVariableOrigin;
1010
use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _};
1111
use rustc_infer::traits::ObligationCause;
1212
use rustc_middle::ty::error::TypeError;
13+
use rustc_middle::ty::RePlaceholder;
14+
use rustc_middle::ty::Region;
1315
use rustc_middle::ty::RegionVid;
1416
use rustc_middle::ty::UniverseIndex;
1517
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
@@ -205,6 +207,8 @@ trait TypeOpInfo<'tcx> {
205207
let span = cause.span;
206208
let nice_error = self.nice_error(mbcx, cause, placeholder_region, error_region);
207209

210+
debug!(?nice_error);
211+
208212
if let Some(nice_error) = nice_error {
209213
mbcx.buffer_error(nice_error);
210214
} else {
@@ -404,19 +408,41 @@ fn try_extract_error_from_region_constraints<'tcx>(
404408
mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin,
405409
mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex,
406410
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
407-
let (sub_region, cause) =
408-
region_constraints.constraints.iter().find_map(|(constraint, cause)| {
409-
match *constraint {
410-
Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => {
411-
Some((sub, cause.clone()))
412-
}
413-
// FIXME: Should this check the universe of the var?
414-
Constraint::VarSubReg(vid, sup) if sup == placeholder_region => {
415-
Some((ty::Region::new_var(infcx.tcx, vid), cause.clone()))
416-
}
417-
_ => None,
411+
let matches =
412+
|a_region: Region<'tcx>, b_region: Region<'tcx>| match (a_region.kind(), b_region.kind()) {
413+
(RePlaceholder(a_p), RePlaceholder(b_p)) => a_p.bound == b_p.bound,
414+
_ => a_region == b_region,
415+
};
416+
let check = |constraint: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| {
417+
match *constraint {
418+
Constraint::RegSubReg(sub, sup)
419+
if ((exact && sup == placeholder_region)
420+
|| (!exact && matches(sup, placeholder_region)))
421+
&& sup != sub =>
422+
{
423+
Some((sub, cause.clone()))
424+
}
425+
// FIXME: Should this check the universe of the var?
426+
Constraint::VarSubReg(vid, sup)
427+
if ((exact && sup == placeholder_region)
428+
|| (!exact && matches(sup, placeholder_region))) =>
429+
{
430+
Some((ty::Region::new_var(infcx.tcx, vid), cause.clone()))
418431
}
419-
})?;
432+
_ => None,
433+
}
434+
};
435+
let mut info = region_constraints
436+
.constraints
437+
.iter()
438+
.find_map(|(constraint, cause)| check(constraint, cause, true));
439+
if info.is_none() {
440+
info = region_constraints
441+
.constraints
442+
.iter()
443+
.find_map(|(constraint, cause)| check(constraint, cause, false));
444+
}
445+
let (sub_region, cause) = info?;
420446

421447
debug!(?sub_region, "cause = {:#?}", cause);
422448
let error = match (error_region, *sub_region) {

compiler/rustc_borrowck/src/diagnostics/region_errors.rs

+6
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ impl<'tcx> RegionErrors<'tcx> {
9595
}
9696
}
9797

98+
impl std::fmt::Debug for RegionErrors<'_> {
99+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100+
f.debug_tuple("RegionErrors").field(&self.0).finish()
101+
}
102+
}
103+
98104
#[derive(Clone, Debug)]
99105
pub(crate) enum RegionErrorKind<'tcx> {
100106
/// A generic bound failure for a type test (`T: 'a`).

compiler/rustc_borrowck/src/region_infer/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ pub(crate) struct AppliedMemberConstraint {
147147
pub(crate) member_constraint_index: NllMemberConstraintIndex,
148148
}
149149

150+
#[derive(Debug)]
150151
pub(crate) struct RegionDefinition<'tcx> {
151152
/// What kind of variable is this -- a free region? existential
152153
/// variable? etc. (See the `NllRegionVariableOrigin` for more
@@ -680,6 +681,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
680681
&mut errors_buffer,
681682
);
682683

684+
debug!(?errors_buffer);
685+
debug!(?outlives_requirements);
686+
683687
// In Polonius mode, the errors about missing universal region relations are in the output
684688
// and need to be emitted or propagated. Otherwise, we need to check whether the
685689
// constraints were too strong, and if so, emit or propagate those errors.
@@ -693,10 +697,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
693697
self.check_universal_regions(outlives_requirements.as_mut(), &mut errors_buffer);
694698
}
695699

700+
debug!(?errors_buffer);
701+
696702
if errors_buffer.is_empty() {
697703
self.check_member_constraints(infcx, &mut errors_buffer);
698704
}
699705

706+
debug!(?errors_buffer);
707+
700708
let outlives_requirements = outlives_requirements.unwrap_or_default();
701709

702710
if outlives_requirements.is_empty() {
@@ -1450,6 +1458,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
14501458
errors_buffer: &mut RegionErrors<'tcx>,
14511459
) {
14521460
for (fr, fr_definition) in self.definitions.iter_enumerated() {
1461+
debug!(?fr, ?fr_definition);
14531462
match fr_definition.origin {
14541463
NllRegionVariableOrigin::FreeRegion => {
14551464
// Go through each of the universal regions `fr` and check that

compiler/rustc_borrowck/src/type_check/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1181,7 +1181,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
11811181
self.infcx.tcx
11821182
}
11831183

1184-
#[instrument(skip(self, body, location), level = "debug")]
1184+
#[instrument(skip(self, body), level = "debug")]
11851185
fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Location) {
11861186
let tcx = self.tcx();
11871187
debug!("stmt kind: {:?}", stmt.kind);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
fn assert_all<F, T>(_f: F)
2+
where
3+
F: FnMut(&String) -> T,
4+
{
5+
}
6+
7+
fn id(x: &String) -> &String {
8+
x
9+
}
10+
11+
fn main() {
12+
assert_all::<_, &String>(id);
13+
//~^ mismatched types
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/higher-ranked-lifetime-error.rs:12:5
3+
|
4+
LL | assert_all::<_, &String>(id);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
6+
|
7+
= note: expected reference `&String`
8+
found reference `&String`
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)