Either way, try to update/remove it in order to fix the error.
"##,
+E0611: r##"
+Lifetime parameter is missing in one of the function argument. Erroneous
+code example:
+
+```compile_fail,E0611
+fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 { // explicit lifetime required
+ // in the type of `y`
+ if x > y { x } else { y }
+}
+
+fn main () { }
+```
+
+Please add the missing lifetime parameter to remove this error. Example:
+
+```
+fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
+ if x > y { x } else { y }
+}
+
+fn main() {
+}
+```
+"##,
+
}
use middle::region;
use traits::{ObligationCause, ObligationCauseCode};
use ty::{self, TyCtxt, TypeFoldable};
-use ty::{Region, Issue32330};
+use ty::{Region, Issue32330 };
use ty::error::TypeError;
use syntax::ast::DUMMY_NODE_ID;
use syntax_pos::{Pos, Span};
use errors::{DiagnosticBuilder, DiagnosticStyledString};
-
mod note;
+
mod need_type_info;
+mod named_anon_conflict;
+mod util;
+
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn note_and_explain_region(self,
}
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
- pub fn report_region_errors(&self,
- errors: &Vec<RegionResolutionError<'tcx>>) {
+
+ pub fn report_region_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>) {
debug!("report_region_errors(): {} errors to start", errors.len());
// try to pre-process the errors, which will group some of them
// together into a `ProcessedErrors` group:
let errors = self.process_errors(errors);
- debug!("report_region_errors: {} errors after preprocessing", errors.len());
+ debug!("report_region_errors: {} errors after preprocessing",
+ errors.len());
for error in errors {
+
debug!("report_region_errors: error = {:?}", error);
- match error.clone() {
- ConcreteFailure(origin, sub, sup) => {
- self.report_concrete_failure(origin, sub, sup).emit();
- }
+ // If ConcreteFailure does not have an anonymous region
+ if !self.report_named_anon_conflict(&error){
- GenericBoundFailure(kind, param_ty, sub) => {
- self.report_generic_bound_failure(kind, param_ty, sub);
- }
+ match error.clone() {
+
+ ConcreteFailure(origin, sub, sup) => {
+
+ self.report_concrete_failure(origin, sub, sup).emit();
+ }
- SubSupConflict(var_origin,
+ GenericBoundFailure(kind, param_ty, sub) => {
+ self.report_generic_bound_failure(kind, param_ty, sub);
+ }
+
+ SubSupConflict(var_origin,
sub_origin, sub_r,
sup_origin, sup_r) => {
- self.report_sub_sup_conflict(var_origin,
+ self.report_sub_sup_conflict(var_origin,
sub_origin, sub_r,
sup_origin, sup_r);
- }
+ }
+ }
}
}
}
--- /dev/null
+// Copyright 2012-2013 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.
+
+//! Error Reporting for Anonymous Region Lifetime Errors.
+use hir;
+use infer::InferCtxt;
+use ty::{self, Region};
+use infer::region_inference::RegionResolutionError::*;
+use infer::region_inference::RegionResolutionError;
+
+impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
+ // This method walks the Type of the function body arguments using
+ // `fold_regions()` function and returns the
+ // &hir::Arg of the function argument corresponding to the anonymous
+ // region and the Ty corresponding to the named region.
+ // Currently only the case where the function declaration consists of
+ // one named region and one anonymous region is handled.
+ // Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32`
+ // Here, the `y` and the `Ty` of `y` is returned after being substituted
+ // by that of the named region.
+ pub fn find_arg_with_anonymous_region(&self,
+ anon_region: Region<'tcx>,
+ named_region: Region<'tcx>)
+ -> Option<(&hir::Arg, ty::Ty<'tcx>)> {
+
+ match *anon_region {
+ ty::ReFree(ref free_region) => {
+
+ let id = free_region.scope;
+ let node_id = self.tcx.hir.as_local_node_id(id).unwrap();
+ let body_id = self.tcx.hir.maybe_body_owned_by(node_id).unwrap();
+
+ let body = self.tcx.hir.body(body_id);
+ body.arguments
+ .iter()
+ .filter_map(|arg| if let Some(tables) = self.in_progress_tables {
+ let ty = tables.borrow().node_id_to_type(arg.id);
+ let mut found_anon_region = false;
+ let new_arg_ty = self.tcx
+ .fold_regions(&ty,
+ &mut false,
+ |r, _| if *r == *anon_region {
+ found_anon_region = true;
+ named_region
+ } else {
+ r
+ });
+ if found_anon_region {
+ return Some((arg, new_arg_ty));
+ } else {
+ None
+ }
+ } else {
+ None
+ })
+ .next()
+ }
+ _ => None,
+ }
+
+ }
+
+ // 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(..)`
+ pub fn 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
+ };
+
+ let (named, (var, new_ty)) =
+ if self.is_named_region(sub) && self.is_anonymous_region(sup) {
+ (sub, self.find_arg_with_anonymous_region(sup, sub).unwrap())
+ } else if self.is_named_region(sup) && self.is_anonymous_region(sub) {
+ (sup, self.find_arg_with_anonymous_region(sub, sup).unwrap())
+ } else {
+ return false; // inapplicable
+ };
+
+ if let Some(simple_name) = var.pat.simple_name() {
+ struct_span_err!(self.tcx.sess,
+ var.pat.span,
+ E0611,
+ "explicit lifetime required in the type of `{}`",
+ simple_name)
+ .span_label(var.pat.span,
+ format!("consider changing the type of `{}` to `{}`",
+ simple_name,
+ new_ty))
+ .span_label(span, format!("lifetime `{}` required", named))
+ .emit();
+
+ } else {
+ struct_span_err!(self.tcx.sess,
+ var.pat.span,
+ E0611,
+ "explicit lifetime required in parameter type")
+ .span_label(var.pat.span,
+ format!("consider changing type to `{}`", new_ty))
+ .span_label(span, format!("lifetime `{}` required", named))
+ .emit();
+ }
+ return true;
+
+ }
+}
--- /dev/null
+// Copyright 2012-2013 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.
+
+//! Helper for error reporting code for named_anon_conflict
+
+use ty::{self, Region};
+use infer::InferCtxt;
+use hir::map as hir_map;
+
+impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
+ // This method returns whether the given Region is Named
+ pub fn is_named_region(&self, region: Region<'tcx>) -> bool {
+
+ match *region {
+ ty::ReFree(ref free_region) => {
+ match free_region.bound_region {
+ ty::BrNamed(..) => true,
+ _ => false,
+ }
+ }
+ _ => false,
+ }
+ }
+
+ // This method returns whether the given Region is Anonymous
+ pub fn is_anonymous_region(&self, region: Region<'tcx>) -> bool {
+
+ match *region {
+ ty::ReFree(ref free_region) => {
+ match free_region.bound_region {
+ ty::BrAnon(..) => {
+ let id = free_region.scope;
+ let node_id = self.tcx.hir.as_local_node_id(id).unwrap();
+ match self.tcx.hir.find(node_id) {
+ Some(hir_map::NodeItem(..)) |
+ Some(hir_map::NodeImplItem(..)) |
+ Some(hir_map::NodeTraitItem(..)) => { /* proceed ahead */ }
+ _ => return false, // inapplicable
+ // we target only top-level functions
+ }
+ return true;
+ }
+ _ => false,
+ }
+ }
+ _ => false,
+ }
+ }
+}
use syntax_pos::{self, Span, DUMMY_SP};
use util::nodemap::FxHashMap;
use arena::DroplessArena;
-
use self::combine::CombineFields;
use self::higher_ranked::HrMatchResult;
use self::region_inference::{RegionVarBindings, RegionSnapshot};
region_map,
free_regions);
let errors = self.region_vars.resolve_regions(®ion_rels);
+
if !self.is_tainted_by_errors() {
// As a heuristic, just skip reporting region errors
// altogether if other errors have been reported while
--- /dev/null
+// Copyright 2016 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.
+
+fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 {
+ if x > y { x } else { y }
+}
+
+fn main() { }
--- /dev/null
+error[E0611]: explicit lifetime required in the type of `x`
+ --> $DIR/ex1-return-one-existing-name-if-else-2.rs:11:12
+ |
+11 | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 {
+ | ^ consider changing the type of `x` to `&'a i32`
+12 | if x > y { x } else { y }
+ | - lifetime `'a` required
+
+error: aborting due to previous error(s)
+
--- /dev/null
+// Copyright 2016 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.
+
+fn foo<'a>((x, y): (&'a i32, &i32)) -> &'a i32 {
+ if x > y { x } else { y }
+}
+
+fn main () { }
--- /dev/null
+error[E0611]: explicit lifetime required in parameter type
+ --> $DIR/ex1-return-one-existing-name-if-else-3.rs:11:12
+ |
+11 | fn foo<'a>((x, y): (&'a i32, &i32)) -> &'a i32 {
+ | ^^^^^^ consider changing type to `(&'a i32, &'a i32)`
+12 | if x > y { x } else { y }
+ | - lifetime `'a` required
+
+error: aborting due to previous error(s)
+
--- /dev/null
+// Copyright 2016 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.
+
+fn invoke<'a, F>(x: &'a i32, f: F) -> &'a i32
+where F: FnOnce(&'a i32, &i32) -> &'a i32
+{
+ let y = 22;
+ f(x, &y)
+}
+
+fn foo<'a>(x: &'a i32) {
+ invoke(&x, |a, b| if a > b { a } else { b });
+}
+
+fn main() {
+}
+
--- /dev/null
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+ --> $DIR/ex1-return-one-existing-name-if-else-using-closure.rs:19:5
+ |
+19 | invoke(&x, |a, b| if a > b { a } else { b });
+ | ^^^^^^
+ |
+note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 19:16...
+ --> $DIR/ex1-return-one-existing-name-if-else-using-closure.rs:19:16
+ |
+19 | invoke(&x, |a, b| if a > b { a } else { b });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...so that reference does not outlive borrowed content
+ --> $DIR/ex1-return-one-existing-name-if-else-using-closure.rs:19:45
+ |
+19 | invoke(&x, |a, b| if a > b { a } else { b });
+ | ^
+note: but, the lifetime must be valid for the call at 19:5...
+ --> $DIR/ex1-return-one-existing-name-if-else-using-closure.rs:19:5
+ |
+19 | invoke(&x, |a, b| if a > b { a } else { b });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...so that argument is valid for the call
+ --> $DIR/ex1-return-one-existing-name-if-else-using-closure.rs:19:12
+ |
+19 | invoke(&x, |a, b| if a > b { a } else { b });
+ | ^^
+
+error: aborting due to previous error(s)
+
-error[E0312]: lifetime of reference outlives lifetime of borrowed content...
- --> $DIR/ex1-return-one-existing-name-if-else.rs:12:27
+error[E0611]: explicit lifetime required in the type of `y`
+ --> $DIR/ex1-return-one-existing-name-if-else.rs:11:24
|
+11 | fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 {
+ | ^ consider changing the type of `y` to `&'a i32`
12 | if x > y { x } else { y }
- | ^
- |
-note: ...the reference is valid for the lifetime 'a as defined on the function body at 11:1...
- --> $DIR/ex1-return-one-existing-name-if-else.rs:11:1
- |
-11 | / fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 {
-12 | | if x > y { x } else { y }
-13 | | }
- | |_^
-note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the function body at 11:1
- --> $DIR/ex1-return-one-existing-name-if-else.rs:11:1
- |
-11 | / fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 {
-12 | | if x > y { x } else { y }
-13 | | }
- | |_^
+ | - lifetime `'a` required
error: aborting due to previous error(s)
--- /dev/null
+// Copyright 2016 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.
+
+struct Ref<'a, T: 'a> {
+ data: &'a T
+}
+
+fn foo<'a>(x: Ref<i32>, y: &mut Vec<Ref<'a, i32>>) {
+ y.push(x);
+}
+
+fn main() { }
--- /dev/null
+error[E0611]: explicit lifetime required in the type of `x`
+ --> $DIR/ex2a-push-one-existing-name-2.rs:15:12
+ |
+15 | fn foo<'a>(x: Ref<i32>, y: &mut Vec<Ref<'a, i32>>) {
+ | ^ consider changing the type of `x` to `Ref<'a, i32>`
+16 | y.push(x);
+ | - lifetime `'a` required
+
+error: aborting due to previous error(s)
+
-error[E0308]: mismatched types
- --> $DIR/ex2a-push-one-existing-name.rs:16:12
+error[E0611]: explicit lifetime required in the type of `y`
+ --> $DIR/ex2a-push-one-existing-name.rs:15:39
|
+15 | fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<i32>) {
+ | ^ consider changing the type of `y` to `Ref<'a, i32>`
16 | x.push(y);
- | ^ lifetime mismatch
- |
- = note: expected type `Ref<'a, _>`
- found type `Ref<'_, _>`
-note: the anonymous lifetime #2 defined on the function body at 15:1...
- --> $DIR/ex2a-push-one-existing-name.rs:15:1
- |
-15 | / fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<i32>) {
-16 | | x.push(y);
-17 | | }
- | |_^
-note: ...does not necessarily outlive the lifetime 'a as defined on the function body at 15:1
- --> $DIR/ex2a-push-one-existing-name.rs:15:1
- |
-15 | / fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<i32>) {
-16 | | x.push(y);
-17 | | }
- | |_^
+ | - lifetime `'a` required
error: aborting due to previous error(s)