Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle anon lifetime arg being returned with named lifetime return type #45751

Merged
merged 2 commits into from
Nov 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 36 additions & 19 deletions src/librustc/infer/error_reporting/different_lifetimes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
///
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

/// ```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),
Expand Down
16 changes: 5 additions & 11 deletions src/librustc/infer/error_reporting/named_anon_conflict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(..)`
/// When given a `ConcreteFailure` for a function with arguments containing a named region and
/// an anonymous region, emit an descriptive diagnostic error.
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
Expand All @@ -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,
Expand Down Expand Up @@ -101,6 +96,5 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
.span_label(span, format!("lifetime `{}` required", named))
.emit();
return true;

}
}
1 change: 1 addition & 0 deletions src/librustc/infer/error_reporting/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
_ => false,
}
}
ty::ReEarlyBound(_) => true,
_ => false,
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/regions-infer-at-fn-not-param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
Original file line number Diff line number Diff line change
@@ -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() { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0621]: explicit lifetime required in the type of `other`
--> $DIR/ex1-return-one-existing-name-early-bound-in-struct.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

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0621]: explicit lifetime required in the type of `y`
--> $DIR/ex2a-push-one-existing-name-early-bound.rs:17:12
|
13 | fn baz<'a, 'b, T>(x: &mut Vec<&'a T>, y: &T)
| - consider changing the type of `y` to `&'a T`
...
17 | x.push(y);
| ^ lifetime `'a` required

error: aborting due to previous error

This file was deleted.