Don't ICE if HIR and middle types disagree in borrowck error reporting

This commit is contained in:
Michael Goulet 2024-07-24 23:36:42 -04:00
parent 2ccafed862
commit d004edf311
4 changed files with 81 additions and 20 deletions

View File

@ -4304,17 +4304,35 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
// search for relevant arguments.
let mut arguments = Vec::new();
for (index, argument) in sig.inputs().skip_binder().iter().enumerate() {
if let ty::Ref(argument_region, _, _) = argument.kind() {
if argument_region == return_region {
// Need to use the `rustc_middle::ty` types to compare against the
// `return_region`. Then use the `rustc_hir` type to get only
// the lifetime span.
if let hir::TyKind::Ref(lifetime, _) = &fn_decl.inputs[index].kind {
if let ty::Ref(argument_region, _, _) = argument.kind()
&& argument_region == return_region
{
// Need to use the `rustc_middle::ty` types to compare against the
// `return_region`. Then use the `rustc_hir` type to get only
// the lifetime span.
match &fn_decl.inputs[index].kind {
hir::TyKind::Ref(lifetime, _) => {
// With access to the lifetime, we can get
// the span of it.
arguments.push((*argument, lifetime.ident.span));
} else {
bug!("ty type is a ref but hir type is not");
}
// Resolve `self` whose self type is `&T`.
hir::TyKind::Path(hir::QPath::Resolved(None, path)) => {
if let Res::SelfTyAlias { alias_to, .. } = path.res
&& let Some(alias_to) = alias_to.as_local()
&& let hir::Impl { self_ty, .. } = self
.infcx
.tcx
.hir_node_by_def_id(alias_to)
.expect_item()
.expect_impl()
&& let hir::TyKind::Ref(lifetime, _) = self_ty.kind
{
arguments.push((*argument, lifetime.ident.span));
}
}
_ => {
// Don't ICE though. It might be a type alias.
}
}
}

View File

@ -1,12 +0,0 @@
//@ known-bug: #121816
fn f<'a, T>(_: &'static &'a (), x: &'a T) -> &'static T {
x
}
trait W<'a> {
fn g<T>(self, x: &'a T) -> &'static T;
}
impl<'a> W<'a> for &'static () {
fn g<T>(self, x: &'a T) -> &'static T {
f(&self, x)
}
}

View File

@ -0,0 +1,19 @@
// Don't ICE when trying to annotate signature and we see `&()`
fn f<'a, T>(_: &'static &'a (), x: &'a T) -> &'static T {
x
}
trait W<'a> {
fn g<T>(self, x: &'a T) -> &'static T;
}
// Frankly this error message is impossible to parse, but :shrug:.
impl<'a> W<'a> for &'static () {
fn g<T>(self, x: &'a T) -> &'static T {
f(&self, x)
//~^ ERROR borrowed data escapes outside of method
//~| ERROR `self` does not live long enough
}
}
fn main() {}

View File

@ -0,0 +1,36 @@
error[E0521]: borrowed data escapes outside of method
--> $DIR/ice-on-non-ref-sig-ty.rs:13:9
|
LL | impl<'a> W<'a> for &'static () {
| -- lifetime `'a` defined here
LL | fn g<T>(self, x: &'a T) -> &'static T {
| ---- - `x` is a reference that is only valid in the method body
| |
| `self` declared here, outside of the method body
LL | f(&self, x)
| ^^^^^^^^^^^
| |
| `x` escapes the method body here
| argument requires that `'a` must outlive `'static`
error[E0597]: `self` does not live long enough
--> $DIR/ice-on-non-ref-sig-ty.rs:13:11
|
LL | impl<'a> W<'a> for &'static () {
| ------- has lifetime `'static`
LL | fn g<T>(self, x: &'a T) -> &'static T {
| ------- also has lifetime `'static`
LL | f(&self, x)
| ^^^^^ `self` would have to be valid for `'static`...
...
LL | }
| - ...but `self` will be dropped here, when the function `g` returns
|
= help: use data from the highlighted arguments which match the `'static` lifetime of the return type
= note: functions cannot return a borrow to data owned within the function's scope, functions can only return borrows to data passed as arguments
= note: to learn more, visit <https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#dangling-references>
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0521, E0597.
For more information about an error, try `rustc --explain E0521`.