borrowck: use implied bounds from impl header
This commit is contained in:
parent
a3fe3bbb2c
commit
8d4693c0f8
@ -1,5 +1,6 @@
|
||||
use rustc_data_structures::frozen::Frozen;
|
||||
use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_infer::infer::canonical::QueryRegionConstraints;
|
||||
use rustc_infer::infer::outlives;
|
||||
use rustc_infer::infer::outlives::env::RegionBoundPairs;
|
||||
@ -195,7 +196,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn create(mut self) -> CreateResult<'tcx> {
|
||||
let span = self.infcx.tcx.def_span(self.universal_regions.defining_ty.def_id());
|
||||
let tcx = self.infcx.tcx;
|
||||
let defining_ty_def_id = self.universal_regions.defining_ty.def_id().expect_local();
|
||||
let span = tcx.def_span(defining_ty_def_id);
|
||||
|
||||
// Insert the facts we know from the predicates. Why? Why not.
|
||||
let param_env = self.param_env;
|
||||
@ -275,6 +278,26 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
normalized_inputs_and_output.push(norm_ty);
|
||||
}
|
||||
|
||||
// Add implied bounds from impl header.
|
||||
if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst) {
|
||||
for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) {
|
||||
let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = self
|
||||
.param_env
|
||||
.and(type_op::normalize::Normalize::new(ty))
|
||||
.fully_perform(self.infcx, span)
|
||||
else {
|
||||
tcx.dcx().span_delayed_bug(span, format!("failed to normalize {ty:?}"));
|
||||
continue;
|
||||
};
|
||||
constraints.extend(c);
|
||||
|
||||
// We currently add implied bounds from the normalized ty only.
|
||||
// This is more conservative and matches wfcheck behavior.
|
||||
let c = self.add_implied_bounds(norm_ty);
|
||||
constraints.extend(c);
|
||||
}
|
||||
}
|
||||
|
||||
for c in constraints {
|
||||
self.push_region_constraints(c, span);
|
||||
}
|
||||
|
@ -3049,9 +3049,8 @@ where
|
||||
#[stable(feature = "hash_extend_copy", since = "1.4.0")]
|
||||
impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashMap<K, V, S>
|
||||
where
|
||||
// FIXME(aliemjay): the bound `+ 'a` should not be necessary.
|
||||
K: Eq + Hash + Copy + 'a,
|
||||
V: Copy + 'a,
|
||||
K: Eq + Hash + Copy,
|
||||
V: Copy,
|
||||
S: BuildHasher,
|
||||
{
|
||||
#[inline]
|
||||
|
42
tests/ui/wf/wf-associated-const.rs
Normal file
42
tests/ui/wf/wf-associated-const.rs
Normal file
@ -0,0 +1,42 @@
|
||||
// check that associated consts can assume the impl header is well-formed.
|
||||
|
||||
// FIXME(aliemjay): we should check the impl header is WF at the use site
|
||||
// but we currently don't in some cases. This is *unsound*.
|
||||
|
||||
trait Foo<'a, 'b, T>: Sized {
|
||||
const EVIL: fn(u: &'b u32) -> &'a u32;
|
||||
}
|
||||
|
||||
struct Evil<'a, 'b: 'a>(Option<&'a &'b ()>);
|
||||
|
||||
impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () {
|
||||
const EVIL: fn(&'b u32) -> &'a u32 = { |u| u };
|
||||
}
|
||||
|
||||
struct IndirectEvil<'a, 'b: 'a>(Option<&'a &'b ()>);
|
||||
|
||||
impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> {
|
||||
const EVIL: fn(&'b u32) -> &'a u32 = { |u| u };
|
||||
}
|
||||
|
||||
impl<'a, 'b> Evil<'a, 'b> {
|
||||
const INHERENT_EVIL: fn(&'b u32) -> &'a u32 = { |u| u };
|
||||
}
|
||||
|
||||
// while static methods can *assume* this, we should still
|
||||
// *check* that it holds at the use site.
|
||||
|
||||
fn evil<'a, 'b>(b: &'b u32) -> &'a u32 {
|
||||
<()>::EVIL(b) // FIXME: should be an error
|
||||
}
|
||||
|
||||
fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
|
||||
<IndirectEvil>::EVIL(b) // FIXME: should be an error
|
||||
}
|
||||
|
||||
fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
|
||||
<Evil>::INHERENT_EVIL(b)
|
||||
//~^ ERROR lifetime may not live long enough
|
||||
}
|
||||
|
||||
fn main() {}
|
14
tests/ui/wf/wf-associated-const.stderr
Normal file
14
tests/ui/wf/wf-associated-const.stderr
Normal file
@ -0,0 +1,14 @@
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/wf-associated-const.rs:38:5
|
||||
|
|
||||
LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
|
||||
| -- -- lifetime `'b` defined here
|
||||
| |
|
||||
| lifetime `'a` defined here
|
||||
LL | <Evil>::INHERENT_EVIL(b)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
|
||||
|
|
||||
= help: consider adding the following bound: `'b: 'a`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -1,8 +1,4 @@
|
||||
// check that static methods don't get to assume their trait-ref
|
||||
// is well-formed.
|
||||
// FIXME(#27579): this is just a bug. However, our checking with
|
||||
// static inherent methods isn't quite working - need to
|
||||
// fix that before removing the check.
|
||||
// check that static methods can assume their trait-ref is well-formed.
|
||||
|
||||
trait Foo<'a, 'b, T>: Sized {
|
||||
fn make_me() -> Self { loop {} }
|
||||
@ -15,7 +11,6 @@ impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () {
|
||||
fn make_me() -> Self { }
|
||||
fn static_evil(u: &'b u32) -> &'a u32 {
|
||||
u
|
||||
//~^ ERROR lifetime may not live long enough
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +20,6 @@ impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> {
|
||||
fn make_me() -> Self { IndirectEvil(None) }
|
||||
fn static_evil(u: &'b u32) -> &'a u32 {
|
||||
let me = Self::make_me();
|
||||
//~^ ERROR lifetime may not live long enough
|
||||
loop {} // (`me` could be used for the lifetime transmute).
|
||||
}
|
||||
}
|
||||
@ -33,12 +27,11 @@ impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> {
|
||||
impl<'a, 'b> Evil<'a, 'b> {
|
||||
fn inherent_evil(u: &'b u32) -> &'a u32 {
|
||||
u
|
||||
//~^ ERROR lifetime may not live long enough
|
||||
}
|
||||
}
|
||||
|
||||
// while static methods don't get to *assume* this, we still
|
||||
// *check* that they hold.
|
||||
// while static methods can *assume* this, we should still
|
||||
// *check* that it holds at the use site.
|
||||
|
||||
fn evil<'a, 'b>(b: &'b u32) -> &'a u32 {
|
||||
<()>::static_evil(b)
|
||||
|
@ -1,44 +1,5 @@
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/wf-static-method.rs:17:9
|
||||
|
|
||||
LL | impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () {
|
||||
| -- -- lifetime `'b` defined here
|
||||
| |
|
||||
| lifetime `'a` defined here
|
||||
...
|
||||
LL | u
|
||||
| ^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
|
||||
|
|
||||
= help: consider adding the following bound: `'b: 'a`
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/wf-static-method.rs:27:18
|
||||
|
|
||||
LL | impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> {
|
||||
| -- -- lifetime `'b` defined here
|
||||
| |
|
||||
| lifetime `'a` defined here
|
||||
...
|
||||
LL | let me = Self::make_me();
|
||||
| ^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
|
||||
|
|
||||
= help: consider adding the following bound: `'b: 'a`
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/wf-static-method.rs:35:9
|
||||
|
|
||||
LL | impl<'a, 'b> Evil<'a, 'b> {
|
||||
| -- -- lifetime `'b` defined here
|
||||
| |
|
||||
| lifetime `'a` defined here
|
||||
LL | fn inherent_evil(u: &'b u32) -> &'a u32 {
|
||||
LL | u
|
||||
| ^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
|
||||
|
|
||||
= help: consider adding the following bound: `'b: 'a`
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/wf-static-method.rs:44:5
|
||||
--> $DIR/wf-static-method.rs:37:5
|
||||
|
|
||||
LL | fn evil<'a, 'b>(b: &'b u32) -> &'a u32 {
|
||||
| -- -- lifetime `'b` defined here
|
||||
@ -50,7 +11,7 @@ LL | <()>::static_evil(b)
|
||||
= help: consider adding the following bound: `'b: 'a`
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/wf-static-method.rs:49:5
|
||||
--> $DIR/wf-static-method.rs:42:5
|
||||
|
|
||||
LL | fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
|
||||
| -- -- lifetime `'b` defined here
|
||||
@ -62,7 +23,7 @@ LL | <IndirectEvil>::static_evil(b)
|
||||
= help: consider adding the following bound: `'b: 'a`
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/wf-static-method.rs:54:5
|
||||
--> $DIR/wf-static-method.rs:47:5
|
||||
|
|
||||
LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
|
||||
| -- -- lifetime `'b` defined here
|
||||
@ -73,5 +34,5 @@ LL | <Evil>::inherent_evil(b)
|
||||
|
|
||||
= help: consider adding the following bound: `'b: 'a`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user