/// from a `for<'a> T` binder). Meant to represent "any region".
Placeholder(ty::PlaceholderRegion),
- Existential,
+ Existential {
+ was_placeholder: bool
+ },
}
impl NLLRegionVariableOrigin {
match self {
NLLRegionVariableOrigin::FreeRegion => true,
NLLRegionVariableOrigin::Placeholder(..) => true,
- NLLRegionVariableOrigin::Existential => false,
+ NLLRegionVariableOrigin::Existential{ .. } => false,
}
}
/// we will invoke this method to instantiate `'a` with an
/// inference variable (though `'b` would be instantiated first,
/// as a placeholder).
- fn next_existential_region_var(&mut self) -> ty::Region<'tcx>;
+ fn next_existential_region_var(&mut self, was_placeholder: bool) -> ty::Region<'tcx>;
/// Creates a new region variable representing a
/// higher-ranked region that is instantiated universally.
let placeholder = ty::PlaceholderRegion { universe, name: br };
delegate.next_placeholder_region(placeholder)
} else {
- delegate.next_existential_region_var()
+ delegate.next_existential_region_var(true)
}
}
};
&self,
body: &Body<'tcx>,
from_region: RegionVid,
+ from_region_origin: NLLRegionVariableOrigin,
target_test: impl Fn(RegionVid) -> bool,
) -> (ConstraintCategory, bool, Span) {
- debug!("best_blame_constraint(from_region={:?})", from_region);
+ debug!("best_blame_constraint(from_region={:?}, from_region_origin={:?})",
+ from_region, from_region_origin);
// Find all paths
let (path, target_region) =
// we still want to screen for an "interesting" point to
// highlight (e.g., a call site or something).
let target_scc = self.constraint_sccs.scc(target_region);
- let best_choice = (0..path.len()).rev().find(|&i| {
- let constraint = path[i];
+ let mut range = 0..path.len();
+
+ let should_reverse = match from_region_origin {
+ NLLRegionVariableOrigin::FreeRegion
+ | NLLRegionVariableOrigin::Existential { was_placeholder: false } => {
+ true
+ }
+ NLLRegionVariableOrigin::Placeholder(_)
+ | NLLRegionVariableOrigin::Existential { was_placeholder: true } => {
+ false
+ }
+ };
+
+ let find_region = |i: &usize| {
+ let constraint = path[*i];
let constraint_sup_scc = self.constraint_sccs.scc(constraint.sup);
- match categorized_path[i].0 {
- ConstraintCategory::OpaqueType | ConstraintCategory::Boring |
- ConstraintCategory::BoringNoLocation | ConstraintCategory::Internal => false,
- ConstraintCategory::TypeAnnotation | ConstraintCategory::Return |
- ConstraintCategory::Yield => true,
- _ => constraint_sup_scc != target_scc,
+ if should_reverse {
+ match categorized_path[*i].0 {
+ ConstraintCategory::OpaqueType | ConstraintCategory::Boring |
+ ConstraintCategory::BoringNoLocation | ConstraintCategory::Internal => false,
+ ConstraintCategory::TypeAnnotation | ConstraintCategory::Return |
+ ConstraintCategory::Yield => true,
+ _ => constraint_sup_scc != target_scc,
+ }
+ } else {
+ match categorized_path[*i].0 {
+ ConstraintCategory::OpaqueType | ConstraintCategory::Boring |
+ ConstraintCategory::BoringNoLocation | ConstraintCategory::Internal => false,
+ _ => true
+ }
}
- });
+ };
+
+ let best_choice = if should_reverse {
+ range.rev().find(find_region)
+ } else {
+ range.find(find_region)
+ };
+
+ debug!("best_blame_constraint: best_choice={:?} should_reverse={}",
+ best_choice, should_reverse);
+
if let Some(i) = best_choice {
if let Some(next) = categorized_path.get(i + 1) {
if categorized_path[i].0 == ConstraintCategory::Return
infcx: &'a InferCtxt<'a, 'tcx>,
mir_def_id: DefId,
fr: RegionVid,
+ fr_origin: NLLRegionVariableOrigin,
outlived_fr: RegionVid,
renctx: &mut RegionErrorNamingCtx,
) -> DiagnosticBuilder<'a> {
debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
- let (category, _, span) = self.best_blame_constraint(body, fr, |r| {
+ let (category, _, span) = self.best_blame_constraint(body, fr, fr_origin, |r| {
self.provides_universal_region(r, fr, outlived_fr)
});
let (category, from_closure, span) = self.best_blame_constraint(
body,
borrow_region,
+ NLLRegionVariableOrigin::FreeRegion,
|r| self.provides_universal_region(r, borrow_region, outlived_region)
);
&self,
body: &Body<'tcx>,
fr1: RegionVid,
+ fr1_origin: NLLRegionVariableOrigin,
fr2: RegionVid,
) -> (ConstraintCategory, Span) {
let (category, _, span) = self.best_blame_constraint(
body,
fr1,
+ fr1_origin,
|r| self.provides_universal_region(r, fr1, fr2),
);
(category, span)
universe1.cannot_name(placeholder.universe)
}
- NLLRegionVariableOrigin::FreeRegion | NLLRegionVariableOrigin::Existential => false,
+ NLLRegionVariableOrigin::FreeRegion | NLLRegionVariableOrigin::Existential { .. } => {
+ false
+ }
}
}
}
}
}
- NLLRegionVariableOrigin::Existential => {
+ NLLRegionVariableOrigin::Existential { .. } => {
// For existential, regions, nothing to do.
}
}
self.check_bound_universal_region(infcx, body, mir_def_id, fr, placeholder);
}
- NLLRegionVariableOrigin::Existential => {
+ NLLRegionVariableOrigin::Existential { .. } => {
// nothing to check here
}
}
debug!("check_universal_region: fr_minus={:?}", fr_minus);
let blame_span_category =
- self.find_outlives_blame_span(body, longer_fr, shorter_fr);
+ self.find_outlives_blame_span(body, longer_fr,
+ NLLRegionVariableOrigin::FreeRegion,shorter_fr);
// Grow `shorter_fr` until we find some non-local regions. (We
// always will.) We'll call them `shorter_fr+` -- they're ever
infcx,
mir_def_id,
longer_fr,
+ NLLRegionVariableOrigin::FreeRegion,
shorter_fr,
region_naming,
);
};
// Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
- let (_, span) = self.find_outlives_blame_span(body, longer_fr, error_region);
+ let (_, span) = self.find_outlives_blame_span(
+ body, longer_fr, NLLRegionVariableOrigin::Placeholder(placeholder), error_region
+ );
// Obviously, this error message is far from satisfactory.
// At present, though, it only appears in unit tests --
let origin = match rv_origin {
RegionVariableOrigin::NLL(origin) => origin,
- _ => NLLRegionVariableOrigin::Existential,
+ _ => NLLRegionVariableOrigin::Existential { was_placeholder: false },
};
Self { origin, universe, external_name: None }
infcx
.tcx
.fold_regions(value, &mut false, |_region, _depth| {
- let origin = NLLRegionVariableOrigin::Existential;
+ let origin = NLLRegionVariableOrigin::Existential { was_placeholder: false };
infcx.next_nll_region_var(origin)
})
}
self.infcx.create_next_universe()
}
- fn next_existential_region_var(&mut self) -> ty::Region<'tcx> {
+ fn next_existential_region_var(&mut self, was_placeholder: bool) -> ty::Region<'tcx> {
if let Some(_) = &mut self.borrowck_context {
- let origin = NLLRegionVariableOrigin::Existential;
+ let origin = NLLRegionVariableOrigin::Existential { was_placeholder };
self.infcx.next_nll_region_var(origin)
} else {
self.infcx.tcx.lifetimes.re_erased
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
self.infcx
- .next_nll_region_var_in_universe(NLLRegionVariableOrigin::Existential, universe)
+ .next_nll_region_var_in_universe(NLLRegionVariableOrigin::Existential {
+ was_placeholder: false
+ }, universe)
}
fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
self.infcx.create_next_universe()
}
- fn next_existential_region_var(&mut self) -> ty::Region<'tcx> {
+ fn next_existential_region_var(&mut self, _was_placeholder: bool) -> ty::Region<'tcx> {
self.infcx.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP))
}
//[nll]~^ ERROR higher-ranked subtype error
let count = filter.count(); // Assert that we still have a valid stream.
//[nll]~^ ERROR higher-ranked subtype error
+
}
--- /dev/null
+// Test that NLL produces correct spans for higher-ranked subtyping errors.
+//
+// compile-flags:-Zno-leak-check
+
+#![feature(nll)]
+
+fn main() {
+ let x: fn(&'static ()) = |_| {};
+ let y: for<'a> fn(&'a ()) = x; //~ ERROR higher-ranked subtype error
+}
--- /dev/null
+error: higher-ranked subtype error
+ --> $DIR/fn-subtype.rs:9:33
+ |
+LL | let y: for<'a> fn(&'a ()) = x;
+ | ^
+
+error: aborting due to previous error
+
--- /dev/null
+// Test that NLL generates proper error spans for trait HRTB errors
+//
+// compile-flags:-Zno-leak-check
+
+#![feature(nll)]
+
+trait Foo<'a> {}
+
+fn make_foo<'a>() -> Box<dyn Foo<'a>> {
+ panic!()
+}
+
+fn main() {
+ let x: Box<dyn Foo<'static>> = make_foo();
+ let y: Box<dyn for<'a> Foo<'a>> = x; //~ ERROR higher-ranked subtype error
+}
--- /dev/null
+error: higher-ranked subtype error
+ --> $DIR/trait-hrtb.rs:15:39
+ |
+LL | let y: Box<dyn for<'a> Foo<'a>> = x;
+ | ^
+
+error: aborting due to previous error
+