From 1a8cdc0f2f6a9f513cefbed36e5f57c1c45b8039 Mon Sep 17 00:00:00 2001 From: Barosl Lee Date: Tue, 4 Aug 2015 02:01:15 +0900 Subject: [PATCH 01/10] Use different numbers of `#`s when expanding documentation comments Any documentation comments that contain raw-string-looking sequences may pretty-print invalid code when expanding them, as the current logic always uses the `r"literal"` form, without appending any `#`s. This commit calculates the minimum number of `#`s required to wrap a comment correctly and appends `#`s appropriately. Fixes #27489. --- src/libstd/macros.rs | 3 ++ src/libsyntax/ast.rs | 16 +++++++- src/test/run-pass/macro-doc-raw-str-hashes.rs | 39 +++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/macro-doc-raw-str-hashes.rs diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 0917346213f4a..b7afd12d8e527 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -365,6 +365,9 @@ pub mod builtin { /// stringification of all the tokens passed to the macro. No restrictions /// are placed on the syntax of the macro invocation itself. /// + /// Note that the expanded results of the input tokens may change in the + /// future. You should be careful if you rely on the output. + /// /// # Examples /// /// ``` diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index e327adfaf892c..6ce8e70ecf24f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1174,6 +1174,20 @@ impl TokenTree { } (&TokenTree::Token(sp, token::DocComment(name)), _) => { let stripped = strip_doc_comment_decoration(&name.as_str()); + + // Searches for the occurrences of `"#*` and returns the minimum number of `#`s + // required to wrap the text. + let num_of_hashes = stripped.chars().scan(0, |cnt, x| { + *cnt = if x == '"' { + 1 + } else if *cnt != 0 && x == '#' { + *cnt + 1 + } else { + 0 + }; + Some(*cnt) + }).max().unwrap_or(0); + TokenTree::Delimited(sp, Rc::new(Delimited { delim: token::Bracket, open_span: sp, @@ -1181,7 +1195,7 @@ impl TokenTree { token::Plain)), TokenTree::Token(sp, token::Eq), TokenTree::Token(sp, token::Literal( - token::StrRaw(token::intern(&stripped), 0), None))], + token::StrRaw(token::intern(&stripped), num_of_hashes), None))], close_span: sp, })) } diff --git a/src/test/run-pass/macro-doc-raw-str-hashes.rs b/src/test/run-pass/macro-doc-raw-str-hashes.rs new file mode 100644 index 0000000000000..ffbe237b74e60 --- /dev/null +++ b/src/test/run-pass/macro-doc-raw-str-hashes.rs @@ -0,0 +1,39 @@ +// Copyright 2015 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. + +// The number of `#`s used to wrap the documentation comment should differ regarding the content. +// +// Related issue: #27489 + +macro_rules! homura { + ($x:expr, #[$y:meta]) => (assert_eq!($x, stringify!($y))) +} + +fn main() { + homura! { + r#"doc = r" Madoka""#, + /// Madoka + }; + + homura! { + r##"doc = r#" One quote mark: ["]"#"##, + /// One quote mark: ["] + }; + + homura! { + r##"doc = r#" Two quote marks: [""]"#"##, + /// Two quote marks: [""] + }; + + homura! { + r#####"doc = r####" Raw string ending sequences: ["###]"####"#####, + /// Raw string ending sequences: ["###] + }; +} From db63a55b29bebf50977dd72865a81905a5f9427d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 31 Jan 2016 01:09:55 +0100 Subject: [PATCH 02/10] Fix E0118 --- src/librustc_typeck/coherence/orphan.rs | 9 ++++-- src/librustc_typeck/diagnostics.rs | 42 +++++++++++++++++++------ 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 69eb7f51f3785..fb257f0e67328 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -209,9 +209,12 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { return; } _ => { - span_err!(self.tcx.sess, item.span, E0118, - "no base type found for inherent implementation; \ - implement a trait or new type instead"); + struct_span_err!(self.tcx.sess, item.span, E0118, + "no base type found for inherent implementation") + .span_help(item.span, + "either implement a trait on it or create a newtype to wrap it \ + instead") + .emit(); return; } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index df09cd261344e..f138b997f4cc3 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1489,22 +1489,46 @@ For information on the design of the orphan rules, see [RFC 1023]. "##, E0118: r##" -Rust can't find a base type for an implementation you are providing, or the type -cannot have an implementation. For example, only a named type or a trait can -have an implementation: +You're trying to write an inherent implementation for something which isn't a +struct nor an enum. Erroneous code example: ``` -type NineString = [char, ..9] // This isn't a named type (struct, enum or trait) -impl NineString { - // Some code here +impl (u8, u8) { // error: no base type found for inherent implementation + fn get_state(&self) -> String { + // ... + } +} +``` + +To fix this error, please implement a trait on the type or wrap it in a struct. +Example: + +``` +// we create a trait here +trait LiveLongAndProsper { + fn get_state(&self) -> String; +} + +// and now you can implement it on (u8, u8) +impl LiveLongAndProsper for (u8, u8) { + fn get_state(&self) -> String { + "He's dead, Jim!".to_owned() + } } ``` -In the other, simpler case, Rust just can't find the type you are providing an -impelementation for: +Alternatively, you can create a newtype. A newtype is a wrapping tuple-struct. +For example, `NewType` is a newtype over `Foo` in `struct NewType(Foo)`. +Example: ``` -impl SomeTypeThatDoesntExist { } +struct TypeWrapper((u8, u8)); + +impl TypeWrapper { + fn get_state(&self) -> String { + "Fascinating!".to_owned() + } +} ``` "##, From cea8f671994026cefdaadd7388aef9e05b479e66 Mon Sep 17 00:00:00 2001 From: Brandon W Maister Date: Sun, 31 Jan 2016 15:48:08 -0500 Subject: [PATCH 03/10] Don't show `const` in docs when it's not available Fixes #31098 --- src/librustdoc/html/format.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 9d5189cfd0b12..68909b958ba70 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -657,6 +657,9 @@ impl fmt::Display for UnsafetySpace { impl fmt::Display for ConstnessSpace { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() { + return Ok(()); + } match self.get() { hir::Constness::Const => write!(f, "const "), hir::Constness::NotConst => Ok(()) From 20c1dfd39e7326ae505bce0b1f1838e1371c82ad Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Sun, 31 Jan 2016 17:19:38 -0500 Subject: [PATCH 04/10] show location of unused error codes --- src/etc/errorck.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/etc/errorck.py b/src/etc/errorck.py index 1b15d2c8598e5..1f5f3784ac61d 100644 --- a/src/etc/errorck.py +++ b/src/etc/errorck.py @@ -114,7 +114,7 @@ def check_unused_error_codes(error_codes, check_error_codes, filenames, dirnames if errcode in errcode_checked: continue all_errors.append(errcode) - print("error: unused error code: " + errcode) + print("error: unused error code: {0} ({1}:{2})".format(*errcode_map[errcode][0])) errors = True From d59372b7aad364a287f21cfbcf12e85d8be97fc7 Mon Sep 17 00:00:00 2001 From: Brandon W Maister Date: Mon, 1 Feb 2016 13:05:37 -0500 Subject: [PATCH 05/10] Decide to hide constness only in fn/method renders ConstnessSpace has no knowledge of the type of item it's modifying, so hide the constness a level up. --- src/librustdoc/html/format.rs | 3 --- src/librustdoc/html/render.rs | 14 ++++++++++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 68909b958ba70..9d5189cfd0b12 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -657,9 +657,6 @@ impl fmt::Display for UnsafetySpace { impl fmt::Display for ConstnessSpace { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() { - return Ok(()); - } match self.get() { hir::Constness::Const => write!(f, "const "), hir::Constness::NotConst => Ok(()) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 850045382e1f2..dfbe08a0e423d 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -54,10 +54,12 @@ use externalfiles::ExternalHtml; use serialize::json::{self, ToJson}; use syntax::{abi, ast}; +use syntax::feature_gate::UnstableFeatures; use rustc::middle::cstore::LOCAL_CRATE; use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::middle::privacy::AccessLevels; use rustc::middle::stability; +use rustc::session::config::get_unstable_features_setting; use rustc_front::hir; use clean::{self, SelfTy}; @@ -1897,10 +1899,14 @@ fn item_static(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, f: &clean::Function) -> fmt::Result { + let vis_constness = match get_unstable_features_setting() { + UnstableFeatures::Allow => f.constness, + _ => hir::Constness::NotConst + }; try!(write!(w, "
{vis}{constness}{unsafety}{abi}fn \
                     {name}{generics}{decl}{where_clause}
", vis = VisSpace(it.visibility), - constness = ConstnessSpace(f.constness), + constness = ConstnessSpace(vis_constness), unsafety = UnsafetySpace(f.unsafety), abi = AbiSpace(f.abi), name = it.name.as_ref().unwrap(), @@ -2122,9 +2128,13 @@ fn render_assoc_item(w: &mut fmt::Formatter, meth: &clean::Item, href(did).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor) } }; + let vis_constness = match get_unstable_features_setting() { + UnstableFeatures::Allow => constness, + _ => hir::Constness::NotConst + }; write!(w, "{}{}{}fn {name}\ {generics}{decl}{where_clause}", - ConstnessSpace(constness), + ConstnessSpace(vis_constness), UnsafetySpace(unsafety), match abi { Abi::Rust => String::new(), From 7deb057d550b120aebe6576f860362cec38e3cf3 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 26 Jan 2016 13:03:31 -0500 Subject: [PATCH 06/10] Discuss pitfalls of stateful closures with Map Fixes #30632 --- src/libcore/iter.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 3f1c0f6a5492a..b9ca99628e5d0 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -3276,6 +3276,49 @@ impl DoubleEndedIterator for Zip where /// /// [`map()`]: trait.Iterator.html#method.map /// [`Iterator`]: trait.Iterator.html +/// +/// # Notes about side effects +/// +/// The [`map()`] iterator implements [`DoubleEndedIterator`], meaning that +/// you can also [`map()`] backwards: +/// +/// ```rust +/// let v: Vec = vec![1, 2, 3].into_iter().rev().map(|x| x + 1).collect(); +/// +/// assert_eq!(v, [4, 3, 2]); +/// ``` +/// +/// [`DoubleEndedIterator`]: trait.DoubleEndedIterator.html +/// +/// But if your closure has state, iterating backwards may act in a way you do +/// not expect. Let's go through an example. First, in the forward direction: +/// +/// ```rust +/// let mut c = 0; +/// +/// for pair in vec!['a', 'b', 'c'].into_iter() +/// .map(|letter| { c += 1; (letter, c) }) { +/// println!("{:?}", pair); +/// } +/// ``` +/// +/// This will print "('a', 1), ('b', 2), ('c', 3)". +/// +/// Now consider this twist where we add a call to `rev`. This version will +/// print `('c', 1), ('b', 2), ('a', 3)`. Note that the letters are reversed, +/// but the values of the counter still go in order. This is because `map()` is +/// still being called lazilly on each item, but we are popping items off the +/// back of the vector now, instead of shifting them from the front. +/// +/// ```rust +/// let mut c = 0; +/// +/// for pair in vec!['a', 'b', 'c'].into_iter() +/// .map(|letter| { c += 1; (letter, c) }) +/// .rev() { +/// println!("{:?}", pair); +/// } +/// ``` #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] From 69c298e733331ea742a4ddc9bccbcd70c9c7b45c Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 1 Feb 2016 18:33:08 -0500 Subject: [PATCH 07/10] Further explain take_while This is a behavior that some find confusing, so it deserves its own example. Fixes #31318 --- src/libcore/iter.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 3f1c0f6a5492a..65d1b96f81d1d 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -1050,6 +1050,30 @@ pub trait Iterator { /// // got a false, take_while() isn't used any more /// assert_eq!(iter.next(), None); /// ``` + /// + /// Because `take_while()` needs to look at the value in order to see if it + /// should be included or not, consuming iterators will see that it is + /// removed: + /// + /// ``` + /// let a = [1, 2, 3, 4]; + /// let mut iter = a.into_iter(); + /// + /// let result: Vec = iter.by_ref() + /// .take_while(|n| **n != 3) + /// .cloned() + /// .collect(); + /// + /// assert_eq!(result, &[1, 2]); + /// + /// let result: Vec = iter.cloned().collect(); + /// + /// assert_eq!(result, &[4]); + /// ``` + /// + /// The `3` is no longer there, because it was consumed in order to see if + /// the iteration should stop, but wasn't placed back into the iterator or + /// some similar thing. #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn take_while

(self, predicate: P) -> TakeWhile where From dc3a39d807512c626495c16680df2fffc16e8722 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 1 Feb 2016 18:49:47 -0500 Subject: [PATCH 08/10] Explain behavior of _ Fixes #31154 --- src/doc/book/patterns.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/doc/book/patterns.md b/src/doc/book/patterns.md index 8e9e7246e56f0..39a9cb1885e84 100644 --- a/src/doc/book/patterns.md +++ b/src/doc/book/patterns.md @@ -173,7 +173,31 @@ let (x, _, z) = coordinate(); Here, we bind the first and last element of the tuple to `x` and `z`, but ignore the middle element. -Similarly, you can use `..` in a pattern to disregard multiple values. +It’s worth noting that using `_` never binds the value in the first place, +which means a value may not move: + +```rust +let tuple: (u32, String) = (5, String::from("five")); + +// Here, tuple is moved, because the String moved: +let (x, _s) = tuple; + +// The next line would give "error: use of partially moved value: `tuple`" +// println!("Tuple is: {:?}", tuple); + +// However, + +let tuple = (5, String::from("five")); + +// Here, tuple is _not_ moved, as the String was never moved, and u32 is Copy: +let (x, _) = tuple; + +// That means this works: +println!("Tuple is: {:?}", tuple); +``` + +In a similar fashion to `_`, you can use `..` in a pattern to disregard +multiple values: ```rust enum OptionalTuple { From b2e887f0aa81e0751e30165d599ef97614320645 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Tue, 2 Feb 2016 08:47:23 -0600 Subject: [PATCH 09/10] Fix reference to `expect` The context of the link is `Result` but it points to the docs on `Option`'s `expect`. --- src/doc/book/guessing-game.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/guessing-game.md b/src/doc/book/guessing-game.md index 861ef6810f54a..a5259e9ca4c42 100644 --- a/src/doc/book/guessing-game.md +++ b/src/doc/book/guessing-game.md @@ -276,7 +276,7 @@ it’s called on, and if it isn’t a successful one, [`panic!`][panic]s with a message you passed it. A `panic!` like this will cause our program to crash, displaying the message. -[expect]: ../std/option/enum.Option.html#method.expect +[expect]: ../std/result/enum.Result.html#method.expect [panic]: error-handling.html If we leave off calling this method, our program will compile, but From 6c907212b446e1c39ddb6db621bb72c6d07255f6 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 2 Feb 2016 11:15:45 -0500 Subject: [PATCH 10/10] Add note about temporaries --- src/doc/book/patterns.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/doc/book/patterns.md b/src/doc/book/patterns.md index 39a9cb1885e84..6fd7f4cd4755a 100644 --- a/src/doc/book/patterns.md +++ b/src/doc/book/patterns.md @@ -196,8 +196,16 @@ let (x, _) = tuple; println!("Tuple is: {:?}", tuple); ``` -In a similar fashion to `_`, you can use `..` in a pattern to disregard -multiple values: +This also means that any temporary variables will be dropped at the end of the +statement: + +```rust +// Here, the String created will be dropped immediately, as it’s not bound: + +let _ = String::from(" hello ").trim(); +``` + +You can also use `..` in a pattern to disregard multiple values: ```rust enum OptionalTuple {