mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-10 06:47:34 +00:00
Handle anon lifetime arg being returned with named lifetime return type
When there's a lifetime mismatch between an argument with an anonymous lifetime being returned in a method with a return type that has a named lifetime, show specialized lifetime error pointing at argument with a hint to give it an explicit lifetime matching the return type. ``` error[E0621]: explicit lifetime required in the type of `other` --> file2.rs:21:21 | 17 | fn bar(&self, other: Foo) -> Foo<'a> { | ----- consider changing the type of `other` to `Foo<'a>` ... 21 | other | ^^^^^ lifetime `'a` required ``` Follow up to #44124 and #42669.
This commit is contained in:
parent
5ce3d482e2
commit
de959afab5
@ -21,25 +21,42 @@ use hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||
use infer::error_reporting::util::AnonymousArgInfo;
|
||||
|
||||
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
// This method prints the error message for lifetime errors when both the concerned regions
|
||||
// are anonymous.
|
||||
// Consider a case where we have
|
||||
// fn foo(x: &mut Vec<&u8>, y: &u8)
|
||||
// { x.push(y); }.
|
||||
// The example gives
|
||||
// fn foo(x: &mut Vec<&u8>, y: &u8) {
|
||||
// --- --- these references are declared with different lifetimes...
|
||||
// x.push(y);
|
||||
// ^ ...but data from `y` flows into `x` here
|
||||
// It has been extended for the case of structs too.
|
||||
// Consider the example
|
||||
// struct Ref<'a> { x: &'a u32 }
|
||||
// fn foo(mut x: Vec<Ref>, y: Ref) {
|
||||
// --- --- these structs are declared with different lifetimes...
|
||||
// x.push(y);
|
||||
// ^ ...but data from `y` flows into `x` here
|
||||
// }
|
||||
// It will later be extended to trait objects.
|
||||
/// Print the error message for lifetime errors when both the concerned regions are anonymous.
|
||||
///
|
||||
/// Consider a case where we have
|
||||
///
|
||||
/// ```no_run
|
||||
/// fn foo(x: &mut Vec<&u8>, y: &u8) {
|
||||
/// x.push(y);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The example gives
|
||||
///
|
||||
/// ```text
|
||||
/// fn foo(x: &mut Vec<&u8>, y: &u8) {
|
||||
/// --- --- these references are declared with different lifetimes...
|
||||
/// x.push(y);
|
||||
/// ^ ...but data from `y` flows into `x` here
|
||||
/// ```
|
||||
///
|
||||
/// It has been extended for the case of structs too.
|
||||
///
|
||||
/// Consider the example
|
||||
///
|
||||
/// ```no_run
|
||||
/// struct Ref<'a> { x: &'a u32 }
|
||||
/// ```
|
||||
///
|
||||
/// ```text
|
||||
/// fn foo(mut x: Vec<Ref>, y: Ref) {
|
||||
/// --- --- these structs are declared with different lifetimes...
|
||||
/// x.push(y);
|
||||
/// ^ ...but data from `y` flows into `x` here
|
||||
/// }
|
||||
/// ````
|
||||
///
|
||||
/// It will later be extended to trait objects.
|
||||
pub fn try_report_anon_anon_conflict(&self, error: &RegionResolutionError<'tcx>) -> bool {
|
||||
let (span, sub, sup) = match *error {
|
||||
ConcreteFailure(ref origin, sub, sup) => (origin.span(), sub, sup),
|
||||
|
@ -16,18 +16,15 @@ use infer::region_inference::RegionResolutionError;
|
||||
use ty;
|
||||
|
||||
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
// This method generates the error message for the case when
|
||||
// the function arguments consist of a named region and an anonymous
|
||||
// region and corresponds to `ConcreteFailure(..)`
|
||||
/// Generate an error message for when the function arguments consist of a named region and
|
||||
/// an anonymous region and corresponds to `ConcreteFailure(..)`
|
||||
pub fn try_report_named_anon_conflict(&self, error: &RegionResolutionError<'tcx>) -> bool {
|
||||
let (span, sub, sup) = match *error {
|
||||
ConcreteFailure(ref origin, sub, sup) => (origin.span(), sub, sup),
|
||||
_ => return false, // inapplicable
|
||||
};
|
||||
|
||||
debug!("try_report_named_anon_conflict(sub={:?}, sup={:?})",
|
||||
sub,
|
||||
sup);
|
||||
debug!("try_report_named_anon_conflict(sub={:?}, sup={:?})", sub, sup);
|
||||
|
||||
// Determine whether the sub and sup consist of one named region ('a)
|
||||
// and one anonymous (elided) region. If so, find the parameter arg
|
||||
@ -53,10 +50,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
};
|
||||
|
||||
debug!("try_report_named_anon_conflict: named = {:?}", named);
|
||||
debug!("try_report_named_anon_conflict: anon_arg_info = {:?}",
|
||||
anon_arg_info);
|
||||
debug!("try_report_named_anon_conflict: region_info = {:?}",
|
||||
region_info);
|
||||
debug!("try_report_named_anon_conflict: anon_arg_info = {:?}", anon_arg_info);
|
||||
debug!("try_report_named_anon_conflict: region_info = {:?}", region_info);
|
||||
|
||||
let (arg, new_ty, br, is_first, scope_def_id, is_impl_item) = (anon_arg_info.arg,
|
||||
anon_arg_info.arg_ty,
|
||||
@ -101,6 +96,5 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
.span_label(span, format!("lifetime `{}` required", named))
|
||||
.emit();
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -221,6 +221,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
ty::ReEarlyBound(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ struct not_parameterized2 {
|
||||
}
|
||||
|
||||
fn take1<'a>(p: parameterized1) -> parameterized1<'a> { p }
|
||||
//~^ ERROR mismatched types
|
||||
//~^ ERROR explicit lifetime required in the type of `p`
|
||||
|
||||
fn take3(p: not_parameterized1) -> not_parameterized1 { p }
|
||||
fn take4(p: not_parameterized2) -> not_parameterized2 { p }
|
||||
|
@ -1,11 +1,11 @@
|
||||
error[E0623]: lifetime mismatch
|
||||
error[E0621]: explicit lifetime required in the type of `y`
|
||||
--> $DIR/ex3-both-anon-regions-earlybound-regions.rs:17:12
|
||||
|
|
||||
13 | fn baz<'a, 'b, T>(x: &mut Vec<&'a T>, y: &T)
|
||||
| ----- -- these two types are declared with different lifetimes...
|
||||
| - consider changing the type of `y` to `&'a T`
|
||||
...
|
||||
17 | x.push(y);
|
||||
| ^ ...but data from `y` flows into `x` here
|
||||
| ^ lifetime `'a` required
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
30
src/test/ui/lifetime-errors/ex4-anon-named-regions.rs
Normal file
30
src/test/ui/lifetime-errors/ex4-anon-named-regions.rs
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[derive(Clone)]
|
||||
enum Foo<'a> {
|
||||
Bar(&'a str),
|
||||
}
|
||||
|
||||
impl<'a> Foo<'a> {
|
||||
fn bar(&self, other: Foo) -> Foo<'a> {
|
||||
match *self {
|
||||
Foo::Bar(s) => {
|
||||
if s == "test" {
|
||||
other
|
||||
} else {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() { }
|
11
src/test/ui/lifetime-errors/ex4-anon-named-regions.stderr
Normal file
11
src/test/ui/lifetime-errors/ex4-anon-named-regions.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
error[E0621]: explicit lifetime required in the type of `other`
|
||||
--> $DIR/ex4-anon-named-regions.rs:21:21
|
||||
|
|
||||
17 | fn bar(&self, other: Foo) -> Foo<'a> {
|
||||
| ----- consider changing the type of `other` to `Foo<'a>`
|
||||
...
|
||||
21 | other
|
||||
| ^^^^^ lifetime `'a` required
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
Reference in New Issue
Block a user