Skip to content

Commit

Permalink
Use Predicate ConstraintCategory when normalizing
Browse files Browse the repository at this point in the history
  • Loading branch information
jackh726 committed Sep 17, 2022
1 parent 1eb71f0 commit e7ca6e1
Show file tree
Hide file tree
Showing 14 changed files with 172 additions and 15 deletions.
5 changes: 1 addition & 4 deletions compiler/rustc_borrowck/src/constraints/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ pub(crate) struct OutlivesConstraintSet<'tcx> {

impl<'tcx> OutlivesConstraintSet<'tcx> {
pub(crate) fn push(&mut self, constraint: OutlivesConstraint<'tcx>) {
debug!(
"OutlivesConstraintSet::push({:?}: {:?} @ {:?}",
constraint.sup, constraint.sub, constraint.locations
);
debug!("OutlivesConstraintSet::push({:?})", constraint);
if constraint.sup == constraint.sub {
// 'a: 'a is pretty uninteresting
return;
Expand Down
20 changes: 14 additions & 6 deletions compiler/rustc_borrowck/src/diagnostics/region_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use crate::session_diagnostics::{
};

use super::{OutlivesSuggestionBuilder, RegionName};
use crate::region_infer::BlameConstraint;
use crate::region_infer::{BlameConstraint, ExtraConstraintInfo};
use crate::{
nll::ConstraintDescription,
region_infer::{values::RegionElement, TypeTest},
Expand Down Expand Up @@ -354,12 +354,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
) {
debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);

let BlameConstraint { category, cause, variance_info, .. } = self
.regioncx
.best_blame_constraint(fr, fr_origin, |r| {
let (blame_constraint, extra_info) =
self.regioncx.best_blame_constraint(fr, fr_origin, |r| {
self.regioncx.provides_universal_region(r, fr, outlived_fr)
})
.0;
});
let BlameConstraint { category, cause, variance_info, .. } = blame_constraint;

debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info);

Expand Down Expand Up @@ -468,6 +467,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}

for extra in extra_info {
match extra {
ExtraConstraintInfo::PlaceholderFromPredicate(span) => {
diag.span_note(span, format!("due to current limitations in the borrow checker, this implies a `'static` lifetime"));
}
}
}

self.buffer_error(diag);
}

Expand Down Expand Up @@ -559,6 +566,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
/// LL | ref_obj(x)
/// | ^^^^^^^^^^ `x` escapes the function body here
/// ```
#[instrument(level = "debug", skip(self))]
fn report_escaping_data_error(
&self,
errci: &ErrorConstraintInfo<'tcx>,
Expand Down
22 changes: 18 additions & 4 deletions compiler/rustc_borrowck/src/type_check/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);
}

#[instrument(level = "debug", skip(self))]
pub(super) fn normalize_and_prove_instantiated_predicates(
&mut self,
// Keep this parameter for now, in case we start using
Expand All @@ -118,8 +119,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
.zip(instantiated_predicates.spans.into_iter())
{
debug!(?predicate);
let predicate = self.normalize(predicate, locations);
self.prove_predicate(predicate, locations, ConstraintCategory::Predicate(span));
let category = ConstraintCategory::Predicate(span);
let predicate = self.normalize_with_category(predicate, locations, category);
self.prove_predicate(predicate, locations, category);
}
}

Expand Down Expand Up @@ -155,15 +157,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
})
}

#[instrument(skip(self), level = "debug")]
pub(super) fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
where
T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
{
self.normalize_with_category(value, location, ConstraintCategory::Boring)
}

#[instrument(skip(self), level = "debug")]
pub(super) fn normalize_with_category<T>(
&mut self,
value: T,
location: impl NormalizeLocation,
category: ConstraintCategory<'tcx>,
) -> T
where
T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
{
let param_env = self.param_env;
self.fully_perform_op(
location.to_locations(),
ConstraintCategory::Boring,
category,
param_env.and(type_op::normalize::Normalize::new(value)),
)
.unwrap_or_else(|NoSolution| {
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
}

fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
debug!(?constant, ?location, "visit_constant");

self.super_constant(constant, location);
let ty = self.sanitize_type(constant, constant.literal.ty());

Expand Down Expand Up @@ -1811,6 +1813,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}

fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) {
debug!(?op, ?location, "check_operand");

if let Operand::Constant(constant) = op {
let maybe_uneval = match constant.literal {
ConstantKind::Ty(ct) => match ct.kind() {
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_trait_selection/src/traits/query/normalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,11 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
T: TypeFoldable<'tcx>,
{
debug!(
"normalize::<{}>(value={:?}, param_env={:?})",
"normalize::<{}>(value={:?}, param_env={:?}, cause={:?})",
std::any::type_name::<T>(),
value,
self.param_env,
self.cause,
);
if !needs_normalization(&value, self.param_env.reveal()) {
return Ok(Normalized { value, obligations: vec![] });
Expand Down
40 changes: 40 additions & 0 deletions src/test/ui/generic-associated-types/bugs/hrtb-implied-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// check-fail
// known-bug

// This gives us problems because `for<'a> I::Item<'a>: Debug` should mean "for
// all 'a where I::Item<'a> is WF", but really means "for all 'a possible"

trait LendingIterator: Sized {
type Item<'a>
where
Self: 'a;
fn next(&mut self) -> Self::Item<'_>;
}
fn fails<I: LendingIterator, F>(iter: &mut I, f: F) -> bool
where
F: FnMut(I::Item<'_>),
{
let mut iter2 = Eat(iter, f);
let _next = iter2.next();
//~^ borrowed data escapes
true
}
impl<I: LendingIterator> LendingIterator for &mut I {
type Item<'a> = I::Item<'a> where Self:'a;
fn next(&mut self) -> Self::Item<'_> {
(**self).next()
}
}

struct Eat<I, F>(I, F);
impl<I: LendingIterator, F> Iterator for Eat<I, F>
where
F: FnMut(I::Item<'_>),
{
type Item = ();
fn next(&mut self) -> Option<Self::Item> {
None
}
}

fn main() {}
22 changes: 22 additions & 0 deletions src/test/ui/generic-associated-types/bugs/hrtb-implied-2.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
error[E0521]: borrowed data escapes outside of function
--> $DIR/hrtb-implied-2.rs:18:17
|
LL | fn fails<I: LendingIterator, F>(iter: &mut I, f: F) -> bool
| ---- - let's call the lifetime of this reference `'1`
| |
| `iter` is a reference that is only valid in the function body
...
LL | let _next = iter2.next();
| ^^^^^^^^^^^^
| |
| `iter` escapes the function body here
| argument requires that `'1` must outlive `'static`
|
= note: requirement occurs because of a mutable reference to `Eat<&mut I, F>`
= note: mutable references are invariant over their type parameter
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
= note: due to current limitations in the borrow checker, this implies a `'static` lifetime

error: aborting due to previous error

For more information about this error, try `rustc --explain E0521`.
23 changes: 23 additions & 0 deletions src/test/ui/generic-associated-types/bugs/hrtb-implied-3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
trait LendingIterator {
type Item<'a>
where
Self: 'a;
}

impl LendingIterator for &str {
type Item<'a> = () where Self:'a;
}

fn trivial_bound<I>(_: I)
where
I: LendingIterator,
for<'a> I::Item<'a>: Sized,
{
}

fn fails(iter: &str) {
trivial_bound(iter);
//~^ borrowed data escapes
}

fn main() {}
22 changes: 22 additions & 0 deletions src/test/ui/generic-associated-types/bugs/hrtb-implied-3.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
error[E0521]: borrowed data escapes outside of function
--> $DIR/hrtb-implied-3.rs:19:5
|
LL | fn fails(iter: &str) {
| ---- - let's call the lifetime of this reference `'1`
| |
| `iter` is a reference that is only valid in the function body
LL | trivial_bound(iter);
| ^^^^^^^^^^^^^^^^^^^
| |
| `iter` escapes the function body here
| argument requires that `'1` must outlive `'static`
|
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
--> $DIR/hrtb-implied-3.rs:14:26
|
LL | for<'a> I::Item<'a>: Sized,
| ^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0521`.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ LL | x.size_hint().0
| |
| `x` escapes the function body here
| argument requires that `'1` must outlive `'static`
|
= note: due to current limitations in the borrow checker, this implies a `'static` lifetime

error: aborting due to previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ LL | fn give_some<'a>() {
| -- lifetime `'a` defined here
LL | want_hrtb::<&'a u32>()
| ^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
--> $DIR/hrtb-just-for-static.rs:9:15
|
LL | where T : for<'a> Foo<&'a isize>
| ^^^^^^^^^^^^^^^^^^^^^^

error: implementation of `Foo` is not general enough
--> $DIR/hrtb-just-for-static.rs:30:5
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ LL | fn foo_hrtb_bar_not<'b, T>(mut t: T)
...
LL | foo_hrtb_bar_not(&mut t);
| ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
|
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
--> $DIR/hrtb-perfect-forwarding.rs:37:8
|
LL | T: for<'a> Foo<&'a isize> + Bar<&'b isize>,
| ^^^^^^^^^^^^^^^^^^^^^^

error: implementation of `Bar` is not general enough
--> $DIR/hrtb-perfect-forwarding.rs:43:5
Expand Down
6 changes: 6 additions & 0 deletions src/test/ui/issues/issue-26217.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ LL | fn bar<'a>() {
| -- lifetime `'a` defined here
LL | foo::<&'a i32>();
| ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
--> $DIR/issue-26217.rs:1:30
|
LL | fn foo<T>() where for<'a> T: 'a {}
| ^^

error: aborting due to previous error

6 changes: 6 additions & 0 deletions src/test/ui/nll/type-test-universe.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ LL | fn test2<'a>() {
| -- lifetime `'a` defined here
LL | outlives_forall::<Value<'a>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
--> $DIR/type-test-universe.rs:6:16
|
LL | for<'u> T: 'u,
| ^^

error: aborting due to 2 previous errors

0 comments on commit e7ca6e1

Please sign in to comment.