diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 54c507304f9f1..70376c120fc0a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -301,12 +301,12 @@ It's absolutely fine to have multiple build directories with different [pull-requests]: #pull-requests Pull requests are the primary mechanism we use to change Rust. GitHub itself -has some [great documentation][pull-requests] on using the Pull Request feature. +has some [great documentation][about-pull-requests] on using the Pull Request feature. We use the "fork and pull" model [described here][development-models], where contributors push changes to their personal fork and create pull requests to bring those changes into the source repository. -[pull-requests]: https://help.github.com/articles/about-pull-requests/ +[about-pull-requests]: https://help.github.com/articles/about-pull-requests/ [development-models]: https://help.github.com/articles/about-collaborative-development-models/ Please make pull requests against the `master` branch. diff --git a/src/doc/index.md b/src/doc/index.md index 3784cc3c4b497..3add2774105e0 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -28,6 +28,7 @@ Rust provides a number of book-length sets of documentation, collectively nicknamed 'The Rust Bookshelf.' * [The Rust Programming Language][book] teaches you how to program in Rust. +* [Rust By Example][rbe] teaches you how to program in Rust using editable examples. * [The Cargo Book][cargo-book] is a guide to Cargo, Rust's build tool and dependency manager. * [The Unstable Book][unstable-book] has documentation for unstable features. * [The Rustonomicon][nomicon] is your guidebook to the dark arts of unsafe Rust. @@ -51,6 +52,7 @@ before this policy was put into place. That work is being tracked [refchecklist]: https://github.com/rust-lang-nursery/reference/issues/9 [err]: error-index.html [book]: book/index.html +[rbe]: rust-by-example/index.html [nomicon]: nomicon/index.html [unstable-book]: unstable-book/index.html [rustdoc-book]: rustdoc/index.html diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 15181dab8531c..b8fe28d0f0d71 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -881,6 +881,35 @@ impl Option { } } +impl Option> { + /// Transposes an `Option` of a `Result` into a `Result` of an `Option`. + /// + /// `None` will be mapped to `Ok(None)`. + /// `Some(Ok(_))` and `Some(Err(_))` will be mapped to `Ok(Some(_))` and `Err(_)`. + /// + /// # Examples + /// + /// ``` + /// #![feature(transpose_result)] + /// + /// #[derive(Debug, Eq, PartialEq)] + /// struct SomeErr; + /// + /// let x: Result, SomeErr> = Ok(Some(5)); + /// let y: Option> = Some(Ok(5)); + /// assert_eq!(x, y.transpose()); + /// ``` + #[inline] + #[unstable(feature = "transpose_result", issue = "47338")] + pub fn transpose(self) -> Result, E> { + match self { + Some(Ok(x)) => Ok(Some(x)), + Some(Err(e)) => Err(e), + None => Ok(None), + } + } +} + // This is a separate function to reduce the code size of .expect() itself. #[inline(never)] #[cold] diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 2ace3d2aee873..3801db94e15d5 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -909,6 +909,35 @@ impl Result { } } +impl Result, E> { + /// Transposes a `Result` of an `Option` into an `Option` of a `Result`. + /// + /// `Ok(None)` will be mapped to `None`. + /// `Ok(Some(_))` and `Err(_)` will be mapped to `Some(Ok(_))` and `Some(Err(_))`. + /// + /// # Examples + /// + /// ``` + /// #![feature(transpose_result)] + /// + /// #[derive(Debug, Eq, PartialEq)] + /// struct SomeErr; + /// + /// let x: Result, SomeErr> = Ok(Some(5)); + /// let y: Option> = Some(Ok(5)); + /// assert_eq!(x.transpose(), y); + /// ``` + #[inline] + #[unstable(feature = "transpose_result", issue = "47338")] + pub fn transpose(self) -> Option> { + match self { + Ok(Some(x)) => Some(Ok(x)), + Ok(None) => None, + Err(e) => Some(Err(e)), + } + } +} + // This is a separate function to reduce the code size of the methods #[inline(never)] #[cold] diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 1aca687af2bf3..e649f1b49df76 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -717,93 +717,40 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.hir.span_if_local(did) }).map(|sp| self.tcx.sess.codemap().def_span(sp)); // the sp could be an fn def - let found_ty_count = - match found_trait_ref.skip_binder().substs.type_at(1).sty { - ty::TyTuple(ref tys, _) => tys.len(), - _ => 1, - }; - let (expected_tys, expected_ty_count) = - match expected_trait_ref.skip_binder().substs.type_at(1).sty { - ty::TyTuple(ref tys, _) => - (tys.iter().map(|t| &t.sty).collect(), tys.len()), - ref sty => (vec![sty], 1), - }; - if found_ty_count == expected_ty_count { + let found = match found_trait_ref.skip_binder().substs.type_at(1).sty { + ty::TyTuple(ref tys, _) => tys.iter() + .map(|_| ArgKind::empty()).collect::>(), + _ => vec![ArgKind::empty()], + }; + let expected = match expected_trait_ref.skip_binder().substs.type_at(1).sty { + ty::TyTuple(ref tys, _) => tys.iter() + .map(|t| match t.sty { + ty::TypeVariants::TyTuple(ref tys, _) => ArgKind::Tuple( + span, + tys.iter() + .map(|ty| ("_".to_owned(), format!("{}", ty.sty))) + .collect::>() + ), + _ => ArgKind::Arg("_".to_owned(), format!("{}", t.sty)), + }).collect(), + ref sty => vec![ArgKind::Arg("_".to_owned(), format!("{}", sty))], + }; + if found.len()== expected.len() { self.report_closure_arg_mismatch(span, found_span, found_trait_ref, expected_trait_ref) } else { - let expected_tuple = if expected_ty_count == 1 { - expected_tys.first().and_then(|t| { - if let &&ty::TyTuple(ref tuptys, _) = t { - Some(tuptys.len()) - } else { - None - } - }) - } else { - None - }; - - // FIXME(#44150): Expand this to "N args expected but a N-tuple found." - // Type of the 1st expected argument is somehow provided as type of a - // found one in that case. - // - // ``` - // [1i32, 2, 3].sort_by(|(a, b)| ..) - // // ^^^^^^^ -------- - // // expected_trait_ref: std::ops::FnMut<(&i32, &i32)> - // // found_trait_ref: std::ops::FnMut<(&i32,)> - // ``` - - let (closure_span, closure_args) = found_did + let (closure_span, found) = found_did .and_then(|did| self.tcx.hir.get_if_local(did)) - .and_then(|node| { - if let hir::map::NodeExpr( - &hir::Expr { - node: hir::ExprClosure(_, ref decl, id, span, _), - .. - }) = node - { - let ty_snips = decl.inputs.iter() - .map(|ty| { - self.tcx.sess.codemap().span_to_snippet(ty.span).ok() - .and_then(|snip| { - // filter out dummy spans - if snip == "," || snip == "|" { - None - } else { - Some(snip) - } - }) - }) - .collect::>>(); - - let body = self.tcx.hir.body(id); - let pat_snips = body.arguments.iter() - .map(|arg| - self.tcx.sess.codemap().span_to_snippet(arg.pat.span).ok()) - .collect::>>(); - - Some((span, pat_snips, ty_snips)) - } else { - None - } - }) - .map(|(span, pat, ty)| (Some(span), Some((pat, ty)))) - .unwrap_or((None, None)); - let closure_args = closure_args.and_then(|(pat, ty)| Some((pat?, ty))); - - self.report_arg_count_mismatch( - span, - closure_span.or(found_span), - expected_ty_count, - expected_tuple, - found_ty_count, - closure_args, - found_trait_ty.is_closure() - ) + .map(|node| self.get_fn_like_arguments(node)) + .unwrap_or((found_span.unwrap(), found)); + + self.report_arg_count_mismatch(span, + closure_span, + expected, + found, + found_trait_ty.is_closure()) } } @@ -845,94 +792,135 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } + fn get_fn_like_arguments(&self, node: hir::map::Node) -> (Span, Vec) { + if let hir::map::NodeExpr(&hir::Expr { + node: hir::ExprClosure(_, ref _decl, id, span, _), + .. + }) = node { + (self.tcx.sess.codemap().def_span(span), self.tcx.hir.body(id).arguments.iter() + .map(|arg| { + if let hir::Pat { + node: hir::PatKind::Tuple(args, _), + span, + .. + } = arg.pat.clone().into_inner() { + ArgKind::Tuple( + span, + args.iter().map(|pat| { + let snippet = self.tcx.sess.codemap() + .span_to_snippet(pat.span).unwrap(); + (snippet, "_".to_owned()) + }).collect::>(), + ) + } else { + let name = self.tcx.sess.codemap().span_to_snippet(arg.pat.span).unwrap(); + ArgKind::Arg(name, "_".to_owned()) + } + }) + .collect::>()) + } else if let hir::map::NodeItem(&hir::Item { + span, + node: hir::ItemFn(ref decl, ..), + .. + }) = node { + (self.tcx.sess.codemap().def_span(span), decl.inputs.iter() + .map(|arg| match arg.clone().into_inner().node { + hir::TyTup(ref tys) => ArgKind::Tuple( + arg.span, + tys.iter() + .map(|_| ("_".to_owned(), "_".to_owned())) + .collect::>(), + ), + _ => ArgKind::Arg("_".to_owned(), "_".to_owned()) + }).collect::>()) + } else { + panic!("non-FnLike node found: {:?}", node); + } + } + fn report_arg_count_mismatch( &self, span: Span, - found_span: Option, - expected: usize, - expected_tuple: Option, - found: usize, - closure_args: Option<(Vec, Vec>)>, - is_closure: bool + found_span: Span, + expected_args: Vec, + found_args: Vec, + is_closure: bool, ) -> DiagnosticBuilder<'tcx> { - use std::borrow::Cow; - let kind = if is_closure { "closure" } else { "function" }; - let args_str = |n, distinct| format!( - "{} {}argument{}", - n, - if distinct && n >= 2 { "distinct " } else { "" }, - if n == 1 { "" } else { "s" }, - ); - - let expected_str = if let Some(n) = expected_tuple { - assert!(expected == 1); - if closure_args.as_ref().map(|&(ref pats, _)| pats.len()) == Some(n) { - Cow::from("a single tuple as argument") - } else { - // be verbose when numbers differ - Cow::from(format!("a single {}-tuple as argument", n)) + let args_str = |arguments: &Vec, other: &Vec| { + let arg_length = arguments.len(); + let distinct = match &other[..] { + &[ArgKind::Tuple(..)] => true, + _ => false, + }; + match (arg_length, arguments.get(0)) { + (1, Some(&ArgKind::Tuple(_, ref fields))) => { + format!("a single {}-tuple as argument", fields.len()) + } + _ => format!("{} {}argument{}", + arg_length, + if distinct && arg_length > 1 { "distinct " } else { "" }, + if arg_length == 1 { "" } else { "s" }), } - } else { - Cow::from(args_str(expected, false)) - }; - - let found_str = if expected_tuple.is_some() { - args_str(found, true) - } else { - args_str(found, false) }; + let expected_str = args_str(&expected_args, &found_args); + let found_str = args_str(&found_args, &expected_args); - let mut err = struct_span_err!(self.tcx.sess, span, E0593, + let mut err = struct_span_err!( + self.tcx.sess, + span, + E0593, "{} is expected to take {}, but it takes {}", kind, expected_str, found_str, ); - err.span_label( - span, - format!( - "expected {} that takes {}", - kind, - expected_str, - ) - ); - - if let Some(span) = found_span { - if let (Some(expected_tuple), Some((pats, tys))) = (expected_tuple, closure_args) { - if expected_tuple != found || pats.len() != found { - err.span_label(span, format!("takes {}", found_str)); - } else { - let sugg = format!( - "|({}){}|", - pats.join(", "), - - // add type annotations if available - if tys.iter().any(|ty| ty.is_some()) { - Cow::from(format!( - ": ({})", - tys.into_iter().map(|ty| if let Some(ty) = ty { - ty - } else { - "_".to_string() - }).collect::>().join(", ") - )) - } else { - Cow::from("") - }, - ); - - err.span_suggestion( - span, - "consider changing the closure to accept a tuple", - sugg - ); - } - } else { - err.span_label(span, format!("takes {}", found_str)); + err.span_label(span, format!( "expected {} that takes {}", kind, expected_str)); + err.span_label(found_span, format!("takes {}", found_str)); + + if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] { + if fields.len() == expected_args.len() { + let sugg = fields.iter() + .map(|(name, _)| name.to_owned()) + .collect::>().join(", "); + err.span_suggestion(found_span, + "change the closure to take multiple arguments instead of \ + a single tuple", + format!("|{}|", sugg)); + } + } + if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] { + if fields.len() == found_args.len() && is_closure { + let sugg = format!( + "|({}){}|", + found_args.iter() + .map(|arg| match arg { + ArgKind::Arg(name, _) => name.to_owned(), + _ => "_".to_owned(), + }) + .collect::>() + .join(", "), + // add type annotations if available + if found_args.iter().any(|arg| match arg { + ArgKind::Arg(_, ty) => ty != "_", + _ => false, + }) { + format!(": ({})", + fields.iter() + .map(|(_, ty)| ty.to_owned()) + .collect::>() + .join(", ")) + } else { + "".to_owned() + }, + ); + err.span_suggestion(found_span, + "change the closure to accept a tuple instead of individual \ + arguments", + sugg); } } @@ -1331,3 +1319,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { suggested_limit)); } } + +enum ArgKind { + Arg(String, String), + Tuple(Span, Vec<(String, String)>), +} + +impl ArgKind { + fn empty() -> ArgKind { + ArgKind::Arg("_".to_owned(), "_".to_owned()) + } +} diff --git a/src/librustc_back/target/aarch64_unknown_cloudabi.rs b/src/librustc_back/target/aarch64_unknown_cloudabi.rs index d5e8194c3f79b..59c82e06a679c 100644 --- a/src/librustc_back/target/aarch64_unknown_cloudabi.rs +++ b/src/librustc_back/target/aarch64_unknown_cloudabi.rs @@ -15,6 +15,7 @@ pub fn target() -> TargetResult { let mut base = super::cloudabi_base::opts(); base.max_atomic_width = Some(128); base.abi_blacklist = super::arm_base::abi_blacklist(); + base.linker = "aarch64-unknown-cloudabi-cc".to_string(); Ok(Target { llvm_target: "aarch64-unknown-cloudabi".to_string(), diff --git a/src/librustc_back/target/armv7_unknown_cloudabi_eabihf.rs b/src/librustc_back/target/armv7_unknown_cloudabi_eabihf.rs index 4dad8e1713b43..faa2c4fdceb9b 100644 --- a/src/librustc_back/target/armv7_unknown_cloudabi_eabihf.rs +++ b/src/librustc_back/target/armv7_unknown_cloudabi_eabihf.rs @@ -17,6 +17,7 @@ pub fn target() -> TargetResult { base.max_atomic_width = Some(64); base.features = "+v7,+vfp3,+neon".to_string(); base.abi_blacklist = super::arm_base::abi_blacklist(); + base.linker = "armv7-unknown-cloudabi-eabihf-cc".to_string(); Ok(Target { llvm_target: "armv7-unknown-cloudabi-eabihf".to_string(), diff --git a/src/librustc_back/target/i686_unknown_cloudabi.rs b/src/librustc_back/target/i686_unknown_cloudabi.rs index b9aa6176d8768..e244f443d3e3a 100644 --- a/src/librustc_back/target/i686_unknown_cloudabi.rs +++ b/src/librustc_back/target/i686_unknown_cloudabi.rs @@ -15,6 +15,7 @@ pub fn target() -> TargetResult { let mut base = super::cloudabi_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); + base.linker = "i686-unknown-cloudabi-cc".to_string(); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); base.stack_probes = true; diff --git a/src/librustc_back/target/x86_64_unknown_cloudabi.rs b/src/librustc_back/target/x86_64_unknown_cloudabi.rs index f9a563174d4a9..1ce3c6444f1ea 100644 --- a/src/librustc_back/target/x86_64_unknown_cloudabi.rs +++ b/src/librustc_back/target/x86_64_unknown_cloudabi.rs @@ -15,6 +15,7 @@ pub fn target() -> TargetResult { let mut base = super::cloudabi_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); + base.linker = "x86_64-unknown-cloudabi-cc".to_string(); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); base.stack_probes = true; diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 61de5f4bc4c45..3a18c6b8a809e 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -94,20 +94,22 @@ r##"

Keyboard Shortcuts

-
?
+
?
Show this help dialog
-
S
+
S
Focus the search field
-
+
Move up in search results
-
+
Move down in search results
-
+
Switch tab
-
+
Go to active search result
-
+ / -
-
Collapse/expand all sections
+
+
+
Expand all sections
+
-
+
Collapse all sections
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index b41874a56b8e7..34b04de86735e 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -585,18 +585,13 @@ body.blur > :not(#help) { flex: 0 0 auto; box-shadow: 0 0 6px rgba(0,0,0,.2); width: 550px; - height: 354px; + height: auto; border: 1px solid; } #help dt { float: left; - border-radius: 4px; - border: 1px solid; - width: 23px; - text-align: center; clear: left; display: block; - margin-top: -1px; } #help dd { margin: 5px 35px; } #help .infos { padding-left: 0; } @@ -1134,3 +1129,14 @@ h3.important { left: -42px; margin-top: 2px; } + +kbd { + display: inline-block; + padding: 3px 5px; + font: 15px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; + line-height: 10px; + vertical-align: middle; + border: solid 1px; + border-radius: 3px; + box-shadow: inset 0 -1px 0; +} diff --git a/src/librustdoc/html/static/styles/main.css b/src/librustdoc/html/static/styles/main.css index c79413c0852ce..bd74056242442 100644 --- a/src/librustdoc/html/static/styles/main.css +++ b/src/librustdoc/html/static/styles/main.css @@ -194,11 +194,6 @@ a.test-arrow { border-color: #bfbfbf; } -#help dt { - border-color: #bfbfbf; - background: #fff; -} - .since { color: grey; } @@ -348,3 +343,11 @@ pre.ignore:hover, .information:hover + pre.ignore { border-bottom-color: #e0e0e0; } } + +kbd { + color: #444d56; + background-color: #fafbfc; + border-color: #d1d5da; + border-bottom-color: #c6cbd1; + box-shadow-color: #c6cbd1; +} diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index b8a6a66eaa65d..e9a150f34a51e 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -64,11 +64,11 @@ //! * You want a map, with no extra functionality. //! //! ### Use a `BTreeMap` when: +//! * You want a map sorted by its keys. +//! * You want to be able to get a range of entries on-demand. //! * You're interested in what the smallest or largest key-value pair is. //! * You want to find the largest or smallest key that is smaller or larger //! than something. -//! * You want to be able to get all of the entries in order on-demand. -//! * You want a map sorted by its keys. //! //! ### Use the `Set` variant of any of these `Map`s when: //! * You just want to remember which keys you've seen. diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 1ca7e66ed9ca9..fa430939f058c 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -12,7 +12,9 @@ use fmt; use hash; use io; use mem; -use net::{lookup_host, ntoh, hton, IpAddr, Ipv4Addr, Ipv6Addr}; +use net::{ntoh, hton, IpAddr, Ipv4Addr, Ipv6Addr}; +#[allow(deprecated)] +use net::lookup_host; use option; use sys::net::netc as c; use sys_common::{FromInner, AsInner, IntoInner}; @@ -845,6 +847,7 @@ impl ToSocketAddrs for (Ipv6Addr, u16) { } } +#[allow(deprecated)] fn resolve_socket_addr(s: &str, p: u16) -> io::Result> { let ips = lookup_host(s)?; let v: Vec<_> = ips.map(|mut a| { a.set_port(p); a }).collect(); diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index 9fcb93e2032b3..eb0e2e13b4cd2 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -134,12 +134,15 @@ fn each_addr(addr: A, mut f: F) -> io::Result iterator and returning socket \ addresses", issue = "27705")] +#[rustc_deprecated(since = "1.25", reason = "Use the ToSocketAddrs trait instead")] pub struct LookupHost(net_imp::LookupHost); #[unstable(feature = "lookup_host", reason = "unsure about the returned \ iterator and returning socket \ addresses", issue = "27705")] +#[rustc_deprecated(since = "1.25", reason = "Use the ToSocketAddrs trait instead")] +#[allow(deprecated)] impl Iterator for LookupHost { type Item = SocketAddr; fn next(&mut self) -> Option { self.0.next() } @@ -149,6 +152,8 @@ impl Iterator for LookupHost { iterator and returning socket \ addresses", issue = "27705")] +#[rustc_deprecated(since = "1.25", reason = "Use the ToSocketAddrs trait instead")] +#[allow(deprecated)] impl fmt::Debug for LookupHost { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("LookupHost { .. }") @@ -181,6 +186,8 @@ impl fmt::Debug for LookupHost { iterator and returning socket \ addresses", issue = "27705")] +#[rustc_deprecated(since = "1.25", reason = "Use the ToSocketAddrs trait instead")] +#[allow(deprecated)] pub fn lookup_host(host: &str) -> io::Result { net_imp::lookup_host(host).map(LookupHost) } diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 7631a9a44bbe7..ed102c2949ede 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1869,7 +1869,11 @@ impl Path { /// /// let path = Path::new("/test/haha/foo.txt"); /// + /// assert_eq!(path.strip_prefix("/"), Ok(Path::new("test/haha/foo.txt"))); /// assert_eq!(path.strip_prefix("/test"), Ok(Path::new("haha/foo.txt"))); + /// assert_eq!(path.strip_prefix("/test/"), Ok(Path::new("haha/foo.txt"))); + /// assert_eq!(path.strip_prefix("/test/haha/foo.txt"), Ok(Path::new(""))); + /// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Path::new(""))); /// assert_eq!(path.strip_prefix("test").is_ok(), false); /// assert_eq!(path.strip_prefix("/haha").is_ok(), false); /// ``` @@ -1900,6 +1904,9 @@ impl Path { /// let path = Path::new("/etc/passwd"); /// /// assert!(path.starts_with("/etc")); + /// assert!(path.starts_with("/etc/")); + /// assert!(path.starts_with("/etc/passwd")); + /// assert!(path.starts_with("/etc/passwd/")); /// /// assert!(!path.starts_with("/e")); /// ``` diff --git a/src/test/run-pass/result-opt-conversions.rs b/src/test/run-pass/result-opt-conversions.rs new file mode 100644 index 0000000000000..0f6da002dda37 --- /dev/null +++ b/src/test/run-pass/result-opt-conversions.rs @@ -0,0 +1,57 @@ +// Copyright 2018 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. + +#![feature(transpose_result)] + +#[derive(Copy, Clone, Debug, PartialEq)] +struct BadNumErr; + +fn try_num(x: i32) -> Result { + if x <= 5 { + Ok(x + 1) + } else { + Err(BadNumErr) + } +} + +type ResOpt = Result, BadNumErr>; +type OptRes = Option>; + +fn main() { + let mut x: ResOpt = Ok(Some(5)); + let mut y: OptRes = Some(Ok(5)); + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + x = Ok(None); + y = None; + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + x = Err(BadNumErr); + y = Some(Err(BadNumErr)); + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + let res: Result, BadNumErr> = + (0..10) + .map(|x| { + let y = try_num(x)?; + Ok(if y % 2 == 0 { + Some(y - 1) + } else { + None + }) + }) + .filter_map(Result::transpose) + .collect(); + + assert_eq!(res, Err(BadNumErr)) +} diff --git a/src/test/ui/mismatched_types/closure-arg-count.rs b/src/test/ui/mismatched_types/closure-arg-count.rs index 1ee24e398520b..96e5201716c71 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.rs +++ b/src/test/ui/mismatched_types/closure-arg-count.rs @@ -18,6 +18,8 @@ fn main() { //~^ ERROR closure is expected to take [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); //~^ ERROR closure is expected to take + [1, 2, 3].sort_by(|(tuple, tuple2): (usize, _)| panic!()); + //~^ ERROR closure is expected to take f(|| panic!()); //~^ ERROR closure is expected to take @@ -32,6 +34,9 @@ fn main() { let bar = |i, x, y| i; let _it = vec![1, 2, 3].into_iter().enumerate().map(bar); //~^ ERROR closure is expected to take + let _it = vec![1, 2, 3].into_iter().enumerate().map(qux); + //~^ ERROR function is expected to take } fn foo() {} +fn qux(x: usize, y: usize) {} diff --git a/src/test/ui/mismatched_types/closure-arg-count.stderr b/src/test/ui/mismatched_types/closure-arg-count.stderr index ba25d67d76ef2..be00ee4d74e7e 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.stderr +++ b/src/test/ui/mismatched_types/closure-arg-count.stderr @@ -14,18 +14,34 @@ error[E0593]: closure is expected to take 2 arguments, but it takes 1 argument | | | expected closure that takes 2 arguments -error[E0593]: closure is expected to take 2 arguments, but it takes 1 argument +error[E0593]: closure is expected to take 2 distinct arguments, but it takes a single 2-tuple as argument --> $DIR/closure-arg-count.rs:19:15 | 19 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); - | ^^^^^^^ ----------------- takes 1 argument + | ^^^^^^^ ----------------- takes a single 2-tuple as argument | | - | expected closure that takes 2 arguments + | expected closure that takes 2 distinct arguments +help: change the closure to take multiple arguments instead of a single tuple + | +19 | [1, 2, 3].sort_by(|tuple, tuple2| panic!()); + | ^^^^^^^^^^^^^^^ + +error[E0593]: closure is expected to take 2 distinct arguments, but it takes a single 2-tuple as argument + --> $DIR/closure-arg-count.rs:21:15 + | +21 | [1, 2, 3].sort_by(|(tuple, tuple2): (usize, _)| panic!()); + | ^^^^^^^ ----------------------------- takes a single 2-tuple as argument + | | + | expected closure that takes 2 distinct arguments +help: change the closure to take multiple arguments instead of a single tuple + | +21 | [1, 2, 3].sort_by(|tuple, tuple2| panic!()); + | ^^^^^^^^^^^^^^^ error[E0593]: closure is expected to take 1 argument, but it takes 0 arguments - --> $DIR/closure-arg-count.rs:21:5 + --> $DIR/closure-arg-count.rs:23:5 | -21 | f(|| panic!()); +23 | f(|| panic!()); | ^ -- takes 0 arguments | | | expected closure that takes 1 argument @@ -36,46 +52,63 @@ note: required by `f` 13 | fn f>(_: F) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0593]: closure is expected to take a single tuple as argument, but it takes 2 distinct arguments - --> $DIR/closure-arg-count.rs:24:53 +error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments + --> $DIR/closure-arg-count.rs:26:53 | -24 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x| i); - | ^^^ ------ help: consider changing the closure to accept a tuple: `|(i, x)|` +26 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x| i); + | ^^^ ------ takes 2 distinct arguments | | - | expected closure that takes a single tuple as argument + | expected closure that takes a single 2-tuple as argument +help: change the closure to accept a tuple instead of individual arguments + | +26 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|(i, x)| i); + | ^^^^^^^^ -error[E0593]: closure is expected to take a single tuple as argument, but it takes 2 distinct arguments - --> $DIR/closure-arg-count.rs:26:53 +error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments + --> $DIR/closure-arg-count.rs:28:53 | -26 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i: usize, x| i); - | ^^^ ------------- help: consider changing the closure to accept a tuple: `|(i, x): (usize, _)|` +28 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i: usize, x| i); + | ^^^ ------------- takes 2 distinct arguments | | - | expected closure that takes a single tuple as argument + | expected closure that takes a single 2-tuple as argument +help: change the closure to accept a tuple instead of individual arguments + | +28 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|(i, x)| i); + | ^^^^^^^^ error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 3 distinct arguments - --> $DIR/closure-arg-count.rs:28:53 + --> $DIR/closure-arg-count.rs:30:53 | -28 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x, y| i); +30 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x, y| i); | ^^^ --------- takes 3 distinct arguments | | | expected closure that takes a single 2-tuple as argument error[E0593]: function is expected to take a single 2-tuple as argument, but it takes 0 arguments - --> $DIR/closure-arg-count.rs:30:53 + --> $DIR/closure-arg-count.rs:32:53 | -30 | let _it = vec![1, 2, 3].into_iter().enumerate().map(foo); +32 | let _it = vec![1, 2, 3].into_iter().enumerate().map(foo); | ^^^ expected function that takes a single 2-tuple as argument ... -37 | fn foo() {} +41 | fn foo() {} | -------- takes 0 arguments error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 3 distinct arguments - --> $DIR/closure-arg-count.rs:33:53 + --> $DIR/closure-arg-count.rs:35:53 | -32 | let bar = |i, x, y| i; +34 | let bar = |i, x, y| i; | --------- takes 3 distinct arguments -33 | let _it = vec![1, 2, 3].into_iter().enumerate().map(bar); +35 | let _it = vec![1, 2, 3].into_iter().enumerate().map(bar); | ^^^ expected closure that takes a single 2-tuple as argument -error: aborting due to 9 previous errors +error[E0593]: function is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments + --> $DIR/closure-arg-count.rs:37:53 + | +37 | let _it = vec![1, 2, 3].into_iter().enumerate().map(qux); + | ^^^ expected function that takes a single 2-tuple as argument +... +42 | fn qux(x: usize, y: usize) {} + | -------------------------- takes 2 distinct arguments + +error: aborting due to 11 previous errors diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 61d71986b03eb..eee2902bfb6f7 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -69,6 +69,7 @@ fn filter_dirs(path: &Path) -> bool { "src/tools/miri", "src/librustc/mir/interpret", "src/librustc_mir/interpret", + "src/target", ]; skip.iter().any(|p| path.ends_with(p)) }