From cb12460467aa98cb82587308341939679ff2a7d1 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 30 May 2019 12:49:54 +0200 Subject: [PATCH 01/21] Implement Clone::clone_from for Option. --- src/libcore/option.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 6b7f491effb..c75ecb059e8 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -145,7 +145,7 @@ use crate::pin::Pin; // which basically means it must be `Option`. /// The `Option` type. See [the module level documentation](index.html) for more. -#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] +#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Option { /// No value @@ -1040,6 +1040,25 @@ fn expect_failed(msg: &str) -> ! { // Trait implementations ///////////////////////////////////////////////////////////////////////////// +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Option { + #[inline] + fn clone(&self) -> Self { + match self { + Some(x) => Some(x.clone()), + None => None, + } + } + + #[inline] + fn clone_from(&mut self, source: &Self) { + match (self, source) { + (Some(to), Some(from)) => to.clone_from(from), + (to, from) => *to = from.clone(), + } + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Default for Option { /// Returns [`None`][Option::None]. From 67fd99589ad161fcd154cfdb0f33d349ec23896d Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 30 May 2019 12:50:06 +0200 Subject: [PATCH 02/21] Implement Clone::clone_from for Result. --- src/libcore/result.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/libcore/result.rs b/src/libcore/result.rs index bf8fd63b644..8a09877ce1f 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -240,7 +240,7 @@ use crate::ops::{self, Deref}; /// /// [`Ok`]: enum.Result.html#variant.Ok /// [`Err`]: enum.Result.html#variant.Err -#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] +#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] #[must_use = "this `Result` may be an `Err` variant, which should be handled"] #[stable(feature = "rust1", since = "1.0.0")] pub enum Result { @@ -1003,6 +1003,27 @@ fn unwrap_failed(msg: &str, error: E) -> ! { // Trait implementations ///////////////////////////////////////////////////////////////////////////// +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Result { + #[inline] + fn clone(&self) -> Self { + match self { + Ok(x) => Ok(x.clone()), + Err(x) => Err(x.clone()), + } + } + + #[inline] + fn clone_from(&mut self, source: &Self) { + match (self, source) { + (Ok(to), Ok(from)) => to.clone_from(from), + (Err(to), Err(from)) => to.clone_from(from), + (to, from) => *to = from.clone(), + } + } +} + + #[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for Result { type Item = T; From 5fb099dc786c1bee7116fecb4965d34ad5e0a4a5 Mon Sep 17 00:00:00 2001 From: Cedric Date: Sat, 8 Jun 2019 10:49:46 +0200 Subject: [PATCH 03/21] use pattern matching for slices destructuring --- src/libsyntax/diagnostics/plugin.rs | 23 +++----- src/libsyntax/parse/mod.rs | 55 ++++++++----------- src/libsyntax_ext/deriving/cmp/ord.rs | 4 +- src/libsyntax_ext/deriving/cmp/partial_eq.rs | 4 +- src/libsyntax_ext/deriving/cmp/partial_ord.rs | 8 +-- src/libsyntax_ext/deriving/hash.rs | 4 +- src/libsyntax_ext/trace_macros.rs | 6 +- 7 files changed, 45 insertions(+), 59 deletions(-) diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index 9f01b9b9f9b..b958a760e82 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -33,8 +33,8 @@ pub fn expand_diagnostic_used<'cx>(ecx: &'cx mut ExtCtxt<'_>, span: Span, token_tree: &[TokenTree]) -> Box { - let code = match (token_tree.len(), token_tree.get(0)) { - (1, Some(&TokenTree::Token(Token { kind: token::Ident(code, _), .. }))) => code, + let code = match token_tree { + &[TokenTree::Token(Token { kind: token::Ident(code, _), .. })] => code, _ => unreachable!() }; @@ -66,22 +66,15 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt<'_>, span: Span, token_tree: &[TokenTree]) -> Box { - let (code, description) = match ( - token_tree.len(), - token_tree.get(0), - token_tree.get(1), - token_tree.get(2) - ) { - (1, Some(&TokenTree::Token(Token { kind: token::Ident(code, _), .. })), None, None) => { + let (code, description) = match token_tree { + &[TokenTree::Token(Token { kind: token::Ident(code, _), .. })] => { (code, None) }, - (3, Some(&TokenTree::Token(Token { kind: token::Ident(code, _), .. })), - Some(&TokenTree::Token(Token { kind: token::Comma, .. })), - Some(&TokenTree::Token(Token { - kind: token::Literal(token::Lit { symbol, .. }), .. - }))) => { + &[TokenTree::Token(Token { kind: token::Ident(code, _), .. }), + TokenTree::Token(Token { kind: token::Comma, .. }), + TokenTree::Token(Token { kind: token::Literal(token::Lit { symbol, .. }), ..})] => { (code, Some(symbol)) - } + }, _ => unreachable!() }; diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 063823bbf4d..1d5f1001ac9 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -424,47 +424,40 @@ mod tests { string_to_stream("macro_rules! zip (($a)=>($a))".to_string()).trees().collect(); let tts: &[TokenTree] = &tts[..]; - match (tts.len(), tts.get(0), tts.get(1), tts.get(2), tts.get(3)) { - ( - 4, - Some(&TokenTree::Token(Token { - kind: token::Ident(name_macro_rules, false), .. - })), - Some(&TokenTree::Token(Token { kind: token::Not, .. })), - Some(&TokenTree::Token(Token { kind: token::Ident(name_zip, false), .. })), - Some(&TokenTree::Delimited(_, macro_delim, ref macro_tts)), - ) + match tts { + &[TokenTree::Token(Token {kind: token::Ident(name_macro_rules, false), ..}), + TokenTree::Token(Token { kind: token::Not, .. }), + TokenTree::Token(Token { kind: token::Ident(name_zip, false), .. }), + TokenTree::Delimited(_, macro_delim, ref macro_tts) + ] if name_macro_rules == sym::macro_rules && name_zip.as_str() == "zip" => { let tts = ¯o_tts.trees().collect::>(); - match (tts.len(), tts.get(0), tts.get(1), tts.get(2)) { - ( - 3, - Some(&TokenTree::Delimited(_, first_delim, ref first_tts)), - Some(&TokenTree::Token(Token { kind: token::FatArrow, .. })), - Some(&TokenTree::Delimited(_, second_delim, ref second_tts)), - ) + match tts { + &[ + TokenTree::Delimited(_, first_delim, ref first_tts), + TokenTree::Token(Token { kind: token::FatArrow, .. }), + TokenTree::Delimited(_, second_delim, ref second_tts), + ] if macro_delim == token::Paren => { let tts = &first_tts.trees().collect::>(); - match (tts.len(), tts.get(0), tts.get(1)) { - ( - 2, - Some(&TokenTree::Token(Token { kind: token::Dollar, .. })), - Some(&TokenTree::Token(Token { + match tts { + &[ + TokenTree::Token(Token { kind: token::Dollar, .. }), + TokenTree::Token(Token { kind: token::Ident(name, false), .. - })), - ) + }), + ] if first_delim == token::Paren && name.as_str() == "a" => {}, _ => panic!("value 3: {:?} {:?}", first_delim, first_tts), } let tts = &second_tts.trees().collect::>(); - match (tts.len(), tts.get(0), tts.get(1)) { - ( - 2, - Some(&TokenTree::Token(Token { kind: token::Dollar, .. })), - Some(&TokenTree::Token(Token { + match tts { + &[ + TokenTree::Token(Token { kind: token::Dollar, .. }), + TokenTree::Token(Token { kind: token::Ident(name, false), .. - })), - ) + }), + ] if second_delim == token::Paren && name.as_str() == "a" => {}, _ => panic!("value 4: {:?} {:?}", second_delim, second_tts), } diff --git a/src/libsyntax_ext/deriving/cmp/ord.rs b/src/libsyntax_ext/deriving/cmp/ord.rs index b25a9e4c50f..844865d57c7 100644 --- a/src/libsyntax_ext/deriving/cmp/ord.rs +++ b/src/libsyntax_ext/deriving/cmp/ord.rs @@ -82,8 +82,8 @@ pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P< // } let new = { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, + let other_f = match other_fs { + [o_f] => o_f, _ => cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`"), }; diff --git a/src/libsyntax_ext/deriving/cmp/partial_eq.rs b/src/libsyntax_ext/deriving/cmp/partial_eq.rs index 6172f27261e..732bb234389 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_eq.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_eq.rs @@ -25,8 +25,8 @@ pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt<'_>, -> P { let op = |cx: &mut ExtCtxt<'_>, span: Span, self_f: P, other_fs: &[P]| { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, + let other_f = match other_fs { + [o_f] => o_f, _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`"), }; diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index 3980741f252..a30a7d78222 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -143,8 +143,8 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_ // } let new = { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, + let other_f = match other_fs { + [o_f] => o_f, _ => { cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") @@ -193,8 +193,8 @@ fn cs_op(less: bool, }; let par_cmp = |cx: &mut ExtCtxt<'_>, span, self_f: P, other_fs: &[P], default| { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, + let other_f = match other_fs { + [o_f] => o_f, _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"), }; diff --git a/src/libsyntax_ext/deriving/hash.rs b/src/libsyntax_ext/deriving/hash.rs index e7f99d45782..7ad04aebf6e 100644 --- a/src/libsyntax_ext/deriving/hash.rs +++ b/src/libsyntax_ext/deriving/hash.rs @@ -52,8 +52,8 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt<'_>, } fn hash_substructure(cx: &mut ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>) -> P { - let state_expr = match (substr.nonself_args.len(), substr.nonself_args.get(0)) { - (1, Some(o_f)) => o_f, + let state_expr = match &substr.nonself_args { + &[o_f] => o_f, _ => { cx.span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`") diff --git a/src/libsyntax_ext/trace_macros.rs b/src/libsyntax_ext/trace_macros.rs index 6c74f77ff1f..512513e9b41 100644 --- a/src/libsyntax_ext/trace_macros.rs +++ b/src/libsyntax_ext/trace_macros.rs @@ -16,11 +16,11 @@ pub fn expand_trace_macros(cx: &mut ExtCtxt<'_>, feature_gate::EXPLAIN_TRACE_MACROS); } - match (tt.len(), tt.first()) { - (1, Some(TokenTree::Token(token))) if token.is_keyword(kw::True) => { + match tt { + [TokenTree::Token(token)] if token.is_keyword(kw::True) => { cx.set_trace_macros(true); } - (1, Some(TokenTree::Token(token))) if token.is_keyword(kw::False) => { + [TokenTree::Token(token)] if token.is_keyword(kw::False) => { cx.set_trace_macros(false); } _ => cx.span_err(sp, "trace_macros! accepts only `true` or `false`"), From ad91a8e59abca232a3e4449186712c032ab12519 Mon Sep 17 00:00:00 2001 From: Cedric Date: Sat, 8 Jun 2019 11:38:15 +0200 Subject: [PATCH 04/21] improve style --- src/libsyntax/parse/mod.rs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 1d5f1001ac9..72573af9c40 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -425,27 +425,26 @@ mod tests { let tts: &[TokenTree] = &tts[..]; match tts { - &[TokenTree::Token(Token {kind: token::Ident(name_macro_rules, false), ..}), - TokenTree::Token(Token { kind: token::Not, .. }), - TokenTree::Token(Token { kind: token::Ident(name_zip, false), .. }), - TokenTree::Delimited(_, macro_delim, ref macro_tts) + &[ + TokenTree::Token(Token {kind: token::Ident(name_macro_rules, false), ..}), + TokenTree::Token(Token {kind: token::Not, ..}), + TokenTree::Token(Token {kind: token::Ident(name_zip, false), ..}), + TokenTree::Delimited(_, macro_delim, ref macro_tts) ] if name_macro_rules == sym::macro_rules && name_zip.as_str() == "zip" => { let tts = ¯o_tts.trees().collect::>(); match tts { &[ TokenTree::Delimited(_, first_delim, ref first_tts), - TokenTree::Token(Token { kind: token::FatArrow, .. }), + TokenTree::Token(Token {kind: token::FatArrow, ..}), TokenTree::Delimited(_, second_delim, ref second_tts), ] if macro_delim == token::Paren => { let tts = &first_tts.trees().collect::>(); match tts { &[ - TokenTree::Token(Token { kind: token::Dollar, .. }), - TokenTree::Token(Token { - kind: token::Ident(name, false), .. - }), + TokenTree::Token(Token {kind: token::Dollar, ..}), + TokenTree::Token(Token {kind: token::Ident(name, false), ..}), ] if first_delim == token::Paren && name.as_str() == "a" => {}, _ => panic!("value 3: {:?} {:?}", first_delim, first_tts), @@ -453,10 +452,8 @@ mod tests { let tts = &second_tts.trees().collect::>(); match tts { &[ - TokenTree::Token(Token { kind: token::Dollar, .. }), - TokenTree::Token(Token { - kind: token::Ident(name, false), .. - }), + TokenTree::Token(Token {kind: token::Dollar, ..}), + TokenTree::Token(Token {kind: token::Ident(name, false), ..}), ] if second_delim == token::Paren && name.as_str() == "a" => {}, _ => panic!("value 4: {:?} {:?}", second_delim, second_tts), From 4123b5d796345bb01f0f40b2e28e6c194371fabe Mon Sep 17 00:00:00 2001 From: Cedric Date: Sat, 8 Jun 2019 12:18:13 +0200 Subject: [PATCH 05/21] fix bad style for structs --- src/libsyntax/diagnostics/plugin.rs | 16 +++++++++++----- src/libsyntax/parse/mod.rs | 16 ++++++++-------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index b958a760e82..b4cf24f5ac5 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -34,7 +34,9 @@ pub fn expand_diagnostic_used<'cx>(ecx: &'cx mut ExtCtxt<'_>, token_tree: &[TokenTree]) -> Box { let code = match token_tree { - &[TokenTree::Token(Token { kind: token::Ident(code, _), .. })] => code, + &[ + TokenTree::Token(Token { kind: token::Ident(code, _), .. }) + ] => code, _ => unreachable!() }; @@ -67,12 +69,16 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt<'_>, token_tree: &[TokenTree]) -> Box { let (code, description) = match token_tree { - &[TokenTree::Token(Token { kind: token::Ident(code, _), .. })] => { + &[ + TokenTree::Token(Token { kind: token::Ident(code, _), .. }) + ] => { (code, None) }, - &[TokenTree::Token(Token { kind: token::Ident(code, _), .. }), - TokenTree::Token(Token { kind: token::Comma, .. }), - TokenTree::Token(Token { kind: token::Literal(token::Lit { symbol, .. }), ..})] => { + &[ + TokenTree::Token(Token { kind: token::Ident(code, _), .. }), + TokenTree::Token(Token { kind: token::Comma, .. }), + TokenTree::Token(Token { kind: token::Literal(token::Lit { symbol, .. }), ..}) + ] => { (code, Some(symbol)) }, _ => unreachable!() diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 72573af9c40..025972d8ca7 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -426,9 +426,9 @@ mod tests { match tts { &[ - TokenTree::Token(Token {kind: token::Ident(name_macro_rules, false), ..}), - TokenTree::Token(Token {kind: token::Not, ..}), - TokenTree::Token(Token {kind: token::Ident(name_zip, false), ..}), + TokenTree::Token(Token { kind: token::Ident(name_macro_rules, false), .. }), + TokenTree::Token(Token { kind: token::Not, .. }), + TokenTree::Token(Token { kind: token::Ident(name_zip, false), .. }), TokenTree::Delimited(_, macro_delim, ref macro_tts) ] if name_macro_rules == sym::macro_rules && name_zip.as_str() == "zip" => { @@ -436,15 +436,15 @@ mod tests { match tts { &[ TokenTree::Delimited(_, first_delim, ref first_tts), - TokenTree::Token(Token {kind: token::FatArrow, ..}), + TokenTree::Token(Token { kind: token::FatArrow, .. }), TokenTree::Delimited(_, second_delim, ref second_tts), ] if macro_delim == token::Paren => { let tts = &first_tts.trees().collect::>(); match tts { &[ - TokenTree::Token(Token {kind: token::Dollar, ..}), - TokenTree::Token(Token {kind: token::Ident(name, false), ..}), + TokenTree::Token(Token { kind: token::Dollar, .. }), + TokenTree::Token(Token { kind: token::Ident(name, false), .. }), ] if first_delim == token::Paren && name.as_str() == "a" => {}, _ => panic!("value 3: {:?} {:?}", first_delim, first_tts), @@ -452,8 +452,8 @@ mod tests { let tts = &second_tts.trees().collect::>(); match tts { &[ - TokenTree::Token(Token {kind: token::Dollar, ..}), - TokenTree::Token(Token {kind: token::Ident(name, false), ..}), + TokenTree::Token(Token { kind: token::Dollar, .. }), + TokenTree::Token(Token { kind: token::Ident(name, false), .. }), ] if second_delim == token::Paren && name.as_str() == "a" => {}, _ => panic!("value 4: {:?} {:?}", second_delim, second_tts), From dd442a1fcfba98be5454c2ca6f56bce098e458ed Mon Sep 17 00:00:00 2001 From: Cedric Date: Sat, 8 Jun 2019 13:29:43 +0200 Subject: [PATCH 06/21] use default binding mode in match clauses --- src/libsyntax/diagnostics/plugin.rs | 10 +++++----- src/libsyntax/parse/mod.rs | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index b4cf24f5ac5..98351048c35 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -34,7 +34,7 @@ pub fn expand_diagnostic_used<'cx>(ecx: &'cx mut ExtCtxt<'_>, token_tree: &[TokenTree]) -> Box { let code = match token_tree { - &[ + [ TokenTree::Token(Token { kind: token::Ident(code, _), .. }) ] => code, _ => unreachable!() @@ -69,17 +69,17 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt<'_>, token_tree: &[TokenTree]) -> Box { let (code, description) = match token_tree { - &[ + [ TokenTree::Token(Token { kind: token::Ident(code, _), .. }) ] => { - (code, None) + (*code, None) }, - &[ + [ TokenTree::Token(Token { kind: token::Ident(code, _), .. }), TokenTree::Token(Token { kind: token::Comma, .. }), TokenTree::Token(Token { kind: token::Literal(token::Lit { symbol, .. }), ..}) ] => { - (code, Some(symbol)) + (*code, Some(*symbol)) }, _ => unreachable!() }; diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 025972d8ca7..b912bf8295a 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -434,15 +434,15 @@ mod tests { if name_macro_rules == sym::macro_rules && name_zip.as_str() == "zip" => { let tts = ¯o_tts.trees().collect::>(); match tts { - &[ - TokenTree::Delimited(_, first_delim, ref first_tts), + [ + TokenTree::Delimited(_, first_delim, first_tts), TokenTree::Token(Token { kind: token::FatArrow, .. }), - TokenTree::Delimited(_, second_delim, ref second_tts), + TokenTree::Delimited(_, second_delim, second_tts), ] if macro_delim == token::Paren => { let tts = &first_tts.trees().collect::>(); match tts { - &[ + [ TokenTree::Token(Token { kind: token::Dollar, .. }), TokenTree::Token(Token { kind: token::Ident(name, false), .. }), ] @@ -451,7 +451,7 @@ mod tests { } let tts = &second_tts.trees().collect::>(); match tts { - &[ + [ TokenTree::Token(Token { kind: token::Dollar, .. }), TokenTree::Token(Token { kind: token::Ident(name, false), .. }), ] From 4c242a948c9f109c25c1ae54102f7a66271fa2ca Mon Sep 17 00:00:00 2001 From: Cedric Date: Sat, 8 Jun 2019 16:21:15 +0200 Subject: [PATCH 07/21] cast vec to slices --- src/libsyntax/parse/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index b912bf8295a..ebe5e70d1a7 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -425,15 +425,15 @@ mod tests { let tts: &[TokenTree] = &tts[..]; match tts { - &[ + [ TokenTree::Token(Token { kind: token::Ident(name_macro_rules, false), .. }), TokenTree::Token(Token { kind: token::Not, .. }), TokenTree::Token(Token { kind: token::Ident(name_zip, false), .. }), - TokenTree::Delimited(_, macro_delim, ref macro_tts) + TokenTree::Delimited(_, macro_delim, macro_tts) ] if name_macro_rules == sym::macro_rules && name_zip.as_str() == "zip" => { let tts = ¯o_tts.trees().collect::>(); - match tts { + match &tts[..] { [ TokenTree::Delimited(_, first_delim, first_tts), TokenTree::Token(Token { kind: token::FatArrow, .. }), @@ -441,7 +441,7 @@ mod tests { ] if macro_delim == token::Paren => { let tts = &first_tts.trees().collect::>(); - match tts { + match &tts[..] { [ TokenTree::Token(Token { kind: token::Dollar, .. }), TokenTree::Token(Token { kind: token::Ident(name, false), .. }), @@ -450,7 +450,7 @@ mod tests { _ => panic!("value 3: {:?} {:?}", first_delim, first_tts), } let tts = &second_tts.trees().collect::>(); - match tts { + match &tts[..] { [ TokenTree::Token(Token { kind: token::Dollar, .. }), TokenTree::Token(Token { kind: token::Ident(name, false), .. }), From 0a4504d400805b2d102a433af98cc33f185fdcf2 Mon Sep 17 00:00:00 2001 From: Cedric Date: Sat, 8 Jun 2019 20:43:24 +0200 Subject: [PATCH 08/21] fix libsyntax test --- src/libsyntax/parse/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index ebe5e70d1a7..19dd8ebd087 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -431,7 +431,7 @@ mod tests { TokenTree::Token(Token { kind: token::Ident(name_zip, false), .. }), TokenTree::Delimited(_, macro_delim, macro_tts) ] - if name_macro_rules == sym::macro_rules && name_zip.as_str() == "zip" => { + if name_macro_rules == &sym::macro_rules && name_zip.as_str() == "zip" => { let tts = ¯o_tts.trees().collect::>(); match &tts[..] { [ @@ -439,14 +439,14 @@ mod tests { TokenTree::Token(Token { kind: token::FatArrow, .. }), TokenTree::Delimited(_, second_delim, second_tts), ] - if macro_delim == token::Paren => { + if macro_delim == &token::Paren => { let tts = &first_tts.trees().collect::>(); match &tts[..] { [ TokenTree::Token(Token { kind: token::Dollar, .. }), TokenTree::Token(Token { kind: token::Ident(name, false), .. }), ] - if first_delim == token::Paren && name.as_str() == "a" => {}, + if first_delim == &token::Paren && name.as_str() == "a" => {}, _ => panic!("value 3: {:?} {:?}", first_delim, first_tts), } let tts = &second_tts.trees().collect::>(); @@ -455,7 +455,7 @@ mod tests { TokenTree::Token(Token { kind: token::Dollar, .. }), TokenTree::Token(Token { kind: token::Ident(name, false), .. }), ] - if second_delim == token::Paren && name.as_str() == "a" => {}, + if second_delim == &token::Paren && name.as_str() == "a" => {}, _ => panic!("value 4: {:?} {:?}", second_delim, second_tts), } }, From 26d4c8f01c07fdb3b0c0354dd9b509c955a87e9c Mon Sep 17 00:00:00 2001 From: Adrian Friedli Date: Sat, 8 Jun 2019 22:30:45 +0200 Subject: [PATCH 09/21] implement nth_back for Range --- src/libcore/iter/range.rs | 13 +++++++++++++ src/libcore/tests/iter.rs | 17 +++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 6bbf776fb8f..e171108a146 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -281,6 +281,19 @@ impl DoubleEndedIterator for ops::Range { None } } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + if let Some(minus_n) = self.end.sub_usize(n) { + if minus_n > self.start { + self.end = minus_n.sub_one(); + return Some(self.end.clone()) + } + } + + self.end = self.start.clone(); + None + } } #[stable(feature = "fused", since = "1.26.0")] diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index bedb9e75612..171a33695bc 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1657,6 +1657,23 @@ fn test_range_nth() { assert_eq!(r, 20..20); } +#[test] +fn test_range_nth_back() { + assert_eq!((10..15).nth_back(0), Some(14)); + assert_eq!((10..15).nth_back(1), Some(13)); + assert_eq!((10..15).nth_back(4), Some(10)); + assert_eq!((10..15).nth_back(5), None); + assert_eq!((-120..80_i8).nth_back(199), Some(-120)); + + let mut r = 10..20; + assert_eq!(r.nth_back(2), Some(17)); + assert_eq!(r, 10..17); + assert_eq!(r.nth_back(2), Some(14)); + assert_eq!(r, 10..14); + assert_eq!(r.nth_back(10), None); + assert_eq!(r, 10..10); +} + #[test] fn test_range_from_nth() { assert_eq!((10..).nth(0), Some(10)); From 20efb19043335587e27a1c11bfeb596611e4bef7 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 6 Jun 2019 08:41:31 -0600 Subject: [PATCH 10/21] Make a few methods private --- src/librustc/traits/on_unimplemented.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs index 1c17ace90c2..14b968c83b2 100644 --- a/src/librustc/traits/on_unimplemented.rs +++ b/src/librustc/traits/on_unimplemented.rs @@ -52,7 +52,7 @@ fn parse_error(tcx: TyCtxt<'_, '_, '_>, span: Span, } impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { - pub fn parse(tcx: TyCtxt<'a, 'gcx, 'tcx>, + fn parse(tcx: TyCtxt<'a, 'gcx, 'tcx>, trait_def_id: DefId, items: &[NestedMetaItem], span: Span, @@ -215,7 +215,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { } impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { - pub fn try_parse(tcx: TyCtxt<'a, 'gcx, 'tcx>, + fn try_parse(tcx: TyCtxt<'a, 'gcx, 'tcx>, trait_def_id: DefId, from: LocalInternedString, err_sp: Span) From 7795b155e04dcf245f240f4486485b1099fb4a99 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 4 Jun 2019 08:57:40 -0600 Subject: [PATCH 11/21] Inline raw method --- src/libfmt_macros/lib.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 6fed8302160..d5ce389ed5f 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -302,22 +302,19 @@ impl<'a> Parser<'a> { } } - fn raw(&self) -> usize { - self.style.map(|raw| raw + 1).unwrap_or(0) - } - fn to_span_index(&self, pos: usize) -> SpanIndex { let mut pos = pos; + let raw = self.style.map(|raw| raw + 1).unwrap_or(0); for skip in &self.skips { if pos > *skip { pos += 1; - } else if pos == *skip && self.raw() == 0 { + } else if pos == *skip && raw == 0 { pos += 1; } else { break; } } - SpanIndex(self.raw() + pos + 1) + SpanIndex(raw + pos + 1) } /// Forces consumption of the specified character. If the character is not From dc13072b7b7143fe98926632b9b89e7ffff2cdb7 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 3 Jun 2019 20:47:42 -0600 Subject: [PATCH 12/21] Use Symbol for named arguments in fmt_macros --- Cargo.lock | 3 ++ src/libfmt_macros/Cargo.toml | 3 ++ src/libfmt_macros/lib.rs | 37 +++++++++++++++---------- src/librustc/traits/error_reporting.rs | 32 ++++++++++----------- src/librustc/traits/on_unimplemented.rs | 34 +++++++++++------------ src/libsyntax_ext/format.rs | 25 ++++++++--------- src/libsyntax_pos/symbol.rs | 6 ++++ 7 files changed, 79 insertions(+), 61 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7f35b7344df..73605af7936 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -910,6 +910,9 @@ dependencies = [ [[package]] name = "fmt_macros" version = "0.0.0" +dependencies = [ + "syntax_pos 0.0.0", +] [[package]] name = "fnv" diff --git a/src/libfmt_macros/Cargo.toml b/src/libfmt_macros/Cargo.toml index 50779a2d9ad..fc32f21ec4e 100644 --- a/src/libfmt_macros/Cargo.toml +++ b/src/libfmt_macros/Cargo.toml @@ -8,3 +8,6 @@ edition = "2018" name = "fmt_macros" path = "lib.rs" crate-type = ["dylib"] + +[dependencies] +syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index d5ce389ed5f..9d6720810b8 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -24,6 +24,8 @@ use std::str; use std::string; use std::iter; +use syntax_pos::Symbol; + /// A piece is a portion of the format string which represents the next part /// to emit. These are emitted as a stream by the `Parser` class. #[derive(Copy, Clone, PartialEq)] @@ -39,7 +41,7 @@ pub enum Piece<'a> { #[derive(Copy, Clone, PartialEq)] pub struct Argument<'a> { /// Where to find this argument - pub position: Position<'a>, + pub position: Position, /// How to format the argument pub format: FormatSpec<'a>, } @@ -54,9 +56,9 @@ pub struct FormatSpec<'a> { /// Packed version of various flags provided pub flags: u32, /// The integer precision to use - pub precision: Count<'a>, + pub precision: Count, /// The string width requested for the resulting format - pub width: Count<'a>, + pub width: Count, /// The descriptor string representing the name of the format desired for /// this argument, this can be empty or any number of characters, although /// it is required to be one word. @@ -65,16 +67,16 @@ pub struct FormatSpec<'a> { /// Enum describing where an argument for a format can be located. #[derive(Copy, Clone, PartialEq)] -pub enum Position<'a> { +pub enum Position { /// The argument is implied to be located at an index ArgumentImplicitlyIs(usize), /// The argument is located at a specific index given in the format ArgumentIs(usize), /// The argument has a name. - ArgumentNamed(&'a str), + ArgumentNamed(Symbol), } -impl Position<'_> { +impl Position { pub fn index(&self) -> Option { match self { ArgumentIs(i) | ArgumentImplicitlyIs(i) => Some(*i), @@ -119,11 +121,11 @@ pub enum Flag { /// A count is used for the precision and width parameters of an integer, and /// can reference either an argument or a literal integer. #[derive(Copy, Clone, PartialEq)] -pub enum Count<'a> { +pub enum Count { /// The count is specified explicitly. CountIs(usize), /// The count is specified by the argument with the given name. - CountIsName(&'a str), + CountIsName(Symbol), /// The count is specified by the argument at the given index. CountIsParam(usize), /// The count is implied and cannot be explicitly specified. @@ -431,12 +433,14 @@ impl<'a> Parser<'a> { /// integer index of an argument, a named argument, or a blank string. /// Returns `Some(parsed_position)` if the position is not implicitly /// consuming a macro argument, `None` if it's the case. - fn position(&mut self) -> Option> { + fn position(&mut self) -> Option { if let Some(i) = self.integer() { Some(ArgumentIs(i)) } else { match self.cur.peek() { - Some(&(_, c)) if c.is_alphabetic() => Some(ArgumentNamed(self.word())), + Some(&(_, c)) if c.is_alphabetic() => { + Some(ArgumentNamed(Symbol::intern(self.word()))) + } Some(&(pos, c)) if c == '_' => { let invalid_name = self.string(pos); self.err_with_note(format!("invalid argument name `{}`", invalid_name), @@ -444,7 +448,7 @@ impl<'a> Parser<'a> { "argument names cannot start with an underscore", self.to_span_index(pos), self.to_span_index(pos + invalid_name.len())); - Some(ArgumentNamed(invalid_name)) + Some(ArgumentNamed(Symbol::intern(invalid_name))) }, // This is an `ArgumentNext`. @@ -552,7 +556,7 @@ impl<'a> Parser<'a> { /// Parses a Count parameter at the current position. This does not check /// for 'CountIsNextParam' because that is only used in precision, not /// width. - fn count(&mut self) -> Count<'a> { + fn count(&mut self) -> Count { if let Some(i) = self.integer() { if self.consume('$') { CountIsParam(i) @@ -566,7 +570,7 @@ impl<'a> Parser<'a> { self.cur = tmp; CountImplied } else if self.consume('$') { - CountIsName(word) + CountIsName(Symbol::intern(word)) } else { self.cur = tmp; CountImplied @@ -756,6 +760,8 @@ mod tests { } #[test] fn format_counts() { + use syntax_pos::{GLOBALS, Globals, edition}; + GLOBALS.set(&Globals::new(edition::DEFAULT_EDITION), || { same("{:10s}", &[NextArgument(Argument { position: ArgumentImplicitlyIs(0), @@ -811,11 +817,12 @@ mod tests { fill: None, align: AlignUnknown, flags: 0, - precision: CountIsName("b"), - width: CountIsName("a"), + precision: CountIsName(Symbol::intern("b")), + width: CountIsName(Symbol::intern("a")), ty: "s", }, })]); + }); } #[test] fn format_flags() { diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 490501bde73..50d2eeef421 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -353,7 +353,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { _ => { // this is a "direct", user-specified, rather than derived, // obligation. - flags.push(("direct".to_owned(), None)); + flags.push((sym::direct, None)); } } @@ -365,27 +365,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Currently I'm leaving it for what I need for `try`. if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) { let method = self.tcx.item_name(item); - flags.push(("from_method".to_owned(), None)); - flags.push(("from_method".to_owned(), Some(method.to_string()))); + flags.push((sym::from_method, None)); + flags.push((sym::from_method, Some(method.to_string()))); } } if let Some(t) = self.get_parent_trait_ref(&obligation.cause.code) { - flags.push(("parent_trait".to_owned(), Some(t))); + flags.push((sym::parent_trait, Some(t))); } if let Some(k) = obligation.cause.span.compiler_desugaring_kind() { - flags.push(("from_desugaring".to_owned(), None)); - flags.push(("from_desugaring".to_owned(), Some(k.name().to_string()))); + flags.push((sym::from_desugaring, None)); + flags.push((sym::from_desugaring, Some(k.name().to_string()))); } let generics = self.tcx.generics_of(def_id); let self_ty = trait_ref.self_ty(); // This is also included through the generics list as `Self`, // but the parser won't allow you to use it - flags.push(("_Self".to_owned(), Some(self_ty.to_string()))); + flags.push((sym::_Self, Some(self_ty.to_string()))); if let Some(def) = self_ty.ty_adt_def() { // We also want to be able to select self's original // signature with no type arguments resolved - flags.push(("_Self".to_owned(), Some(self.tcx.type_of(def.did).to_string()))); + flags.push((sym::_Self, Some(self.tcx.type_of(def.did).to_string()))); } for param in generics.params.iter() { @@ -396,38 +396,38 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }, GenericParamDefKind::Lifetime => continue, }; - let name = param.name.to_string(); + let name = param.name.as_symbol(); flags.push((name, Some(value))); } if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) { - flags.push(("crate_local".to_owned(), None)); + flags.push((sym::crate_local, None)); } // Allow targeting all integers using `{integral}`, even if the exact type was resolved if self_ty.is_integral() { - flags.push(("_Self".to_owned(), Some("{integral}".to_owned()))); + flags.push((sym::_Self, Some("{integral}".to_owned()))); } if let ty::Array(aty, len) = self_ty.sty { - flags.push(("_Self".to_owned(), Some("[]".to_owned()))); - flags.push(("_Self".to_owned(), Some(format!("[{}]", aty)))); + flags.push((sym::_Self, Some("[]".to_owned()))); + flags.push((sym::_Self, Some(format!("[{}]", aty)))); if let Some(def) = aty.ty_adt_def() { // We also want to be able to select the array's type's original // signature with no type arguments resolved flags.push(( - "_Self".to_owned(), + sym::_Self, Some(format!("[{}]", self.tcx.type_of(def.did).to_string())), )); let tcx = self.tcx; if let Some(len) = len.assert_usize(tcx) { flags.push(( - "_Self".to_owned(), + sym::_Self, Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)), )); } else { flags.push(( - "_Self".to_owned(), + sym::_Self, Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())), )); } diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs index 14b968c83b2..b78396c90dc 100644 --- a/src/librustc/traits/on_unimplemented.rs +++ b/src/librustc/traits/on_unimplemented.rs @@ -7,7 +7,7 @@ use crate::util::nodemap::FxHashMap; use syntax::ast::{MetaItem, NestedMetaItem}; use syntax::attr; -use syntax::symbol::sym; +use syntax::symbol::{Symbol, kw, sym}; use syntax_pos::Span; use syntax_pos::symbol::LocalInternedString; @@ -167,7 +167,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { pub fn evaluate(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, trait_ref: ty::TraitRef<'tcx>, - options: &[(String, Option)]) + options: &[(Symbol, Option)]) -> OnUnimplementedNote { let mut message = None; @@ -180,7 +180,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { if !attr::eval_condition(condition, &tcx.sess.parse_sess, &mut |c| { c.ident().map_or(false, |ident| { options.contains(&( - ident.to_string(), + ident.name, c.value_str().map(|s| s.as_str().to_string()) )) }) @@ -203,8 +203,8 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { } } - let options: FxHashMap = options.into_iter() - .filter_map(|(k, v)| v.as_ref().map(|v| (k.to_owned(), v.to_owned()))) + let options: FxHashMap = options.into_iter() + .filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))) .collect(); OnUnimplementedNote { label: label.map(|l| l.format(tcx, trait_ref, &options)), @@ -241,16 +241,16 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { Piece::String(_) => (), // Normal string, no need to check it Piece::NextArgument(a) => match a.position { // `{Self}` is allowed - Position::ArgumentNamed(s) if s == "Self" => (), + Position::ArgumentNamed(s) if s == kw::SelfUpper => (), // `{ThisTraitsName}` is allowed - Position::ArgumentNamed(s) if s == name.as_str() => (), + Position::ArgumentNamed(s) if s == name => (), // `{from_method}` is allowed - Position::ArgumentNamed(s) if s == "from_method" => (), + Position::ArgumentNamed(s) if s == sym::from_method => (), // `{from_desugaring}` is allowed - Position::ArgumentNamed(s) if s == "from_desugaring" => (), + Position::ArgumentNamed(s) if s == sym::from_desugaring => (), // So is `{A}` if A is a type parameter Position::ArgumentNamed(s) => match generics.params.iter().find(|param| { - param.name.as_str() == s + param.name.as_symbol() == s }) { Some(_) => (), None => { @@ -276,7 +276,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { &self, tcx: TyCtxt<'a, 'gcx, 'tcx>, trait_ref: ty::TraitRef<'tcx>, - options: &FxHashMap, + options: &FxHashMap, ) -> String { let name = tcx.item_name(trait_ref.def_id); let trait_str = tcx.def_path_str(trait_ref.def_id); @@ -289,9 +289,9 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { }, GenericParamDefKind::Lifetime => return None }; - let name = param.name.to_string(); + let name = param.name.as_symbol(); Some((name, value)) - }).collect::>(); + }).collect::>(); let empty_string = String::new(); let parser = Parser::new(&self.0, None, vec![], false); @@ -299,15 +299,15 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { match p { Piece::String(s) => s, Piece::NextArgument(a) => match a.position { - Position::ArgumentNamed(s) => match generic_map.get(s) { + Position::ArgumentNamed(s) => match generic_map.get(&s) { Some(val) => val, - None if s == name.as_str() => { + None if s == name => { &trait_str } None => { - if let Some(val) = options.get(s) { + if let Some(val) = options.get(&s) { val - } else if s == "from_desugaring" || s == "from_method" { + } else if s == sym::from_desugaring || s == sym::from_method { // don't break messages using these two arguments incorrectly &empty_string } else { diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 377164728f4..2863daa13a9 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -28,7 +28,7 @@ enum ArgumentType { enum Position { Exact(usize), - Named(String), + Named(Symbol), } struct Context<'a, 'b: 'a> { @@ -57,7 +57,7 @@ struct Context<'a, 'b: 'a> { /// Unique format specs seen for each argument. arg_unique_types: Vec>, /// Map from named arguments to their resolved indices. - names: FxHashMap, + names: FxHashMap, /// The latest consecutive literal strings, or empty if there weren't any. literal: String, @@ -127,9 +127,9 @@ fn parse_args<'a>( ecx: &mut ExtCtxt<'a>, sp: Span, tts: &[tokenstream::TokenTree] -) -> Result<(P, Vec>, FxHashMap), DiagnosticBuilder<'a>> { +) -> Result<(P, Vec>, FxHashMap), DiagnosticBuilder<'a>> { let mut args = Vec::>::new(); - let mut names = FxHashMap::::default(); + let mut names = FxHashMap::::default(); let mut p = ecx.new_parser_from_tts(tts); @@ -158,11 +158,10 @@ fn parse_args<'a>( "expected ident, positional arguments cannot follow named arguments", )); }; - let name: &str = &name.as_str(); p.expect(&token::Eq)?; let e = p.parse_expr()?; - if let Some(prev) = names.get(name) { + if let Some(prev) = names.get(&name) { ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", name)) .span_note(args[*prev].span, "previously here") .emit(); @@ -174,7 +173,7 @@ fn parse_args<'a>( // if the input is valid, we can simply append to the positional // args. And remember the names. let slot = args.len(); - names.insert(name.to_string(), slot); + names.insert(name, slot); args.push(e); } else { let e = p.parse_expr()?; @@ -188,7 +187,7 @@ impl<'a, 'b> Context<'a, 'b> { fn resolve_name_inplace(&self, p: &mut parse::Piece<'_>) { // NOTE: the `unwrap_or` branch is needed in case of invalid format // arguments, e.g., `format_args!("{foo}")`. - let lookup = |s| *self.names.get(s).unwrap_or(&0); + let lookup = |s: Symbol| *self.names.get(&s).unwrap_or(&0); match *p { parse::String(_) => {} @@ -222,7 +221,7 @@ impl<'a, 'b> Context<'a, 'b> { // it's written second, so it should come after width/precision. let pos = match arg.position { parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => Exact(i), - parse::ArgumentNamed(s) => Named(s.to_string()), + parse::ArgumentNamed(s) => Named(s), }; let ty = Placeholder(arg.format.ty.to_string()); @@ -232,7 +231,7 @@ impl<'a, 'b> Context<'a, 'b> { } } - fn verify_count(&mut self, c: parse::Count<'_>) { + fn verify_count(&mut self, c: parse::Count) { match c { parse::CountImplied | parse::CountIs(..) => {} @@ -240,7 +239,7 @@ impl<'a, 'b> Context<'a, 'b> { self.verify_arg_type(Exact(i), Count); } parse::CountIsName(s) => { - self.verify_arg_type(Named(s.to_string()), Count); + self.verify_arg_type(Named(s), Count); } } } @@ -390,7 +389,7 @@ impl<'a, 'b> Context<'a, 'b> { ecx.std_path(&[sym::fmt, sym::rt, sym::v1, Symbol::intern(s)]) } - fn build_count(&self, c: parse::Count<'_>) -> P { + fn build_count(&self, c: parse::Count) -> P { let sp = self.macsp; let count = |c, arg| { let mut path = Context::rtpath(self.ecx, "Count"); @@ -739,7 +738,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt<'_>, sp: Span, efmt: P, args: Vec>, - names: FxHashMap, + names: FxHashMap, append_newline: bool) -> P { // NOTE: this verbose way of initializing `Vec>` is because diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 302b3c75263..95d74ce054e 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -203,6 +203,7 @@ symbols! { core_intrinsics, crate_id, crate_in_paths, + crate_local, crate_name, crate_type, crate_visibility_modifier, @@ -221,6 +222,7 @@ symbols! { deref, deref_mut, derive, + direct, doc, doc_alias, doc_cfg, @@ -278,8 +280,10 @@ symbols! { format_args_nl, from, From, + from_desugaring, from_error, from_generator, + from_method, from_ok, from_usize, fundamental, @@ -443,6 +447,7 @@ symbols! { panic_impl, panic_implementation, panic_runtime, + parent_trait, partial_cmp, PartialOrd, passes, @@ -569,6 +574,7 @@ symbols! { __rust_unstable_column, rvalue_static_promotion, sanitizer_runtime, + _Self, self_in_typedefs, self_struct_ctor, Send, From a8594400927c7363d24625ea1521b89c344ec03d Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 6 Jun 2019 16:49:51 -0600 Subject: [PATCH 13/21] Shift padding out of suggestions for format strings --- src/libsyntax_ext/format.rs | 8 ++++---- src/libsyntax_ext/format_foreign.rs | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 2863daa13a9..1fdc2e6274a 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -1043,7 +1043,9 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt<'_>, let mut show_doc_note = false; let mut suggestions = vec![]; - for sub in foreign::$kind::iter_subs(fmt_str) { + // account for `"` and account for raw strings `r#` + let padding = str_style.map(|i| i + 2).unwrap_or(1); + for sub in foreign::$kind::iter_subs(fmt_str, padding) { let trn = match sub.translate() { Some(trn) => trn, @@ -1064,9 +1066,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt<'_>, } if let Some((start, end)) = pos { - // account for `"` and account for raw strings `r#` - let padding = str_style.map(|i| i + 2).unwrap_or(1); - let sp = fmt_sp.from_inner_byte_pos(start + padding, end + padding); + let sp = fmt_sp.from_inner_byte_pos(start, end); suggestions.push((sp, trn)); } else { diag.help(&format!("`{}` should be written as `{}`", sub, trn)); diff --git a/src/libsyntax_ext/format_foreign.rs b/src/libsyntax_ext/format_foreign.rs index 261b2f373ce..b279dbced84 100644 --- a/src/libsyntax_ext/format_foreign.rs +++ b/src/libsyntax_ext/format_foreign.rs @@ -263,10 +263,10 @@ pub mod printf { } /// Returns an iterator over all substitutions in a given string. - pub fn iter_subs(s: &str) -> Substitutions<'_> { + pub fn iter_subs(s: &str, start_pos: usize) -> Substitutions<'_> { Substitutions { s, - pos: 0, + pos: start_pos, } } @@ -711,7 +711,7 @@ pub mod printf { #[test] fn test_iter() { let s = "The %d'th word %% is: `%.*s` %!\n"; - let subs: Vec<_> = iter_subs(s).map(|sub| sub.translate()).collect(); + let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate()).collect(); assert_eq!( subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::>(), vec![Some("{}"), None, Some("{:.*}"), None] @@ -804,10 +804,10 @@ pub mod shell { } /// Returns an iterator over all substitutions in a given string. - pub fn iter_subs(s: &str) -> Substitutions<'_> { + pub fn iter_subs(s: &str, start_pos: usize) -> Substitutions<'_> { Substitutions { s, - pos: 0, + pos: start_pos, } } @@ -940,7 +940,7 @@ pub mod shell { fn test_iter() { use super::iter_subs; let s = "The $0'th word $$ is: `$WORD` $!\n"; - let subs: Vec<_> = iter_subs(s).map(|sub| sub.translate()).collect(); + let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate()).collect(); assert_eq!( subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::>(), vec![Some("{0}"), None, Some("{WORD}")] From b1c357e0c366f5fb865151a9dd144413b4bf6911 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 4 Jun 2019 09:03:43 -0600 Subject: [PATCH 14/21] Introduce InnerSpan abstraction This should be used when trying to get at subsets of a larger span, especially when the larger span is not available in the code attempting to work with those subsets (especially common in the fmt_macros crate). This is usually a good replacement for (BytePos, BytePos) and (usize, usize) tuples. This commit also removes from_inner_byte_pos, since it took usize arguments, which is error prone. --- src/libfmt_macros/lib.rs | 89 +++++++++---------- .../passes/check_code_block_syntax.rs | 4 +- src/librustdoc/passes/mod.rs | 6 +- src/libsyntax_ext/format.rs | 14 ++- src/libsyntax_ext/format_foreign.rs | 26 +++--- src/libsyntax_pos/lib.rs | 18 +++- 6 files changed, 82 insertions(+), 75 deletions(-) diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 9d6720810b8..66355801b6c 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -24,7 +24,16 @@ use std::str; use std::string; use std::iter; -use syntax_pos::Symbol; +use syntax_pos::{InnerSpan, Symbol}; + +#[derive(Copy, Clone)] +struct InnerOffset(usize); + +impl InnerOffset { + fn to(self, end: InnerOffset) -> InnerSpan { + InnerSpan::new(self.0, end.0) + } +} /// A piece is a portion of the format string which represents the next part /// to emit. These are emitted as a stream by the `Parser` class. @@ -136,9 +145,8 @@ pub struct ParseError { pub description: string::String, pub note: Option, pub label: string::String, - pub start: SpanIndex, - pub end: SpanIndex, - pub secondary_label: Option<(string::String, SpanIndex, SpanIndex)>, + pub span: InnerSpan, + pub secondary_label: Option<(string::String, InnerSpan)>, } /// The parser structure for interpreting the input format string. This is @@ -157,24 +165,15 @@ pub struct Parser<'a> { /// `Some(raw count)` when the string is "raw", used to position spans correctly style: Option, /// Start and end byte offset of every successfully parsed argument - pub arg_places: Vec<(SpanIndex, SpanIndex)>, + pub arg_places: Vec, /// Characters that need to be shifted skips: Vec, - /// Span offset of the last opening brace seen, used for error reporting - last_opening_brace_pos: Option, + /// Span of the last opening brace seen, used for error reporting + last_opening_brace: Option, /// Wether the source string is comes from `println!` as opposed to `format!` or `print!` append_newline: bool, } -#[derive(Clone, Copy, Debug)] -pub struct SpanIndex(pub usize); - -impl SpanIndex { - pub fn unwrap(self) -> usize { - self.0 - } -} - impl<'a> Iterator for Parser<'a> { type Item = Piece<'a>; @@ -182,19 +181,20 @@ impl<'a> Iterator for Parser<'a> { if let Some(&(pos, c)) = self.cur.peek() { match c { '{' => { - let curr_last_brace = self.last_opening_brace_pos; - self.last_opening_brace_pos = Some(self.to_span_index(pos)); + let curr_last_brace = self.last_opening_brace; + let byte_pos = self.to_span_index(pos); + self.last_opening_brace = Some(byte_pos.to(byte_pos)); self.cur.next(); if self.consume('{') { - self.last_opening_brace_pos = curr_last_brace; + self.last_opening_brace = curr_last_brace; Some(String(self.string(pos + 1))) } else { let arg = self.argument(); - if let Some(arg_pos) = self.must_consume('}').map(|end| { - (self.to_span_index(pos), self.to_span_index(end + 1)) - }) { - self.arg_places.push(arg_pos); + if let Some(end) = self.must_consume('}') { + let start = self.to_span_index(pos); + let end = self.to_span_index(end + 1); + self.arg_places.push(start.to(end)); } Some(NextArgument(arg)) } @@ -209,8 +209,7 @@ impl<'a> Iterator for Parser<'a> { "unmatched `}` found", "unmatched `}`", "if you intended to print `}`, you can escape it using `}}`", - err_pos, - err_pos, + err_pos.to(err_pos), ); None } @@ -242,7 +241,7 @@ impl<'a> Parser<'a> { style, arg_places: vec![], skips, - last_opening_brace_pos: None, + last_opening_brace: None, append_newline, } } @@ -254,15 +253,13 @@ impl<'a> Parser<'a> { &mut self, description: S1, label: S2, - start: SpanIndex, - end: SpanIndex, + span: InnerSpan, ) { self.errors.push(ParseError { description: description.into(), note: None, label: label.into(), - start, - end, + span, secondary_label: None, }); } @@ -275,15 +272,13 @@ impl<'a> Parser<'a> { description: S1, label: S2, note: S3, - start: SpanIndex, - end: SpanIndex, + span: InnerSpan, ) { self.errors.push(ParseError { description: description.into(), note: Some(note.into()), label: label.into(), - start, - end, + span, secondary_label: None, }); } @@ -304,7 +299,7 @@ impl<'a> Parser<'a> { } } - fn to_span_index(&self, pos: usize) -> SpanIndex { + fn to_span_index(&self, pos: usize) -> InnerOffset { let mut pos = pos; let raw = self.style.map(|raw| raw + 1).unwrap_or(0); for skip in &self.skips { @@ -316,7 +311,7 @@ impl<'a> Parser<'a> { break; } } - SpanIndex(raw + pos + 1) + InnerOffset(raw + pos + 1) } /// Forces consumption of the specified character. If the character is not @@ -334,8 +329,8 @@ impl<'a> Parser<'a> { let label = "expected `}`".to_owned(); let (note, secondary_label) = if c == '}' { (Some("if you intended to print `{`, you can escape it using `{{`".to_owned()), - self.last_opening_brace_pos.map(|pos| { - ("because of this opening brace".to_owned(), pos, pos) + self.last_opening_brace.map(|sp| { + ("because of this opening brace".to_owned(), sp) })) } else { (None, None) @@ -344,8 +339,7 @@ impl<'a> Parser<'a> { description, note, label, - start: pos, - end: pos, + span: pos.to(pos), secondary_label, }); None @@ -359,8 +353,8 @@ impl<'a> Parser<'a> { let label = format!("expected `{:?}`", c); let (note, secondary_label) = if c == '}' { (Some("if you intended to print `{`, you can escape it using `{{`".to_owned()), - self.last_opening_brace_pos.map(|pos| { - ("because of this opening brace".to_owned(), pos, pos) + self.last_opening_brace.map(|sp| { + ("because of this opening brace".to_owned(), sp) })) } else { (None, None) @@ -369,12 +363,11 @@ impl<'a> Parser<'a> { description, note, label, - start: pos, - end: pos, + span: pos.to(pos), secondary_label, }); } else { - self.err(description, format!("expected `{:?}`", c), pos, pos); + self.err(description, format!("expected `{:?}`", c), pos.to(pos)); } None } @@ -446,8 +439,10 @@ impl<'a> Parser<'a> { self.err_with_note(format!("invalid argument name `{}`", invalid_name), "invalid argument name", "argument names cannot start with an underscore", - self.to_span_index(pos), - self.to_span_index(pos + invalid_name.len())); + self.to_span_index(pos).to( + self.to_span_index(pos + invalid_name.len()) + ), + ); Some(ArgumentNamed(Symbol::intern(invalid_name))) }, diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index 694843ad7f7..6d51278b4e5 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -2,7 +2,7 @@ use errors::Applicability; use syntax::parse::lexer::{StringReader as Lexer}; use syntax::parse::{ParseSess, token}; use syntax::source_map::FilePathMapping; -use syntax_pos::FileName; +use syntax_pos::{InnerSpan, FileName}; use crate::clean; use crate::core::DocContext; @@ -63,7 +63,7 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { } if code_block.syntax.is_none() && code_block.is_fenced { - let sp = sp.from_inner_byte_pos(0, 3); + let sp = sp.from_inner(InnerSpan::new(0, 3)); diag.span_suggestion( sp, "mark blocks that do not contain Rust code as text", diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 018ab5dea60..8fc6b9fdbe6 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -6,7 +6,7 @@ use rustc::lint as lint; use rustc::middle::privacy::AccessLevels; use rustc::util::nodemap::DefIdSet; use std::mem; -use syntax_pos::{DUMMY_SP, Span}; +use syntax_pos::{DUMMY_SP, InnerSpan, Span}; use std::ops::Range; use crate::clean::{self, GetDefId, Item}; @@ -440,10 +440,10 @@ crate fn source_span_for_markdown_range( } } - let sp = span_of_attrs(attrs).from_inner_byte_pos( + let sp = span_of_attrs(attrs).from_inner(InnerSpan::new( md_range.start + start_bytes, md_range.end + start_bytes + end_bytes, - ); + )); Some(sp) } diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 1fdc2e6274a..85b524786b2 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -900,15 +900,15 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt<'_>, if !parser.errors.is_empty() { let err = parser.errors.remove(0); - let sp = fmt.span.from_inner_byte_pos(err.start.unwrap(), err.end.unwrap()); + let sp = fmt.span.from_inner(err.span); let mut e = ecx.struct_span_err(sp, &format!("invalid format string: {}", err.description)); e.span_label(sp, err.label + " in format string"); if let Some(note) = err.note { e.note(¬e); } - if let Some((label, start, end)) = err.secondary_label { - let sp = fmt.span.from_inner_byte_pos(start.unwrap(), end.unwrap()); + if let Some((label, span)) = err.secondary_label { + let sp = fmt.span.from_inner(span); e.span_label(sp, label); } e.emit(); @@ -916,9 +916,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt<'_>, } let arg_spans = parser.arg_places.iter() - .map(|&(parse::SpanIndex(start), parse::SpanIndex(end))| { - fmt.span.from_inner_byte_pos(start, end) - }) + .map(|span| fmt.span.from_inner(*span)) .collect(); let mut cx = Context { @@ -1065,8 +1063,8 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt<'_>, show_doc_note = true; } - if let Some((start, end)) = pos { - let sp = fmt_sp.from_inner_byte_pos(start, end); + if let Some(inner_sp) = pos { + let sp = fmt_sp.from_inner(inner_sp); suggestions.push((sp, trn)); } else { diag.help(&format!("`{}` should be written as `{}`", sub, trn)); diff --git a/src/libsyntax_ext/format_foreign.rs b/src/libsyntax_ext/format_foreign.rs index b279dbced84..7ad5997bf2c 100644 --- a/src/libsyntax_ext/format_foreign.rs +++ b/src/libsyntax_ext/format_foreign.rs @@ -1,5 +1,6 @@ pub mod printf { use super::strcursor::StrCursor as Cur; + use syntax_pos::InnerSpan; /// Represents a single `printf`-style substitution. #[derive(Clone, PartialEq, Debug)] @@ -18,7 +19,7 @@ pub mod printf { } } - pub fn position(&self) -> Option<(usize, usize)> { + pub fn position(&self) -> Option { match *self { Substitution::Format(ref fmt) => Some(fmt.position), _ => None, @@ -28,7 +29,7 @@ pub mod printf { pub fn set_position(&mut self, start: usize, end: usize) { match self { Substitution::Format(ref mut fmt) => { - fmt.position = (start, end); + fmt.position = InnerSpan::new(start, end); } _ => {} } @@ -65,7 +66,7 @@ pub mod printf { /// Type of parameter being converted. pub type_: &'a str, /// Byte offset for the start and end of this formatting directive. - pub position: (usize, usize), + pub position: InnerSpan, } impl Format<'_> { @@ -282,9 +283,9 @@ pub mod printf { let (mut sub, tail) = parse_next_substitution(self.s)?; self.s = tail; match sub { - Substitution::Format(_) => if let Some((start, end)) = sub.position() { - sub.set_position(start + self.pos, end + self.pos); - self.pos += end; + Substitution::Format(_) => if let Some(inner_span) = sub.position() { + sub.set_position(inner_span.start + self.pos, inner_span.end + self.pos); + self.pos += inner_span.end; } Substitution::Escape => self.pos += 2, } @@ -373,7 +374,7 @@ pub mod printf { precision: None, length: None, type_: at.slice_between(next).unwrap(), - position: (start.at, next.at), + position: InnerSpan::new(start.at, next.at), }), next.slice_after() )); @@ -560,7 +561,7 @@ pub mod printf { drop(next); end = at; - let position = (start.at, end.at); + let position = InnerSpan::new(start.at, end.at); let f = Format { span: start.slice_between(end).unwrap(), @@ -650,7 +651,7 @@ pub mod printf { precision: $prec, length: $len, type_: $type_, - position: $pos, + position: syntax_pos::InnerSpan::new($pos.0, $pos.1), }), "!" )) @@ -761,6 +762,7 @@ pub mod printf { pub mod shell { use super::strcursor::StrCursor as Cur; + use syntax_pos::InnerSpan; #[derive(Clone, PartialEq, Debug)] pub enum Substitution<'a> { @@ -778,11 +780,11 @@ pub mod shell { } } - pub fn position(&self) -> Option<(usize, usize)> { + pub fn position(&self) -> Option { match self { Substitution::Ordinal(_, pos) | Substitution::Name(_, pos) | - Substitution::Escape(pos) => Some(*pos), + Substitution::Escape(pos) => Some(InnerSpan::new(pos.0, pos.1)), } } @@ -823,7 +825,7 @@ pub mod shell { match parse_next_substitution(self.s) { Some((mut sub, tail)) => { self.s = tail; - if let Some((start, end)) = sub.position() { + if let Some(InnerSpan { start, end }) = sub.position() { sub.set_position(start + self.pos, end + self.pos); self.pos += end; } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 8f5595968a7..bf0ab5fae4e 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -504,10 +504,10 @@ impl Span { ) } - pub fn from_inner_byte_pos(self, start: usize, end: usize) -> Span { + pub fn from_inner(self, inner: InnerSpan) -> Span { let span = self.data(); - Span::new(span.lo + BytePos::from_usize(start), - span.lo + BytePos::from_usize(end), + Span::new(span.lo + BytePos::from_usize(inner.start), + span.lo + BytePos::from_usize(inner.end), span.ctxt) } @@ -1395,6 +1395,18 @@ pub struct MalformedSourceMapPositions { pub end_pos: BytePos } +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct InnerSpan { + pub start: usize, + pub end: usize, +} + +impl InnerSpan { + pub fn new(start: usize, end: usize) -> InnerSpan { + InnerSpan { start, end } + } +} + // Given a slice of line start positions and a position, returns the index of // the line the position is on. Returns -1 if the position is located before // the first line. From 6b9740bf0217ce88d0c2370e955a3c6372d39041 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 6 Jun 2019 18:38:34 -0600 Subject: [PATCH 15/21] Add comment about raw strings to self.style --- src/libfmt_macros/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 66355801b6c..520cc870859 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -301,6 +301,8 @@ impl<'a> Parser<'a> { fn to_span_index(&self, pos: usize) -> InnerOffset { let mut pos = pos; + // This handles the raw string case, the raw argument is the number of # + // in r###"..."### (we need to add one because of the `r`). let raw = self.style.map(|raw| raw + 1).unwrap_or(0); for skip in &self.skips { if pos > *skip { From 45df52f2cca9bee04690f476f4a3f791ea1b04cc Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 6 Jun 2019 19:31:24 -0600 Subject: [PATCH 16/21] Properly point at the last opening brace --- src/libfmt_macros/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 520cc870859..b851183debf 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -183,7 +183,7 @@ impl<'a> Iterator for Parser<'a> { '{' => { let curr_last_brace = self.last_opening_brace; let byte_pos = self.to_span_index(pos); - self.last_opening_brace = Some(byte_pos.to(byte_pos)); + self.last_opening_brace = Some(byte_pos.to(InnerOffset(byte_pos.0 + 1))); self.cur.next(); if self.consume('{') { self.last_opening_brace = curr_last_brace; From 8590074a01364c2263f6e3c3c42e4137e2f77b65 Mon Sep 17 00:00:00 2001 From: Adrian Friedli Date: Sun, 9 Jun 2019 22:45:11 +0200 Subject: [PATCH 17/21] implement nth_back for RangeInclusive --- src/libcore/iter/range.rs | 28 ++++++++++++++++++++++++++++ src/libcore/tests/iter.rs | 20 ++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index e171108a146..efda3b263cc 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -451,6 +451,34 @@ impl DoubleEndedIterator for ops::RangeInclusive { }) } + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + self.compute_is_empty(); + if self.is_empty.unwrap_or_default() { + return None; + } + + if let Some(minus_n) = self.end.sub_usize(n) { + use crate::cmp::Ordering::*; + + match minus_n.partial_cmp(&self.start) { + Some(Greater) => { + self.is_empty = Some(false); + self.end = minus_n.sub_one(); + return Some(minus_n); + } + Some(Equal) => { + self.is_empty = Some(true); + return Some(minus_n); + } + _ => {} + } + } + + self.is_empty = Some(true); + None + } + #[inline] fn try_rfold(&mut self, init: B, mut f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 171a33695bc..020618ae7ae 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1731,6 +1731,26 @@ fn test_range_inclusive_nth() { assert_eq!(ExactSizeIterator::is_empty(&r), true); } +#[test] +fn test_range_inclusive_nth_back() { + assert_eq!((10..=15).nth_back(0), Some(15)); + assert_eq!((10..=15).nth_back(1), Some(14)); + assert_eq!((10..=15).nth_back(5), Some(10)); + assert_eq!((10..=15).nth_back(6), None); + assert_eq!((-120..=80_i8).nth_back(200), Some(-120)); + + let mut r = 10_u8..=20; + assert_eq!(r.nth_back(2), Some(18)); + assert_eq!(r, 10..=17); + assert_eq!(r.nth_back(2), Some(15)); + assert_eq!(r, 10..=14); + assert_eq!(r.is_empty(), false); + assert_eq!(ExactSizeIterator::is_empty(&r), false); + assert_eq!(r.nth_back(10), None); + assert_eq!(r.is_empty(), true); + assert_eq!(ExactSizeIterator::is_empty(&r), true); +} + #[test] fn test_range_step() { #![allow(deprecated)] From 715578ea5769ccf21696fe64eed6971b19c1787c Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Sun, 9 Jun 2019 16:53:46 -0700 Subject: [PATCH 18/21] Pass cflags rather than cxxflags to LLVM as CMAKE_C_FLAGS We mistakenly pass cxxflags from the configuration to LLVM build as CMAKE_C_FLAGS. --- src/bootstrap/native.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index bf3601cb312..8b6e856a8ab 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -416,7 +416,7 @@ fn configure_cmake(builder: &Builder<'_>, cfg.build_arg("-j").build_arg(builder.jobs().to_string()); let mut cflags = builder.cflags(target, GitRepo::Llvm).join(" "); - if let Some(ref s) = builder.config.llvm_cxxflags { + if let Some(ref s) = builder.config.llvm_cflags { cflags.push_str(&format!(" {}", s)); } cfg.define("CMAKE_C_FLAGS", cflags); From 7d3211339b4b76cf7177cf6b48c9e2c97cfae003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Tue, 11 Jun 2019 11:49:38 +0200 Subject: [PATCH 19/21] Migrate rust-by-example to MdBook2 --- src/bootstrap/doc.rs | 2 +- src/doc/rust-by-example | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 2a3577a3d20..278ae8a9add 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -64,7 +64,7 @@ book!( EmbeddedBook, "src/doc/embedded-book", "embedded-book", RustbookVersion::MdBook2; Nomicon, "src/doc/nomicon", "nomicon", RustbookVersion::MdBook2; Reference, "src/doc/reference", "reference", RustbookVersion::MdBook1; - RustByExample, "src/doc/rust-by-example", "rust-by-example", RustbookVersion::MdBook1; + RustByExample, "src/doc/rust-by-example", "rust-by-example", RustbookVersion::MdBook2; RustcBook, "src/doc/rustc", "rustc", RustbookVersion::MdBook1; RustdocBook, "src/doc/rustdoc", "rustdoc", RustbookVersion::MdBook2; ); diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 18566f4dedc..d8eec1dd654 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 18566f4dedc3ef5bf61f5f85685d5966db99cc11 +Subproject commit d8eec1dd65470b9a68e80ac1cba8fad0daac4916 From f2c37a55a4456c4af8b3b3b53cdd4f703a910b29 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 7 Jun 2019 11:30:11 -0700 Subject: [PATCH 20/21] ci: Collect CPU usage statistics on Azure This commit adds a script which we'll execute on Azure Pipelines which is intended to run in the background and passively collect CPU usage statistics for our builders. The intention here is that we can use this information over time to diagnose issues with builders, see where we can optimize our build, fix parallelism issues, etc. This might not end up being too useful in the long run but it's data we've wanted to collect for quite some time now, so here's a stab at it! Comments about how this is intended to work can be found in the python script used here to collect CPU usage statistics. Closes #48828 --- .azure-pipelines/steps/run.yml | 16 +++ src/ci/cpu-usage-over-time.py | 175 +++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) create mode 100644 src/ci/cpu-usage-over-time.py diff --git a/.azure-pipelines/steps/run.yml b/.azure-pipelines/steps/run.yml index cfa28a6a1d7..38aa022b624 100644 --- a/.azure-pipelines/steps/run.yml +++ b/.azure-pipelines/steps/run.yml @@ -11,6 +11,12 @@ steps: - checkout: self fetchDepth: 2 +# Spawn a background process to collect CPU usage statistics which we'll upload +# at the end of the build. See the comments in the script here for more +# information. +- bash: python src/ci/cpu-usage-over-time.py &> cpu-usage.csv & + displayName: "Collect CPU-usage statistics in the background" + - bash: printenv | sort displayName: Show environment variables @@ -136,3 +142,13 @@ steps: AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY) condition: and(succeeded(), or(eq(variables.DEPLOY, '1'), eq(variables.DEPLOY_ALT, '1'))) displayName: Upload artifacts + +# Upload CPU usage statistics that we've been gathering this whole time. Always +# execute this step in case we want to inspect failed builds, but don't let +# errors here ever fail the build since this is just informational. +- bash: aws s3 cp --acl public-read cpu-usage.csv s3://$DEPLOY_BUCKET/rustc-builds/$BUILD_SOURCEVERSION/cpu-$SYSTEM_JOBNAME.csv + env: + AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY) + condition: contains(variables, 'AWS_SECRET_ACCESS_KEY') + continueOnError: true + displayName: Upload CPU usage statistics diff --git a/src/ci/cpu-usage-over-time.py b/src/ci/cpu-usage-over-time.py new file mode 100644 index 00000000000..78427a6360a --- /dev/null +++ b/src/ci/cpu-usage-over-time.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python +# ignore-tidy-linelength + +# This is a small script that we use on CI to collect CPU usage statistics of +# our builders. By seeing graphs of CPU usage over time we hope to correlate +# that with possible improvements to Rust's own build system, ideally diagnosing +# that either builders are always fully using their CPU resources or they're +# idle for long stretches of time. +# +# This script is relatively simple, but it's platform specific. Each platform +# (OSX/Windows/Linux) has a different way of calculating the current state of +# CPU at a point in time. We then compare two captured states to determine the +# percentage of time spent in one state versus another. The state capturing is +# all platform-specific but the loop at the bottom is the cross platform part +# that executes everywhere. +# +# # Viewing statistics +# +# All builders will upload their CPU statistics as CSV files to our S3 buckets. +# These URLS look like: +# +# https://$bucket.s3.amazonaws.com/rustc-builds/$commit/cpu-$builder.csv +# +# for example +# +# https://rust-lang-ci2.s3.amazonaws.com/rustc-builds/68baada19cd5340f05f0db15a3e16d6671609bcc/cpu-x86_64-apple.csv +# +# Each CSV file has two columns. The first is the timestamp of the measurement +# and the second column is the % of idle cpu time in that time slice. Ideally +# the second column is always zero. +# +# Once you've downloaded a file there's various ways to plot it and visualize +# it. For command line usage you can use a script like so: +# +# set timefmt '%Y-%m-%dT%H:%M:%S' +# set xdata time +# set ylabel "Idle CPU %" +# set xlabel "Time" +# set datafile sep ',' +# set term png +# set output "printme.png" +# set grid +# builder = "i686-apple" +# plot "cpu-".builder.".csv" using 1:2 with lines title builder +# +# Executed as `gnuplot < ./foo.plot` it will generate a graph called +# `printme.png` which you can then open up. If you know how to improve this +# script or the viewing process that would be much appreciated :) (or even if +# you know how to automate it!) + +import datetime +import sys +import time + +if sys.platform == 'linux2': + class State: + def __init__(self): + with open('/proc/stat', 'r') as file: + data = file.readline().split() + if data[0] != 'cpu': + raise Exception('did not start with "cpu"') + self.user = int(data[1]) + self.nice = int(data[2]) + self.system = int(data[3]) + self.idle = int(data[4]) + self.iowait = int(data[5]) + self.irq = int(data[6]) + self.softirq = int(data[7]) + self.steal = int(data[8]) + self.guest = int(data[9]) + self.guest_nice = int(data[10]) + + def idle_since(self, prev): + user = self.user - prev.user + nice = self.nice - prev.nice + system = self.system - prev.system + idle = self.idle - prev.idle + iowait = self.iowait - prev.iowait + irq = self.irq - prev.irq + softirq = self.softirq - prev.softirq + steal = self.steal - prev.steal + guest = self.guest - prev.guest + guest_nice = self.guest_nice - prev.guest_nice + total = user + nice + system + idle + iowait + irq + softirq + steal + guest + guest_nice + return float(idle) / float(total) * 100 + +elif sys.platform == 'win32': + from ctypes.wintypes import DWORD + from ctypes import Structure, windll, WinError, GetLastError, byref + + class FILETIME(Structure): + _fields_ = [ + ("dwLowDateTime", DWORD), + ("dwHighDateTime", DWORD), + ] + + class State: + def __init__(self): + idle, kernel, user = FILETIME(), FILETIME(), FILETIME() + + success = windll.kernel32.GetSystemTimes( + byref(idle), + byref(kernel), + byref(user), + ) + + assert success, WinError(GetLastError())[1] + + self.idle = (idle.dwHighDateTime << 32) | idle.dwLowDateTime + self.kernel = (kernel.dwHighDateTime << 32) | kernel.dwLowDateTime + self.user = (user.dwHighDateTime << 32) | user.dwLowDateTime + + def idle_since(self, prev): + idle = self.idle - prev.idle + user = self.user - prev.user + kernel = self.kernel - prev.kernel + return float(idle) / float(user + kernel) * 100 + +elif sys.platform == 'darwin': + from ctypes import * + libc = cdll.LoadLibrary('/usr/lib/libc.dylib') + + PROESSOR_CPU_LOAD_INFO = c_int(2) + CPU_STATE_USER = 0 + CPU_STATE_SYSTEM = 1 + CPU_STATE_IDLE = 2 + CPU_STATE_NICE = 3 + c_int_p = POINTER(c_int) + + class State: + def __init__(self): + num_cpus_u = c_uint(0) + cpu_info = c_int_p() + cpu_info_cnt = c_int(0) + err = libc.host_processor_info( + libc.mach_host_self(), + PROESSOR_CPU_LOAD_INFO, + byref(num_cpus_u), + byref(cpu_info), + byref(cpu_info_cnt), + ) + assert err == 0 + self.user = 0 + self.system = 0 + self.idle = 0 + self.nice = 0 + cur = 0 + while cur < cpu_info_cnt.value: + self.user += cpu_info[cur + CPU_STATE_USER] + self.system += cpu_info[cur + CPU_STATE_SYSTEM] + self.idle += cpu_info[cur + CPU_STATE_IDLE] + self.nice += cpu_info[cur + CPU_STATE_NICE] + cur += num_cpus_u.value + + def idle_since(self, prev): + user = self.user - prev.user + system = self.system - prev.system + idle = self.idle - prev.idle + nice = self.nice - prev.nice + return float(idle) / float(user + system + idle + nice) * 100.0 + +else: + print('unknown platform', sys.platform) + sys.exit(1) + +cur_state = State(); +print("Time,Idle") +while True: + time.sleep(1); + next_state = State(); + now = datetime.datetime.utcnow().isoformat() + idle = next_state.idle_since(cur_state) + print("%s,%s" % (now, idle)) + sys.stdout.flush() + cur_state = next_state From 87d5fe0e5361df9f0e198dad807c8201b6cb4ea3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 12:53:47 +0200 Subject: [PATCH 21/21] is_fp and is_floating_point do the same thing, remove the former also consistently mark all these is_* methods for inlining --- src/librustc/ty/sty.rs | 39 ++++++++++++++++++++------ src/librustc_codegen_ssa/mir/rvalue.rs | 4 +-- src/librustc_typeck/check/mod.rs | 2 +- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 5cc46b21fca..6a1f603f222 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1665,6 +1665,7 @@ impl RegionKind { /// Type utilities impl<'a, 'gcx, 'tcx> TyS<'tcx> { + #[inline] pub fn is_unit(&self) -> bool { match self.sty { Tuple(ref tys) => tys.is_empty(), @@ -1672,6 +1673,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_never(&self) -> bool { match self.sty { Never => true, @@ -1726,6 +1728,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_primitive(&self) -> bool { match self.sty { Bool | Char | Int(_) | Uint(_) | Float(_) => true, @@ -1741,6 +1744,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_ty_infer(&self) -> bool { match self.sty { Infer(_) => true, @@ -1748,6 +1752,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_phantom_data(&self) -> bool { if let Adt(def, _) = self.sty { def.is_phantom_data() @@ -1756,8 +1761,10 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_bool(&self) -> bool { self.sty == Bool } + #[inline] pub fn is_param(&self, index: u32) -> bool { match self.sty { ty::Param(ref data) => data.index == index, @@ -1765,6 +1772,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_self(&self) -> bool { match self.sty { Param(ref p) => p.is_self(), @@ -1772,6 +1780,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_slice(&self) -> bool { match self.sty { RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => match ty.sty { @@ -1814,6 +1823,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_region_ptr(&self) -> bool { match self.sty { Ref(..) => true, @@ -1821,6 +1831,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_mutable_pointer(&self) -> bool { match self.sty { RawPtr(TypeAndMut { mutbl: hir::Mutability::MutMutable, .. }) | @@ -1829,6 +1840,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_unsafe_ptr(&self) -> bool { match self.sty { RawPtr(_) => return true, @@ -1837,6 +1849,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } /// Returns `true` if this type is an `Arc`. + #[inline] pub fn is_arc(&self) -> bool { match self.sty { Adt(def, _) => def.is_arc(), @@ -1845,6 +1858,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } /// Returns `true` if this type is an `Rc`. + #[inline] pub fn is_rc(&self) -> bool { match self.sty { Adt(def, _) => def.is_rc(), @@ -1852,6 +1866,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_box(&self) -> bool { match self.sty { Adt(def, _) => def.is_box(), @@ -1870,6 +1885,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { /// A scalar type is one that denotes an atomic datum, with no sub-components. /// (A RawPtr is scalar because it represents a non-managed pointer, so its /// contents are abstract to rustc.) + #[inline] pub fn is_scalar(&self) -> bool { match self.sty { Bool | Char | Int(_) | Float(_) | Uint(_) | @@ -1880,6 +1896,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } /// Returns `true` if this type is a floating point type. + #[inline] pub fn is_floating_point(&self) -> bool { match self.sty { Float(_) | @@ -1888,6 +1905,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_trait(&self) -> bool { match self.sty { Dynamic(..) => true, @@ -1895,6 +1913,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_enum(&self) -> bool { match self.sty { Adt(adt_def, _) => { @@ -1904,6 +1923,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_closure(&self) -> bool { match self.sty { Closure(..) => true, @@ -1911,6 +1931,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_generator(&self) -> bool { match self.sty { Generator(..) => true, @@ -1926,6 +1947,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_fresh_ty(&self) -> bool { match self.sty { Infer(FreshTy(_)) => true, @@ -1933,6 +1955,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_fresh(&self) -> bool { match self.sty { Infer(FreshTy(_)) => true, @@ -1942,6 +1965,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_char(&self) -> bool { match self.sty { Char => true, @@ -1950,17 +1974,11 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } #[inline] - pub fn is_fp(&self) -> bool { - match self.sty { - Infer(FloatVar(_)) | Float(_) => true, - _ => false - } - } - pub fn is_numeric(&self) -> bool { - self.is_integral() || self.is_fp() + self.is_integral() || self.is_floating_point() } + #[inline] pub fn is_signed(&self) -> bool { match self.sty { Int(_) => true, @@ -1968,6 +1986,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_pointer_sized(&self) -> bool { match self.sty { Int(ast::IntTy::Isize) | Uint(ast::UintTy::Usize) => true, @@ -1975,6 +1994,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_machine(&self) -> bool { match self.sty { Int(..) | Uint(..) | Float(..) => true, @@ -1982,6 +2002,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn has_concrete_skeleton(&self) -> bool { match self.sty { Param(_) | Infer(_) | Error => false, @@ -2028,6 +2049,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_fn(&self) -> bool { match self.sty { FnDef(..) | FnPtr(_) => true, @@ -2043,6 +2065,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + #[inline] pub fn is_impl_trait(&self) -> bool { match self.sty { Opaque(..) => true, diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index 7a2bd18df4e..87e15ba6aac 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -429,7 +429,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::UnaryOp(op, ref operand) => { let operand = self.codegen_operand(&mut bx, operand); let lloperand = operand.immediate(); - let is_float = operand.layout.ty.is_fp(); + let is_float = operand.layout.ty.is_floating_point(); let llval = match op { mir::UnOp::Not => bx.not(lloperand), mir::UnOp::Neg => if is_float { @@ -536,7 +536,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { rhs: Bx::Value, input_ty: Ty<'tcx>, ) -> Bx::Value { - let is_float = input_ty.is_fp(); + let is_float = input_ty.is_floating_point(); let is_signed = input_ty.is_signed(); let is_unit = input_ty.is_unit(); match op { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2e53b380cb7..7f4234c5f26 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4089,7 +4089,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::UnNeg => { let result = self.check_user_unop(expr, oprnd_t, unop); // If it's builtin, we can reuse the type, this helps inference. - if !(oprnd_t.is_integral() || oprnd_t.is_fp()) { + if !oprnd_t.is_numeric() { oprnd_t = result; } }