diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 5e36bd8ec2772..035640b9710e2 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1946,6 +1946,44 @@ Maybe you just misspelled the lint name or the lint doesn't exist anymore. Either way, try to update/remove it in order to fix the error. "##, +E0621: r##" +This error code indicates a mismatch between the function signature (i.e., +the parameter types and the return type) and the function body. Most of +the time, this indicates that the function signature needs to be changed to +match the body, but it may be that the body needs to be changed to match +the signature. + +Specifically, one or more of the parameters contain borrowed data that +needs to have a named lifetime in order for the body to type-check. Most of +the time, this is because the borrowed data is being returned from the +function, as in this example: + +```compile_fail,E0621 +fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 { // explicit lifetime required + // in the type of `y` + if x > y { x } else { y } +} +``` + +Here, the function is returning data borrowed from either x or y, but the +'a annotation indicates that it is returning data only from x. We can make +the signature match the body by changing the type of y to &'a i32, like so: + +``` +fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { + if x > y { x } else { y } +} +``` + +Alternatively, you could change the body not to return data from y: + +``` +fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 { + x +} +``` +"##, + } diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 11bac21bc429e..82bbb4a1bf515 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -72,9 +72,11 @@ 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; + impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn note_and_explain_region(self, @@ -255,34 +257,48 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { - pub fn report_region_errors(&self, - errors: &Vec>) { + + pub fn report_region_errors(&self, errors: &Vec>) { 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(); - } - GenericBoundFailure(kind, param_ty, sub) => { - self.report_generic_bound_failure(kind, param_ty, sub); - } + if !self.try_report_named_anon_conflict(&error){ + + match error.clone() { + // These errors could indicate all manner of different + // problems with many different solutions. Rather + // than generate a "one size fits all" error, what we + // attempt to do is go through a number of specific + // scenarios and try to find the best way to present + // the error. If all of these fails, we fall back to a rather + // general bit of code that displays the error information + 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); - } + } + } } } } diff --git a/src/librustc/infer/error_reporting/named_anon_conflict.rs b/src/librustc/infer/error_reporting/named_anon_conflict.rs new file mode 100644 index 0000000000000..ccbc5cdb862f9 --- /dev/null +++ b/src/librustc/infer/error_reporting/named_anon_conflict.rs @@ -0,0 +1,199 @@ +// 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 or the MIT license +// , 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; +use hir::map as hir_map; +use hir::def_id::DefId; + +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, we would return the hir::Arg for y, we return the type &'a + // i32, which is the type of y but with the anonymous region replaced + // with 'a, the corresponding bound region and is_first which is true if + // the hir::Arg is the first argument in the function declaration. + fn find_arg_with_anonymous_region + (&self, + anon_region: Region<'tcx>, + named_region: Region<'tcx>) + -> Option<(&hir::Arg, ty::Ty<'tcx>, ty::BoundRegion, bool)> { + + 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); + if let Some(tables) = self.in_progress_tables { + body.arguments + .iter() + .enumerate() + .filter_map(|(index, arg)| { + 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 { + let is_first = index == 0; + Some((arg, new_arg_ty, free_region.bound_region, is_first)) + } else { + None + } + }) + .next() + } else { + None + } + } + _ => 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 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 + }; + + // Determine whether the sub and sup consist of one named region ('a) + // and one anonymous (elided) region. If so, find the parameter arg + // where the anonymous region appears (there must always be one; we + // only introduced anonymous regions in parameters) as well as a + // version new_ty of its type where the anonymous region is replaced + // with the named one. + let (named, (arg, new_ty, br, is_first), scope_def_id) = + if sub.is_named_region() && self.is_suitable_anonymous_region(sup).is_some() { + (sub, + self.find_arg_with_anonymous_region(sup, sub).unwrap(), + self.is_suitable_anonymous_region(sup).unwrap()) + } else if sup.is_named_region() && self.is_suitable_anonymous_region(sub).is_some() { + (sup, + self.find_arg_with_anonymous_region(sub, sup).unwrap(), + self.is_suitable_anonymous_region(sub).unwrap()) + } else { + return false; // inapplicable + }; + + // Here, we check for the case where the anonymous region + // is in the return type. + // FIXME(#42703) - Need to handle certain cases here. + let ret_ty = self.tcx.type_of(scope_def_id); + match ret_ty.sty { + ty::TyFnDef(_, _) => { + let sig = ret_ty.fn_sig(self.tcx); + let late_bound_regions = self.tcx + .collect_referenced_late_bound_regions(&sig.output()); + if late_bound_regions.iter().any(|r| *r == br) { + return false; + } else { + } + } + _ => {} + } + + // Here we check for the case where anonymous region + // corresponds to self and if yes, we display E0312. + // FIXME(#42700) - Need to format self properly to + // enable E0621 for it. + if is_first && + self.tcx + .opt_associated_item(scope_def_id) + .map(|i| i.method_has_self_argument) + .unwrap_or(false) { + return false; + } + + let (error_var, span_label_var) = if let Some(simple_name) = arg.pat.simple_name() { + (format!("the type of `{}`", simple_name), format!("the type of `{}`", simple_name)) + } else { + (format!("parameter type"), format!("type")) + }; + + + struct_span_err!(self.tcx.sess, + span, + E0621, + "explicit lifetime required in {}", + error_var) + .span_label(arg.pat.span, + format!("consider changing {} to `{}`", span_label_var, new_ty)) + .span_label(span, format!("lifetime `{}` required", named)) + .emit(); + + return true; + + } + + // This method returns whether the given Region is Anonymous + // and returns the DefId corresponding to the region. + pub fn is_suitable_anonymous_region(&self, region: Region<'tcx>) -> Option { + + match *region { + ty::ReFree(ref free_region) => { + match free_region.bound_region { + ty::BrAnon(..) => { + let anonymous_region_binding_scope = free_region.scope; + let node_id = self.tcx + .hir + .as_local_node_id(anonymous_region_binding_scope) + .unwrap(); + match self.tcx.hir.find(node_id) { + Some(hir_map::NodeItem(..)) | + Some(hir_map::NodeTraitItem(..)) => { + // proceed ahead // + } + Some(hir_map::NodeImplItem(..)) => { + let container_id = self.tcx + .associated_item(anonymous_region_binding_scope) + .container + .id(); + if self.tcx.impl_trait_ref(container_id).is_some() { + // For now, we do not try to target impls of traits. This is + // because this message is going to suggest that the user + // change the fn signature, but they may not be free to do so, + // since the signature must match the trait. + // + // FIXME(#42706) -- in some cases, we could do better here. + return None; + } + } + _ => return None, // inapplicable + // we target only top-level functions + } + return Some(anonymous_region_binding_scope); + } + _ => None, + } + } + _ => None, + } + } +} diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 9500e4a36048d..5cb1606da6708 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -38,7 +38,6 @@ use errors::DiagnosticBuilder; 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}; @@ -1077,6 +1076,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { 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 diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index ed3312d88a384..452775e9e1337 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -990,6 +990,20 @@ impl RegionKind { flags } + + // This method returns whether the given Region is Named + pub fn is_named_region(&self) -> bool { + + match *self { + ty::ReFree(ref free_region) => { + match free_region.bound_region { + ty::BrNamed(..) => true, + _ => false, + } + } + _ => false, + } + } } /// Type utilities diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 54e7c398fe6a6..116576dc536ec 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -83,10 +83,11 @@ use std::cmp::max; use std::cmp::Ordering::Equal; use std::default::Default; use std::env; +use std::ffi::OsString; use std::io::{self, Read, Write}; use std::iter::repeat; use std::path::PathBuf; -use std::process; +use std::process::{self, Command, Stdio}; use std::rc::Rc; use std::str; use std::sync::{Arc, Mutex}; @@ -356,6 +357,8 @@ fn handle_explain(code: &str, match descriptions.find_description(&normalised) { Some(ref description) => { let mut is_in_code_block = false; + let mut text = String::new(); + // Slice off the leading newline and print. for line in description[1..].lines() { let indent_level = line.find(|c: char| !c.is_whitespace()) @@ -363,13 +366,16 @@ fn handle_explain(code: &str, let dedented_line = &line[indent_level..]; if dedented_line.starts_with("```") { is_in_code_block = !is_in_code_block; - println!("{}", &line[..(indent_level+3)]); + text.push_str(&line[..(indent_level+3)]); } else if is_in_code_block && dedented_line.starts_with("# ") { continue; } else { - println!("{}", line); + text.push_str(line); } + text.push('\n'); } + + show_content_with_pager(&text); } None => { early_error(output, &format!("no extended information for {}", code)); @@ -377,6 +383,39 @@ fn handle_explain(code: &str, } } +fn show_content_with_pager(content: &String) { + let pager_name = env::var_os("PAGER").unwrap_or_else(|| if cfg!(windows) { + OsString::from("more.com") + } else { + OsString::from("less") + }); + + let mut fallback_to_println = false; + + match Command::new(pager_name).stdin(Stdio::piped()).spawn() { + Ok(mut pager) => { + if let Some(mut pipe) = pager.stdin.as_mut() { + if pipe.write_all(content.as_bytes()).is_err() { + fallback_to_println = true; + } + } + + if pager.wait().is_err() { + fallback_to_println = true; + } + } + Err(_) => { + fallback_to_println = true; + } + } + + // If pager fails for whatever reason, we should still print the content + // to standard output + if fallback_to_println { + print!("{}", content); + } +} + impl<'a> CompilerCalls<'a> for RustcDefaultCalls { fn early_callback(&mut self, matches: &getopts::Matches, diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 3acfbd1d84403..67fd2845c7a7f 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -37,7 +37,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match it.node { hir::ForeignItemFn(..) => {} _ => { - struct_span_err!(tcx.sess, it.span, E0619, + struct_span_err!(tcx.sess, it.span, E0621, "intrinsic must be a function") .span_label(it.span, "expected a function") .emit(); diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 1b17faccc87f8..77d7b1ba8282b 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4726,6 +4726,26 @@ let x = &[1_usize, 2] as &[usize]; // ok! ``` "##, +E0621: r##" +An intrinsic was declared without being a function. + +Erroneous code example: + +```compile_fail,E0621 +#![feature(intrinsics)] +extern "rust-intrinsic" { + pub static breakpoint : unsafe extern "rust-intrinsic" fn(); + // error: intrinsic must be a function +} + +fn main() { unsafe { breakpoint(); } } +``` + +An intrinsic is a function available for use in a given programming language +whose implementation is handled specially by the compiler. In order to fix this +error, just declare a function. +"##, + } register_diagnostics! { diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 5b8c0c339900d..88994b284c90d 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -653,15 +653,29 @@ impl OpenOptions { /// # Errors /// /// This function will return an error under a number of different - /// circumstances, to include but not limited to: - /// - /// * Opening a file that does not exist without setting `create` or - /// `create_new`. - /// * Attempting to open a file with access that the user lacks - /// permissions for - /// * Filesystem-level errors (full disk, etc) - /// * Invalid combinations of open options (truncate without write access, - /// no access mode set, etc) + /// circumstances. Some of these error conditions are listed here, together + /// with their [`ErrorKind`]. The mapping to [`ErrorKind`]s is not part of + /// the compatiblity contract of the function, especially the `Other` kind + /// might change to more specific kinds in the future. + /// + /// * [`NotFound`]: The specified file does not exist and neither `create` + /// or `create_new` is set. + /// * [`NotFound`]: One of the directory components of the file path does + /// not exist. + /// * [`PermissionDenied`]: The user lacks permission to get the specified + /// access rights for the file. + /// * [`PermissionDenied`]: The user lacks permission to open one of the + /// directory components of the specified path. + /// * [`AlreadyExists`]: `create_new` was specified and the file already + /// exists. + /// * [`InvalidInput`]: Invalid combinations of open options (truncate + /// without write access, no access mode set, etc.). + /// * [`Other`]: One of the directory components of the specified file path + /// was not, in fact, a directory. + /// * [`Other`]: Filesystem-level errors: full disk, write permission + /// requested on a read-only file system, exceeded disk quota, too many + /// open files, too long filename, too many symbolic links in the + /// specified path (Unix-like systems only), etc. /// /// # Examples /// @@ -670,6 +684,13 @@ impl OpenOptions { /// /// let file = OpenOptions::new().open("foo.txt"); /// ``` + /// + /// [`ErrorKind`]: ../io/enum.ErrorKind.html + /// [`AlreadyExists`]: ../io/enum.ErrorKind.html#variant.AlreadyExists + /// [`InvalidInput`]: ../io/enum.ErrorKind.html#variant.InvalidInput + /// [`NotFound`]: ../io/enum.ErrorKind.html#variant.NotFound + /// [`Other`]: ../io/enum.ErrorKind.html#variant.Other + /// [`PermissionDenied`]: ../io/enum.ErrorKind.html#variant.PermissionDenied #[stable(feature = "rust1", since = "1.0.0")] pub fn open>(&self, path: P) -> io::Result { self._open(path.as_ref()) diff --git a/src/test/compile-fail/E0619.rs b/src/test/compile-fail/E0619.rs index 8ef90d8993192..a5a5ff7218dcf 100644 --- a/src/test/compile-fail/E0619.rs +++ b/src/test/compile-fail/E0619.rs @@ -16,3 +16,4 @@ fn main() { _ => {} } } + diff --git a/src/test/compile-fail/E0621-does-not-trigger-for-closures.rs b/src/test/compile-fail/E0621-does-not-trigger-for-closures.rs new file mode 100644 index 0000000000000..980461bedae55 --- /dev/null +++ b/src/test/compile-fail/E0621-does-not-trigger-for-closures.rs @@ -0,0 +1,28 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we give the generic E0495 when one of the free regions is +// bound in a closure (rather than suggesting a change to the signature +// of the closure, which is not specified in `foo` but rather in `invoke`). + +// FIXME - This might be better as a UI test, but the finer details +// of the error seem to vary on different machines. +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 }); //~ ERROR E0495 +} + +fn main() {} diff --git a/src/test/compile-fail/invalid-intrinsic.rs b/src/test/compile-fail/E0621.rs similarity index 92% rename from src/test/compile-fail/invalid-intrinsic.rs rename to src/test/compile-fail/E0621.rs index c42d78c323e3c..63fb159c5d902 100644 --- a/src/test/compile-fail/invalid-intrinsic.rs +++ b/src/test/compile-fail/E0621.rs @@ -11,6 +11,6 @@ #![feature(intrinsics)] extern "rust-intrinsic" { pub static breakpoint : unsafe extern "rust-intrinsic" fn(); - //~^ ERROR intrinsic must be a function + //~^ ERROR intrinsic must be a function [E0621] } fn main() { unsafe { breakpoint(); } } diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-2.rs b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-2.rs new file mode 100644 index 0000000000000..a1716c4e79792 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-2.rs @@ -0,0 +1,15 @@ +// 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 or the MIT license +// , 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() { } diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-2.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-2.stderr new file mode 100644 index 0000000000000..4d8c5e039af41 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-2.stderr @@ -0,0 +1,10 @@ +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/ex1-return-one-existing-name-if-else-2.rs:12:16 + | +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) + diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-3.rs b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-3.rs new file mode 100644 index 0000000000000..7bd32d8761705 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-3.rs @@ -0,0 +1,15 @@ +// 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 or the MIT license +// , 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 () { } diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-3.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-3.stderr new file mode 100644 index 0000000000000..07b276601f47c --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-3.stderr @@ -0,0 +1,10 @@ +error[E0621]: explicit lifetime required in parameter type + --> $DIR/ex1-return-one-existing-name-if-else-3.rs:12:27 + | +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) + diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.rs b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.rs new file mode 100644 index 0000000000000..8849f7084b3cd --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.rs @@ -0,0 +1,18 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo { + +fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 { + if x > y { x } else { y } + } +} + +fn main() { } diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr new file mode 100644 index 0000000000000..2adf0cd762c59 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr @@ -0,0 +1,10 @@ +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/ex1-return-one-existing-name-if-else-using-impl-2.rs:14:15 + | +13 | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 { + | - consider changing the type of `x` to `&'a i32` +14 | if x > y { x } else { y } + | ^ lifetime `'a` required + +error: aborting due to previous error(s) + diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.rs b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.rs new file mode 100644 index 0000000000000..362290ff3fa7d --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.rs @@ -0,0 +1,24 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo { + field: i32 +} + +impl Foo { + fn foo<'a>(&'a self, x: &i32) -> &i32 { + + if true { &self.field } else { x } + + } + +} + +fn main() { } diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr new file mode 100644 index 0000000000000..15825017d15c3 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr @@ -0,0 +1,11 @@ +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:18:36 + | +16 | fn foo<'a>(&'a self, x: &i32) -> &i32 { + | - consider changing the type of `x` to `&'a i32` +17 | +18 | if true { &self.field } else { x } + | ^ lifetime `'a` required + +error: aborting due to previous error(s) + diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.rs b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.rs new file mode 100644 index 0000000000000..36d956a39966f --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.rs @@ -0,0 +1,27 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo { + + fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32; + +} + +impl Foo for () { + + fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 { + + if x > y { x } else { y } + + } + +} + +fn main() {} diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.stderr new file mode 100644 index 0000000000000..15ecca618052e --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.stderr @@ -0,0 +1,27 @@ +error[E0312]: lifetime of reference outlives lifetime of borrowed content... + --> $DIR/ex1-return-one-existing-name-if-else-using-impl.rs:21:20 + | +21 | if x > y { x } else { y } + | ^ + | +note: ...the reference is valid for the lifetime 'a as defined on the method body at 19:5... + --> $DIR/ex1-return-one-existing-name-if-else-using-impl.rs:19:5 + | +19 | / fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 { +20 | | +21 | | if x > y { x } else { y } +22 | | +23 | | } + | |_____^ +note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the method body at 19:5 + --> $DIR/ex1-return-one-existing-name-if-else-using-impl.rs:19:5 + | +19 | / fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 { +20 | | +21 | | if x > y { x } else { y } +22 | | +23 | | } + | |_____^ + +error: aborting due to previous error(s) + diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.stderr index 0ab24b0b3e6c4..892a6dcd1e934 100644 --- a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.stderr +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.stderr @@ -1,23 +1,10 @@ -error[E0312]: lifetime of reference outlives lifetime of borrowed content... +error[E0621]: explicit lifetime required in the type of `y` --> $DIR/ex1-return-one-existing-name-if-else.rs:12:27 | +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) diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.rs b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.rs new file mode 100644 index 0000000000000..96b733be9b4eb --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.rs @@ -0,0 +1,24 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo { + field: i32 +} + +impl Foo { + fn foo<'a>(&self, x: &'a i32) -> &i32 { + + x + + } + +} + +fn main() { } diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.stderr new file mode 100644 index 0000000000000..471b3401827d8 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.stderr @@ -0,0 +1,27 @@ +error[E0312]: lifetime of reference outlives lifetime of borrowed content... + --> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:18:5 + | +18 | x + | ^ + | +note: ...the reference is valid for the anonymous lifetime #1 defined on the method body at 16:3... + --> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:16:3 + | +16 | / fn foo<'a>(&self, x: &'a i32) -> &i32 { +17 | | +18 | | x +19 | | +20 | | } + | |___^ +note: ...but the borrowed content is only valid for the lifetime 'a as defined on the method body at 16:3 + --> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:16:3 + | +16 | / fn foo<'a>(&self, x: &'a i32) -> &i32 { +17 | | +18 | | x +19 | | +20 | | } + | |___^ + +error: aborting due to previous error(s) + diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-self-is-anon.rs b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-self-is-anon.rs new file mode 100644 index 0000000000000..a8ce60c47b6f5 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-self-is-anon.rs @@ -0,0 +1,23 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo { + field: i32, +} + +impl Foo { + fn foo<'a>(&self, x: &'a Foo) -> &'a Foo { + + if true { x } else { self } + + } +} + +fn main() {} diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-self-is-anon.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-self-is-anon.stderr new file mode 100644 index 0000000000000..46fc43eaf5756 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-self-is-anon.stderr @@ -0,0 +1,27 @@ +error[E0312]: lifetime of reference outlives lifetime of borrowed content... + --> $DIR/ex1-return-one-existing-name-self-is-anon.rs:18:30 + | +18 | if true { x } else { self } + | ^^^^ + | +note: ...the reference is valid for the lifetime 'a as defined on the method body at 16:5... + --> $DIR/ex1-return-one-existing-name-self-is-anon.rs:16:5 + | +16 | / fn foo<'a>(&self, x: &'a Foo) -> &'a Foo { +17 | | +18 | | if true { x } else { self } +19 | | +20 | | } + | |_____^ +note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the method body at 16:5 + --> $DIR/ex1-return-one-existing-name-self-is-anon.rs:16:5 + | +16 | / fn foo<'a>(&self, x: &'a Foo) -> &'a Foo { +17 | | +18 | | if true { x } else { self } +19 | | +20 | | } + | |_____^ + +error: aborting due to previous error(s) + diff --git a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-2.rs b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-2.rs new file mode 100644 index 0000000000000..dd34e1aa6d9d2 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-2.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , 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, y: &mut Vec>) { + y.push(x); +} + +fn main() { } diff --git a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-2.stderr b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-2.stderr new file mode 100644 index 0000000000000..ea696c51d6218 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-2.stderr @@ -0,0 +1,10 @@ +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/ex2a-push-one-existing-name-2.rs:16:12 + | +15 | fn foo<'a>(x: Ref, y: &mut Vec>) { + | - consider changing the type of `x` to `Ref<'a, i32>` +16 | y.push(x); + | ^ lifetime `'a` required + +error: aborting due to previous error(s) + diff --git a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr index 7d0947b364e03..1630ae32ba6bf 100644 --- a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr +++ b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr @@ -1,25 +1,10 @@ -error[E0308]: mismatched types +error[E0621]: explicit lifetime required in the type of `y` --> $DIR/ex2a-push-one-existing-name.rs:16:12 | +15 | fn foo<'a>(x: &mut Vec>, y: Ref) { + | - 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>, y: Ref) { -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>, y: Ref) { -16 | | x.push(y); -17 | | } - | |_^ + | ^ lifetime `'a` required error: aborting due to previous error(s)