From bde225e2fafc7f593cfa5a9e1e6c750264682b71 Mon Sep 17 00:00:00 2001 From: Jakub Bukaj Date: Tue, 18 Nov 2014 17:39:16 +0100 Subject: Feature gate non-ASCII lifetime identifiers Fixes #19069. --- src/libsyntax/ast_map/mod.rs | 2 +- src/libsyntax/ast_util.rs | 2 +- src/libsyntax/feature_gate.rs | 4 ++-- src/libsyntax/visit.rs | 26 +++++++++++++++++++------- 4 files changed, 23 insertions(+), 11 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index b116c84552e..472331bc9e1 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -866,7 +866,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { self.insert(lifetime.id, NodeLifetime(lifetime)); } - fn visit_lifetime_decl(&mut self, def: &'ast LifetimeDef) { + fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) { self.visit_lifetime_ref(&def.lifetime); } } diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 30cdecbc851..043e79bffd9 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -535,7 +535,7 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { self.operation.visit_id(lifetime.id); } - fn visit_lifetime_decl(&mut self, def: &'v LifetimeDef) { + fn visit_lifetime_def(&mut self, def: &'v LifetimeDef) { self.visit_lifetime_ref(&def.lifetime); } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ebdcf278934..460a94a8d5a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -141,8 +141,8 @@ impl<'a> Context<'a> { } impl<'a, 'v> Visitor<'v> for Context<'a> { - fn visit_ident(&mut self, sp: Span, id: ast::Ident) { - if !token::get_ident(id).get().is_ascii() { + fn visit_name(&mut self, sp: Span, name: ast::Name) { + if !token::get_name(name).get().is_ascii() { self.gate_feature("non_ascii_idents", sp, "non-ascii idents are not fully supported."); } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index efe1e18eda9..e98cc3b9c71 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -55,8 +55,11 @@ pub enum FnKind<'a> { /// new default implementation gets introduced.) pub trait Visitor<'v> { - fn visit_ident(&mut self, _sp: Span, _ident: Ident) { - /*! Visit the idents */ + fn visit_name(&mut self, _span: Span, _name: Name) { + // Nothing to do. + } + fn visit_ident(&mut self, span: Span, ident: Ident) { + self.visit_name(span, ident.name); } fn visit_mod(&mut self, m: &'v Mod, _s: Span, _n: NodeId) { walk_mod(self, m) } fn visit_view_item(&mut self, i: &'v ViewItem) { walk_view_item(self, i) } @@ -102,11 +105,11 @@ pub trait Visitor<'v> { None => () } } - fn visit_lifetime_ref(&mut self, _lifetime: &'v Lifetime) { - /*! Visits a reference to a lifetime */ + fn visit_lifetime_ref(&mut self, lifetime: &'v Lifetime) { + self.visit_name(lifetime.span, lifetime.name) } - fn visit_lifetime_decl(&mut self, _lifetime: &'v LifetimeDef) { - /*! Visits a declaration of a lifetime */ + fn visit_lifetime_def(&mut self, lifetime: &'v LifetimeDef) { + walk_lifetime_def(self, lifetime) } fn visit_explicit_self(&mut self, es: &'v ExplicitSelf) { walk_explicit_self(self, es) @@ -207,6 +210,14 @@ pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) { walk_expr_opt(visitor, &local.init); } +pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, + lifetime_def: &'v LifetimeDef) { + visitor.visit_lifetime_ref(&lifetime_def.lifetime); + for bound in lifetime_def.bounds.iter() { + visitor.visit_lifetime_ref(bound); + } +} + pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V, explicit_self: &'v ExplicitSelf) { match explicit_self.node { @@ -424,7 +435,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { pub fn walk_lifetime_decls_helper<'v, V: Visitor<'v>>(visitor: &mut V, lifetimes: &'v Vec) { for l in lifetimes.iter() { - visitor.visit_lifetime_decl(l); + visitor.visit_lifetime_def(l); } } @@ -555,6 +566,7 @@ pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) { for type_parameter in generics.ty_params.iter() { + visitor.visit_ident(type_parameter.span, type_parameter.ident); walk_ty_param_bounds_helper(visitor, &type_parameter.bounds); match type_parameter.default { Some(ref ty) => visitor.visit_ty(&**ty), -- cgit 1.4.1-3-g733a5 From ad61ff4b817f8581ea4c12f897f5e6baafe27952 Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Tue, 18 Nov 2014 14:02:40 -0800 Subject: deriving: error out when used on a non-type Besides being more helpful, this gives us the flexibility to later define a meaning for something like #[deriving(...)] mod bar { ... } --- src/libsyntax/ext/deriving/generic/mod.rs | 7 ++++-- src/test/compile-fail/deriving-non-type.rs | 40 ++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/deriving-non-type.rs (limited to 'src/libsyntax') diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index dccc12e406b..eec3805721a 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -335,7 +335,7 @@ pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>) impl<'a> TraitDef<'a> { pub fn expand(&self, cx: &mut ExtCtxt, - _mitem: &ast::MetaItem, + mitem: &ast::MetaItem, item: &ast::Item, push: |P|) { let newitem = match item.node { @@ -351,7 +351,10 @@ impl<'a> TraitDef<'a> { item.ident, generics) } - _ => return + _ => { + cx.span_err(mitem.span, "`deriving` may only be applied to structs and enums"); + return; + } }; // Keep the lint attributes of the previous item to control how the // generated implementations are linted diff --git a/src/test/compile-fail/deriving-non-type.rs b/src/test/compile-fail/deriving-non-type.rs new file mode 100644 index 00000000000..8226bba42b0 --- /dev/null +++ b/src/test/compile-fail/deriving-non-type.rs @@ -0,0 +1,40 @@ +// Copyright 2014 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. + +#![allow(dead_code)] + +struct S; + +#[deriving(PartialEq)] //~ ERROR: `deriving` may only be applied to structs and enums +trait T { } + +#[deriving(PartialEq)] //~ ERROR: `deriving` may only be applied to structs and enums +impl S { } + +#[deriving(PartialEq)] //~ ERROR: `deriving` may only be applied to structs and enums +impl T for S { } + +#[deriving(PartialEq)] //~ ERROR: `deriving` may only be applied to structs and enums +static s: uint = 0u; + +#[deriving(PartialEq)] //~ ERROR: `deriving` may only be applied to structs and enums +const c: uint = 0u; + +#[deriving(PartialEq)] //~ ERROR: `deriving` may only be applied to structs and enums +mod m { } + +#[deriving(PartialEq)] //~ ERROR: `deriving` may only be applied to structs and enums +extern "C" { } + +#[deriving(PartialEq)] //~ ERROR: `deriving` may only be applied to structs and enums +type A = uint; + +#[deriving(PartialEq)] //~ ERROR: `deriving` may only be applied to structs and enums +fn main() { } -- cgit 1.4.1-3-g733a5 From 5b5638f6863803477d56e200d6a9a208015838c1 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 19 Nov 2014 10:17:40 +1100 Subject: Switch to an independent enum for `Lit*` subtokens. --- src/grammar/verify.rs | 50 +++++++++++++++++++------------------ src/librustdoc/html/highlight.rs | 7 +++--- src/libsyntax/ast.rs | 2 +- src/libsyntax/diagnostics/plugin.rs | 2 +- src/libsyntax/ext/quote.rs | 37 ++++++++++++++------------- src/libsyntax/parse/lexer/mod.rs | 41 +++++++++++++++--------------- src/libsyntax/parse/parser.rs | 28 ++++++++++----------- src/libsyntax/parse/token.rs | 42 +++++++++++++------------------ src/libsyntax/print/pprust.rs | 24 +++++++++--------- 9 files changed, 115 insertions(+), 118 deletions(-) (limited to 'src/libsyntax') diff --git a/src/grammar/verify.rs b/src/grammar/verify.rs index 159a62f0110..84a288ef042 100644 --- a/src/grammar/verify.rs +++ b/src/grammar/verify.rs @@ -61,7 +61,7 @@ fn parse_token_list(file: &str) -> HashMap { "SHL" => token::BinOp(token::Shl), "LBRACE" => token::OpenDelim(token::Brace), "RARROW" => token::Rarrow, - "LIT_STR" => token::LitStr(Name(0)), + "LIT_STR" => token::Literal(token::Str_(Name(0))), "DOTDOT" => token::DotDot, "MOD_SEP" => token::ModSep, "DOTDOTDOT" => token::DotDotDot, @@ -71,7 +71,7 @@ fn parse_token_list(file: &str) -> HashMap { "ANDAND" => token::AndAnd, "AT" => token::At, "LBRACKET" => token::OpenDelim(token::Bracket), - "LIT_STR_RAW" => token::LitStrRaw(Name(0), 0), + "LIT_STR_RAW" => token::Literal(token::StrRaw(Name(0), 0)), "RPAREN" => token::CloseDelim(token::Paren), "SLASH" => token::BinOp(token::Slash), "COMMA" => token::Comma, @@ -80,8 +80,8 @@ fn parse_token_list(file: &str) -> HashMap { "TILDE" => token::Tilde, "IDENT" => token::Id(), "PLUS" => token::BinOp(token::Plus), - "LIT_CHAR" => token::LitChar(Name(0)), - "LIT_BYTE" => token::LitByte(Name(0)), + "LIT_CHAR" => token::Literal(token::Char(Name(0))), + "LIT_BYTE" => token::Literal(token::Byte(Name(0))), "EQ" => token::Eq, "RBRACKET" => token::CloseDelim(token::Bracket), "COMMENT" => token::Comment, @@ -95,9 +95,9 @@ fn parse_token_list(file: &str) -> HashMap { "BINOP" => token::BinOp(token::Plus), "POUND" => token::Pound, "OROR" => token::OrOr, - "LIT_INTEGER" => token::LitInteger(Name(0)), + "LIT_INTEGER" => token::Literal(token::Integer(Name(0))), "BINOPEQ" => token::BinOpEq(token::Plus), - "LIT_FLOAT" => token::LitFloat(Name(0)), + "LIT_FLOAT" => token::Literal(token::Float(Name(0))), "WHITESPACE" => token::Whitespace, "UNDERSCORE" => token::Underscore, "MINUS" => token::BinOp(token::Minus), @@ -107,8 +107,8 @@ fn parse_token_list(file: &str) -> HashMap { "OR" => token::BinOp(token::Or), "GT" => token::Gt, "LE" => token::Le, - "LIT_BINARY" => token::LitBinary(Name(0)), - "LIT_BINARY_RAW" => token::LitBinaryRaw(Name(0), 0), + "LIT_BINARY" => token::Literal(token::Binary(Name(0))), + "LIT_BINARY_RAW" => token::Literal(token::BinaryRaw(Name(0), 0)), _ => continue, }; @@ -189,15 +189,17 @@ fn parse_antlr_token(s: &str, tokens: &HashMap) -> TokenAndSpan { token::BinOp(..) => token::BinOp(str_to_binop(content)), token::BinOpEq(..) => token::BinOpEq(str_to_binop(content.slice_to( content.len() - 1))), - token::LitStr(..) => token::LitStr(fix(content)), - token::LitStrRaw(..) => token::LitStrRaw(fix(content), count(content)), - token::LitChar(..) => token::LitChar(fixchar(content)), - token::LitByte(..) => token::LitByte(fixchar(content)), + token::Literal(token::Str_(..)) => token::Literal(token::Str_(fix(content))), + token::Literal(token::StrRaw(..)) => token::Literal(token::StrRaw(fix(content), + count(content))), + token::Literal(token::Char(..)) => token::Literal(token::Char(fixchar(content))), + token::Literal(token::Byte(..)) => token::Literal(token::Byte(fixchar(content))), token::DocComment(..) => token::DocComment(nm), - token::LitInteger(..) => token::LitInteger(nm), - token::LitFloat(..) => token::LitFloat(nm), - token::LitBinary(..) => token::LitBinary(nm), - token::LitBinaryRaw(..) => token::LitBinaryRaw(fix(content), count(content)), + token::Literal(token::Integer(..)) => token::Literal(token::Integer(nm)), + token::Literal(token::Float(..)) => token::Literal(token::Float(nm)), + token::Literal(token::Binary(..)) => token::Literal(token::Binary(nm)), + token::Literal(token::BinaryRaw(..)) => token::Literal(token::BinaryRaw(fix(content), + count(content))), token::Ident(..) => token::Ident(ast::Ident { name: nm, ctxt: 0 }, token::ModName), token::Lifetime(..) => token::Lifetime(ast::Ident { name: nm, ctxt: 0 }), @@ -284,14 +286,14 @@ fn main() { ) matches!( - LitByte(..), - LitChar(..), - LitInteger(..), - LitFloat(..), - LitStr(..), - LitStrRaw(..), - LitBinary(..), - LitBinaryRaw(..), + token::Literal(token::Byte(..)), + token::Literal(token::Char(..)), + token::Literal(token::Integer(..)), + token::Literal(token::Float(..)), + token::Literal(token::Str_(..)), + token::Literal(token::StrRaw(..)), + token::Literal(token::Binary(..)), + token::Literal(token::BinaryRaw(..)), Ident(..), Lifetime(..), Interpolated(..), diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index d445da9d134..527ef553d99 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -129,11 +129,12 @@ fn doit(sess: &parse::ParseSess, mut lexer: lexer::StringReader, } // text literals - token::LitByte(..) | token::LitBinary(..) | token::LitBinaryRaw(..) | - token::LitChar(..) | token::LitStr(..) | token::LitStrRaw(..) => "string", + token::Literal(token::Byte(..)) | token::Literal(token::Char(..)) | + token::Literal(token::Binary(..)) | token::Literal(token::BinaryRaw(..)) | + token::Literal(token::Str_(..)) | token::Literal(token::StrRaw(..)) => "string", // number literals - token::LitInteger(..) | token::LitFloat(..) => "number", + token::Literal(token::Integer(..)) | token::Literal(token::Float(..)) => "number", // keywords are also included in the identifier set token::Ident(ident, _is_mod_sep) => { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 15e14902727..2158bdb416c 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -838,7 +838,7 @@ impl TokenTree { tts: vec![TtToken(sp, token::Ident(token::str_to_ident("doc"), token::Plain)), TtToken(sp, token::Eq), - TtToken(sp, token::LitStr(name))], + TtToken(sp, token::Literal(token::Str_(name)))], close_span: sp, })) } diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index d077fbd7bf0..b928fc778e8 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -87,7 +87,7 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt, }, [ast::TtToken(_, token::Ident(ref code, _)), ast::TtToken(_, token::Comma), - ast::TtToken(_, token::LitStrRaw(description, _))] => { + ast::TtToken(_, token::Literal(token::StrRaw(description, _)))] => { (code, Some(description)) } _ => unreachable!() diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index ec691757077..ec51ce00605 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -542,6 +542,13 @@ fn mk_delim(cx: &ExtCtxt, sp: Span, delim: token::DelimToken) -> P { #[allow(non_upper_case_globals)] fn mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P { + macro_rules! mk_lit { + ($name: expr, $($args: expr),*) => {{ + let inner = cx.expr_call(sp, mk_token_path(cx, sp, $name), vec![$($args),*]); + + cx.expr_call(sp, mk_token_path(cx, sp, "Literal"), vec![inner]) + }} + } match *tok { token::BinOp(binop) => { return cx.expr_call(sp, mk_token_path(cx, sp, "BinOp"), vec!(mk_binop(cx, sp, binop))); @@ -560,38 +567,32 @@ fn mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P { vec![mk_delim(cx, sp, delim)]); } - token::LitByte(i) => { + token::Literal(token::Byte(i)) => { let e_byte = mk_name(cx, sp, i.ident()); - - return cx.expr_call(sp, mk_token_path(cx, sp, "LitByte"), vec!(e_byte)); + return mk_lit!("Byte", e_byte); } - token::LitChar(i) => { + token::Literal(token::Char(i)) => { let e_char = mk_name(cx, sp, i.ident()); - - return cx.expr_call(sp, mk_token_path(cx, sp, "LitChar"), vec!(e_char)); + return mk_lit!("Char", e_char); } - token::LitInteger(i) => { + token::Literal(token::Integer(i)) => { let e_int = mk_name(cx, sp, i.ident()); - return cx.expr_call(sp, mk_token_path(cx, sp, "LitInteger"), vec!(e_int)); + return mk_lit!("Integer", e_int); } - token::LitFloat(fident) => { + token::Literal(token::Float(fident)) => { let e_fident = mk_name(cx, sp, fident.ident()); - return cx.expr_call(sp, mk_token_path(cx, sp, "LitFloat"), vec!(e_fident)); + return mk_lit!("Float", e_fident); } - token::LitStr(ident) => { - return cx.expr_call(sp, - mk_token_path(cx, sp, "LitStr"), - vec!(mk_name(cx, sp, ident.ident()))); + token::Literal(token::Str_(ident)) => { + return mk_lit!("Str_", mk_name(cx, sp, ident.ident())) } - token::LitStrRaw(ident, n) => { - return cx.expr_call(sp, - mk_token_path(cx, sp, "LitStrRaw"), - vec!(mk_name(cx, sp, ident.ident()), cx.expr_uint(sp, n))); + token::Literal(token::StrRaw(ident, n)) => { + return mk_lit!("StrRaw", mk_name(cx, sp, ident.ident()), cx.expr_uint(sp, n)) } token::Ident(ident, style) => { diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 01a66243a96..b7598c7c428 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -655,17 +655,17 @@ impl<'a> StringReader<'a> { } 'u' | 'i' => { self.scan_int_suffix(); - return token::LitInteger(self.name_from(start_bpos)); + return token::Literal(token::Integer(self.name_from(start_bpos))); }, 'f' => { let last_pos = self.last_pos; self.scan_float_suffix(); self.check_float_base(start_bpos, last_pos, base); - return token::LitFloat(self.name_from(start_bpos)); + return token::Literal(token::Float(self.name_from(start_bpos))); } _ => { // just a 0 - return token::LitInteger(self.name_from(start_bpos)); + return token::Literal(token::Integer(self.name_from(start_bpos))); } } } else if c.is_digit_radix(10) { @@ -678,7 +678,7 @@ impl<'a> StringReader<'a> { self.err_span_(start_bpos, self.last_pos, "no valid digits found for number"); // eat any suffix self.scan_int_suffix(); - return token::LitInteger(token::intern("0")); + return token::Literal(token::Integer(token::intern("0"))); } // might be a float, but don't be greedy if this is actually an @@ -696,13 +696,13 @@ impl<'a> StringReader<'a> { } let last_pos = self.last_pos; self.check_float_base(start_bpos, last_pos, base); - return token::LitFloat(self.name_from(start_bpos)); + return token::Literal(token::Float(self.name_from(start_bpos))); } else if self.curr_is('f') { // or it might be an integer literal suffixed as a float self.scan_float_suffix(); let last_pos = self.last_pos; self.check_float_base(start_bpos, last_pos, base); - return token::LitFloat(self.name_from(start_bpos)); + return token::Literal(token::Float(self.name_from(start_bpos))); } else { // it might be a float if it has an exponent if self.curr_is('e') || self.curr_is('E') { @@ -710,11 +710,11 @@ impl<'a> StringReader<'a> { self.scan_float_suffix(); let last_pos = self.last_pos; self.check_float_base(start_bpos, last_pos, base); - return token::LitFloat(self.name_from(start_bpos)); + return token::Literal(token::Float(self.name_from(start_bpos))); } // but we certainly have an integer! self.scan_int_suffix(); - return token::LitInteger(self.name_from(start_bpos)); + return token::Literal(token::Integer(self.name_from(start_bpos))); } } @@ -1126,7 +1126,7 @@ impl<'a> StringReader<'a> { } let id = if valid { self.name_from(start) } else { token::intern("0") }; self.bump(); // advance curr past token - return token::LitChar(id); + return token::Literal(token::Char(id)); } 'b' => { self.bump(); @@ -1157,7 +1157,7 @@ impl<'a> StringReader<'a> { let id = if valid { self.name_from(start_bpos + BytePos(1)) } else { token::intern("??") }; self.bump(); - return token::LitStr(id); + return token::Literal(token::Str_(id)); } 'r' => { let start_bpos = self.last_pos; @@ -1224,7 +1224,7 @@ impl<'a> StringReader<'a> { } else { token::intern("??") }; - return token::LitStrRaw(id, hash_count); + return token::Literal(token::StrRaw(id, hash_count)); } '-' => { if self.nextch_is('>') { @@ -1314,7 +1314,7 @@ impl<'a> StringReader<'a> { let id = if valid { self.name_from(start) } else { token::intern("??") }; self.bump(); // advance curr past token - return token::LitByte(id); + return token::Literal(token::Byte(id)); } fn scan_byte_string(&mut self) -> token::Token { @@ -1336,7 +1336,7 @@ impl<'a> StringReader<'a> { } let id = if valid { self.name_from(start) } else { token::intern("??") }; self.bump(); - return token::LitBinary(id); + return token::Literal(token::Binary(id)); } fn scan_raw_byte_string(&mut self) -> token::Token { @@ -1387,8 +1387,9 @@ impl<'a> StringReader<'a> { self.bump(); } self.bump(); - return token::LitBinaryRaw(self.name_from_to(content_start_bpos, content_end_bpos), - hash_count); + return token::Literal(token::BinaryRaw(self.name_from_to(content_start_bpos, + content_end_bpos), + hash_count)); } } @@ -1535,17 +1536,17 @@ mod test { #[test] fn character_a() { assert_eq!(setup(&mk_sh(), "'a'".to_string()).next_token().tok, - token::LitChar(token::intern("a"))); + token::Literal(token::Char(token::intern("a")))); } #[test] fn character_space() { assert_eq!(setup(&mk_sh(), "' '".to_string()).next_token().tok, - token::LitChar(token::intern(" "))); + token::Literal(token::Char(token::intern(" ")))); } #[test] fn character_escaped() { assert_eq!(setup(&mk_sh(), "'\\n'".to_string()).next_token().tok, - token::LitChar(token::intern("\\n"))); + token::Literal(token::Char(token::intern("\\n")))); } #[test] fn lifetime_name() { @@ -1557,7 +1558,7 @@ mod test { assert_eq!(setup(&mk_sh(), "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token() .tok, - token::LitStrRaw(token::intern("\"#a\\b\x00c\""), 3)); + token::Literal(token::StrRaw(token::intern("\"#a\\b\x00c\""), 3))); } #[test] fn line_doc_comments() { @@ -1573,7 +1574,7 @@ mod test { token::Comment => { }, _ => panic!("expected a comment!") } - assert_eq!(lexer.next_token().tok, token::LitChar(token::intern("a"))); + assert_eq!(lexer.next_token().tok, token::Literal(token::Char(token::intern("a")))); } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 40c4ac9f8c0..4edcb182e53 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1640,23 +1640,23 @@ impl<'a> Parser<'a> { /// Matches token_lit = LIT_INTEGER | ... pub fn lit_from_token(&mut self, tok: &token::Token) -> Lit_ { match *tok { - token::LitByte(i) => LitByte(parse::byte_lit(i.as_str()).val0()), - token::LitChar(i) => LitChar(parse::char_lit(i.as_str()).val0()), - token::LitInteger(s) => parse::integer_lit(s.as_str(), + token::Literal(token::Byte(i)) => LitByte(parse::byte_lit(i.as_str()).val0()), + token::Literal(token::Char(i)) => LitChar(parse::char_lit(i.as_str()).val0()), + token::Literal(token::Integer(s)) => parse::integer_lit(s.as_str(), &self.sess.span_diagnostic, self.last_span), - token::LitFloat(s) => parse::float_lit(s.as_str()), - token::LitStr(s) => { + token::Literal(token::Float(s)) => parse::float_lit(s.as_str()), + token::Literal(token::Str_(s)) => { LitStr(token::intern_and_get_ident(parse::str_lit(s.as_str()).as_slice()), ast::CookedStr) } - token::LitStrRaw(s, n) => { + token::Literal(token::StrRaw(s, n)) => { LitStr(token::intern_and_get_ident(parse::raw_str_lit(s.as_str()).as_slice()), ast::RawStr(n)) } - token::LitBinary(i) => + token::Literal(token::Binary(i)) => LitBinary(parse::binary_lit(i.as_str())), - token::LitBinaryRaw(i, _) => + token::Literal(token::BinaryRaw(i, _)) => LitBinary(Rc::new(i.as_str().as_bytes().iter().map(|&x| x).collect())), _ => { self.unexpected_last(tok); } } @@ -2424,7 +2424,7 @@ impl<'a> Parser<'a> { } } } - token::LitInteger(n) => { + token::Literal(token::Integer(n)) => { let index = n.as_str(); let dot = self.last_span.hi; hi = self.span.hi; @@ -2449,7 +2449,7 @@ impl<'a> Parser<'a> { } } } - token::LitFloat(n) => { + token::Literal(token::Float(n)) => { self.bump(); let last_span = self.last_span; let fstr = n.as_str(); @@ -5085,7 +5085,7 @@ impl<'a> Parser<'a> { self.expect(&token::Semi); (path, the_ident) }, - token::LitStr(..) | token::LitStrRaw(..) => { + token::Literal(token::Str_(..)) | token::Literal(token::StrRaw(..)) => { let path = self.parse_str(); self.expect_keyword(keywords::As); let the_ident = self.parse_ident(); @@ -5267,7 +5267,7 @@ impl<'a> Parser<'a> { /// the `extern` keyword, if one is found. fn parse_opt_abi(&mut self) -> Option { match self.token { - token::LitStr(s) | token::LitStrRaw(s, _) => { + token::Literal(token::Str_(s)) | token::Literal(token::StrRaw(s, _)) => { self.bump(); let the_string = s.as_str(); match abi::lookup(the_string) { @@ -5904,8 +5904,8 @@ impl<'a> Parser<'a> { pub fn parse_optional_str(&mut self) -> Option<(InternedString, ast::StrStyle)> { let (s, style) = match self.token { - token::LitStr(s) => (self.id_to_interned_str(s.ident()), ast::CookedStr), - token::LitStrRaw(s, n) => { + token::Literal(token::Str_(s)) => (self.id_to_interned_str(s.ident()), ast::CookedStr), + token::Literal(token::StrRaw(s, n)) => { (self.id_to_interned_str(s.ident()), ast::RawStr(n)) } _ => return None diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 298328d73ef..bfa6ca798b2 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -12,6 +12,7 @@ pub use self::BinOpToken::*; pub use self::Nonterminal::*; pub use self::DelimToken::*; pub use self::IdentStyle::*; +pub use self::Lit::*; pub use self::Token::*; use ast; @@ -59,6 +60,18 @@ pub enum IdentStyle { Plain, } +#[deriving(Clone, Encodable, Decodable, PartialEq, Eq, Hash, Show)] +pub enum Lit { + Byte(ast::Name), + Char(ast::Name), + Integer(ast::Name), + Float(ast::Name), + Str_(ast::Name), + StrRaw(ast::Name, uint), /* raw str delimited by n hash symbols */ + Binary(ast::Name), + BinaryRaw(ast::Name, uint), /* raw binary str delimited by n hash symbols */ +} + #[allow(non_camel_case_types)] #[deriving(Clone, Encodable, Decodable, PartialEq, Eq, Hash, Show)] pub enum Token { @@ -98,14 +111,7 @@ pub enum Token { CloseDelim(DelimToken), /* Literals */ - LitByte(ast::Name), - LitChar(ast::Name), - LitInteger(ast::Name), - LitFloat(ast::Name), - LitStr(ast::Name), - LitStrRaw(ast::Name, uint), /* raw str delimited by n hash symbols */ - LitBinary(ast::Name), - LitBinaryRaw(ast::Name, uint), /* raw binary str delimited by n hash symbols */ + Literal(Lit), /* Name components */ Ident(ast::Ident, IdentStyle), @@ -145,14 +151,7 @@ impl Token { Ident(_, _) => true, Underscore => true, Tilde => true, - LitByte(_) => true, - LitChar(_) => true, - LitInteger(_) => true, - LitFloat(_) => true, - LitStr(_) => true, - LitStrRaw(_, _) => true, - LitBinary(_) => true, - LitBinaryRaw(_, _) => true, + Literal(_) => true, Pound => true, At => true, Not => true, @@ -173,15 +172,8 @@ impl Token { /// Returns `true` if the token is any literal pub fn is_lit(&self) -> bool { match *self { - LitByte(_) => true, - LitChar(_) => true, - LitInteger(_) => true, - LitFloat(_) => true, - LitStr(_) => true, - LitStrRaw(_, _) => true, - LitBinary(_) => true, - LitBinaryRaw(_, _) => true, - _ => false, + Literal(_) => true, + _ => false, } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index e6e0c33a42d..7997c1ba4ef 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -236,18 +236,18 @@ pub fn token_to_string(tok: &Token) -> String { token::Question => "?".into_string(), /* Literals */ - token::LitByte(b) => format!("b'{}'", b.as_str()), - token::LitChar(c) => format!("'{}'", c.as_str()), - token::LitFloat(c) => c.as_str().into_string(), - token::LitInteger(c) => c.as_str().into_string(), - token::LitStr(s) => format!("\"{}\"", s.as_str()), - token::LitStrRaw(s, n) => format!("r{delim}\"{string}\"{delim}", - delim="#".repeat(n), - string=s.as_str()), - token::LitBinary(v) => format!("b\"{}\"", v.as_str()), - token::LitBinaryRaw(s, n) => format!("br{delim}\"{string}\"{delim}", - delim="#".repeat(n), - string=s.as_str()), + token::Literal(token::Byte(b)) => format!("b'{}'", b.as_str()), + token::Literal(token::Char(c)) => format!("'{}'", c.as_str()), + token::Literal(token::Float(c)) => c.as_str().into_string(), + token::Literal(token::Integer(c)) => c.as_str().into_string(), + token::Literal(token::Str_(s)) => format!("\"{}\"", s.as_str()), + token::Literal(token::StrRaw(s, n)) => format!("r{delim}\"{string}\"{delim}", + delim="#".repeat(n), + string=s.as_str()), + token::Literal(token::Binary(v)) => format!("b\"{}\"", v.as_str()), + token::Literal(token::BinaryRaw(s, n)) => format!("br{delim}\"{string}\"{delim}", + delim="#".repeat(n), + string=s.as_str()), /* Name components */ token::Ident(s, _) => token::get_ident(s).get().into_string(), -- cgit 1.4.1-3-g733a5 From 4af3494bb02e80badc978faa65e59625ade0c675 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 17 Nov 2014 11:29:38 -0800 Subject: std: Stabilize std::fmt This commit applies the stabilization of std::fmt as outlined in [RFC 380][rfc]. There are a number of breaking changes as a part of this commit which will need to be handled to migrated old code: * A number of formatting traits have been removed: String, Bool, Char, Unsigned, Signed, and Float. It is recommended to instead use Show wherever possible or to use adaptor structs to implement other methods of formatting. * The format specifier for Boolean has changed from `t` to `b`. * The enum `FormatError` has been renamed to `Error` as well as becoming a unit struct instead of an enum. The `WriteError` variant no longer exists. * The `format_args_method!` macro has been removed with no replacement. Alter code to use the `format_args!` macro instead. * The public fields of a `Formatter` have become read-only with no replacement. Use a new formatting string to alter the formatting flags in combination with the `write!` macro. The fields can be accessed through accessor methods on the `Formatter` structure. Other than these breaking changes, the contents of std::fmt should now also all contain stability markers. Most of them are still #[unstable] or #[experimental] [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0380-stabilize-std-fmt.md [breaking-change] Closes #18904 --- src/libcore/fmt/mod.rs | 149 ++++++++++++-------------- src/libcore/fmt/num.rs | 5 +- src/libcore/fmt/rt.rs | 2 + src/libcore/macros.rs | 15 +-- src/libcoretest/fmt/num.rs | 81 +++++++------- src/libflate/lib.rs | 2 +- src/libgraphviz/lib.rs | 4 +- src/liblog/lib.rs | 7 -- src/librand/lib.rs | 2 +- src/librustc/middle/borrowck/mod.rs | 2 +- src/librustc/middle/cfg/graphviz.rs | 2 +- src/librustc/middle/check_match.rs | 3 +- src/librustc/middle/dataflow.rs | 30 +++--- src/librustc/middle/graph.rs | 4 +- src/librustc/middle/ty.rs | 5 + src/librustc/middle/typeck/variance.rs | 2 +- src/librustc_trans/back/write.rs | 2 +- src/librustc_trans/driver/mod.rs | 10 +- src/librustc_trans/driver/pretty.rs | 4 +- src/librustc_trans/trans/base.rs | 2 +- src/librustc_trans/trans/cleanup.rs | 2 +- src/librustdoc/html/item_type.rs | 6 -- src/librustdoc/html/render.rs | 10 +- src/librustdoc/lib.rs | 4 +- src/libserialize/json.rs | 2 +- src/libstd/fmt.rs | 39 +++---- src/libstd/io/mod.rs | 12 +-- src/libstd/macros.rs | 8 +- src/libsyntax/ast.rs | 2 +- src/libsyntax/ext/base.rs | 3 - src/libsyntax/ext/deriving/generic/mod.rs | 2 +- src/libsyntax/ext/format.rs | 22 +--- src/libsyntax/ext/mtwt.rs | 2 +- src/libterm/terminfo/parm.rs | 4 +- src/libtest/lib.rs | 4 +- src/libtime/lib.rs | 38 +++---- src/test/bench/core-set.rs | 2 +- src/test/bench/noise.rs | 2 +- src/test/bench/shootout-k-nucleotide-pipes.rs | 2 +- src/test/bench/shootout-k-nucleotide.rs | 2 +- src/test/bench/shootout-nbody.rs | 4 +- src/test/bench/shootout-spectralnorm.rs | 2 +- src/test/compile-fail/ifmt-bad-arg.rs | 4 +- src/test/compile-fail/ifmt-unimpl.rs | 4 +- src/test/compile-fail/issue-1448-2.rs | 2 +- src/test/compile-fail/issue-14853.rs | 11 +- src/test/run-pass/ifmt.rs | 100 ++++++++--------- src/test/run-pass/realloc-16687.rs | 10 +- 48 files changed, 291 insertions(+), 347 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 1efb5956101..be8828b3ec8 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -12,8 +12,6 @@ #![allow(unused_variables)] -pub use self::FormatError::*; - use any; use cell::{Cell, Ref, RefMut}; use iter::{Iterator, range}; @@ -23,10 +21,9 @@ use option::{Option, Some, None}; use ops::Deref; use result::{Ok, Err}; use result; -use slice::{AsSlice, SlicePrelude}; +use slice::SlicePrelude; use slice; use str::StrPrelude; -use str; pub use self::num::radix; pub use self::num::Radix; @@ -36,18 +33,16 @@ mod num; mod float; pub mod rt; -pub type Result = result::Result<(), FormatError>; +#[experimental = "core and I/O reconciliation may alter this definition"] +pub type Result = result::Result<(), Error>; /// The error type which is returned from formatting a message into a stream. /// /// This type does not support transmission of an error other than that an error /// occurred. Any extra information must be arranged to be transmitted through /// some other means. -pub enum FormatError { - /// A generic write error occurred during formatting, no other information - /// is transmitted via this variant. - WriteError, -} +#[experimental = "core and I/O reconciliation may alter this definition"] +pub struct Error; /// A collection of methods that are required to format a message into a stream. /// @@ -58,6 +53,7 @@ pub enum FormatError { /// This trait should generally not be implemented by consumers of the standard /// library. The `write!` macro accepts an instance of `io::Writer`, and the /// `io::Writer` trait is favored over implementing this trait. +#[experimental = "waiting for core and I/O reconciliation"] pub trait FormatWriter { /// Writes a slice of bytes into this writer, returning whether the write /// succeeded. @@ -81,17 +77,13 @@ pub trait FormatWriter { /// A struct to represent both where to emit formatting strings to and how they /// should be formatted. A mutable version of this is passed to all formatting /// traits. +#[unstable = "name may change and implemented traits are also unstable"] pub struct Formatter<'a> { - /// Flags for formatting (packed version of rt::Flag) - pub flags: uint, - /// Character used as 'fill' whenever there is alignment - pub fill: char, - /// Boolean indication of whether the output should be left-aligned - pub align: rt::Alignment, - /// Optionally specified integer width that the output should be - pub width: Option, - /// Optionally specified precision for numeric types - pub precision: Option, + flags: uint, + fill: char, + align: rt::Alignment, + width: Option, + precision: Option, buf: &'a mut FormatWriter+'a, curarg: slice::Items<'a, Argument<'a>>, @@ -104,6 +96,7 @@ enum Void {} /// family of functions. It contains a function to format the given value. At /// compile time it is ensured that the function and the value have the correct /// types, and then this struct is used to canonicalize arguments to one type. +#[experimental = "implementation detail of the `format_args!` macro"] pub struct Argument<'a> { formatter: extern "Rust" fn(&Void, &mut Formatter) -> Result, value: &'a Void, @@ -115,6 +108,7 @@ impl<'a> Arguments<'a> { /// which is valid because the compiler performs all necessary validation to /// ensure that the resulting call to format/write would be safe. #[doc(hidden)] #[inline] + #[experimental = "implementation detail of the `format_args!` macro"] pub unsafe fn new<'a>(pieces: &'static [&'static str], args: &'a [Argument<'a>]) -> Arguments<'a> { Arguments { @@ -128,6 +122,7 @@ impl<'a> Arguments<'a> { /// The `pieces` array must be at least as long as `fmt` to construct /// a valid Arguments structure. #[doc(hidden)] #[inline] + #[experimental = "implementation detail of the `format_args!` macro"] pub unsafe fn with_placeholders<'a>(pieces: &'static [&'static str], fmt: &'static [rt::Argument<'static>], args: &'a [Argument<'a>]) -> Arguments<'a> { @@ -148,6 +143,7 @@ impl<'a> Arguments<'a> { /// and pass it to a function or closure, passed as the first argument. The /// macro validates the format string at compile-time so usage of the `write` /// and `format` functions can be safely performed. +#[stable] pub struct Arguments<'a> { // Format string pieces to print. pieces: &'a [&'a str], @@ -169,84 +165,57 @@ impl<'a> Show for Arguments<'a> { /// When a format is not otherwise specified, types are formatted by ascribing /// to this trait. There is not an explicit way of selecting this trait to be /// used for formatting, it is only if no other format is specified. +#[unstable = "I/O and core have yet to be reconciled"] pub trait Show for Sized? { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } -/// Format trait for the `b` character -pub trait Bool for Sized? { - /// Formats the value using the given formatter. - fn fmt(&self, &mut Formatter) -> Result; -} - -/// Format trait for the `c` character -pub trait Char for Sized? { - /// Formats the value using the given formatter. - fn fmt(&self, &mut Formatter) -> Result; -} - -/// Format trait for the `i` and `d` characters -pub trait Signed for Sized? { - /// Formats the value using the given formatter. - fn fmt(&self, &mut Formatter) -> Result; -} - -/// Format trait for the `u` character -pub trait Unsigned for Sized? { - /// Formats the value using the given formatter. - fn fmt(&self, &mut Formatter) -> Result; -} /// Format trait for the `o` character +#[unstable = "I/O and core have yet to be reconciled"] pub trait Octal for Sized? { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } /// Format trait for the `t` character +#[unstable = "I/O and core have yet to be reconciled"] pub trait Binary for Sized? { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } /// Format trait for the `x` character +#[unstable = "I/O and core have yet to be reconciled"] pub trait LowerHex for Sized? { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } /// Format trait for the `X` character +#[unstable = "I/O and core have yet to be reconciled"] pub trait UpperHex for Sized? { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } -/// Format trait for the `s` character -pub trait String for Sized? { - /// Formats the value using the given formatter. - fn fmt(&self, &mut Formatter) -> Result; -} - /// Format trait for the `p` character +#[unstable = "I/O and core have yet to be reconciled"] pub trait Pointer for Sized? { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } -/// Format trait for the `f` character -pub trait Float for Sized? { - /// Formats the value using the given formatter. - fn fmt(&self, &mut Formatter) -> Result; -} - /// Format trait for the `e` character +#[unstable = "I/O and core have yet to be reconciled"] pub trait LowerExp for Sized? { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } /// Format trait for the `E` character +#[unstable = "I/O and core have yet to be reconciled"] pub trait UpperExp for Sized? { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; @@ -271,6 +240,8 @@ static DEFAULT_ARGUMENT: rt::Argument<'static> = rt::Argument { /// /// * output - the buffer to write output to /// * args - the precompiled arguments generated by `format_args!` +#[experimental = "libcore and I/O have yet to be reconciled, and this is an \ + implementation detail which should not otherwise be exported"] pub fn write(output: &mut FormatWriter, args: &Arguments) -> Result { let mut formatter = Formatter { flags: 0, @@ -368,6 +339,7 @@ impl<'a> Formatter<'a> { /// /// This function will correctly account for the flags provided as well as /// the minimum width. It will not take precision into account. + #[unstable = "definition may change slightly over time"] pub fn pad_integral(&mut self, is_positive: bool, prefix: &str, @@ -440,6 +412,7 @@ impl<'a> Formatter<'a> { /// is longer than this length /// /// Notably this function ignored the `flag` parameters + #[unstable = "definition may change slightly over time"] pub fn pad(&mut self, s: &str) -> Result { // Make sure there's a fast path up front if self.width.is_none() && self.precision.is_none() { @@ -516,19 +489,48 @@ impl<'a> Formatter<'a> { /// Writes some data to the underlying buffer contained within this /// formatter. + #[unstable = "reconciling core and I/O may alter this definition"] pub fn write(&mut self, data: &[u8]) -> Result { self.buf.write(data) } /// Writes some formatted information into this instance + #[unstable = "reconciling core and I/O may alter this definition"] pub fn write_fmt(&mut self, fmt: &Arguments) -> Result { write(self.buf, fmt) } + + /// Flags for formatting (packed version of rt::Flag) + #[experimental = "return type may change and method was just created"] + pub fn flags(&self) -> uint { self.flags } + + /// Character used as 'fill' whenever there is alignment + #[unstable = "method was just created"] + pub fn fill(&self) -> char { self.fill } + + /// Flag indicating what form of alignment was requested + #[unstable = "method was just created"] + pub fn align(&self) -> rt::Alignment { self.align } + + /// Optionally specified integer width that the output should be + #[unstable = "method was just created"] + pub fn width(&self) -> Option { self.width } + + /// Optionally specified precision for numeric types + #[unstable = "method was just created"] + pub fn precision(&self) -> Option { self.precision } +} + +impl Show for Error { + fn fmt(&self, f: &mut Formatter) -> Result { + "an error occurred when formatting an argument".fmt(f) + } } /// This is a function which calls are emitted to by the compiler itself to /// create the Argument structures that are passed into the `format` function. #[doc(hidden)] #[inline] +#[experimental = "implementation detail of the `format_args!` macro"] pub fn argument<'a, T>(f: extern "Rust" fn(&T, &mut Formatter) -> Result, t: &'a T) -> Argument<'a> { unsafe { @@ -542,15 +544,17 @@ pub fn argument<'a, T>(f: extern "Rust" fn(&T, &mut Formatter) -> Result, /// When the compiler determines that the type of an argument *must* be a string /// (such as for select), then it invokes this method. #[doc(hidden)] #[inline] +#[experimental = "implementation detail of the `format_args!` macro"] pub fn argumentstr<'a>(s: &'a &str) -> Argument<'a> { - argument(String::fmt, s) + argument(Show::fmt, s) } /// When the compiler determines that the type of an argument *must* be a uint /// (such as for plural), then it invokes this method. #[doc(hidden)] #[inline] +#[experimental = "implementation detail of the `format_args!` macro"] pub fn argumentuint<'a>(s: &'a uint) -> Argument<'a> { - argument(Unsigned::fmt, s) + argument(Show::fmt, s) } // Implementations of the core formatting traits @@ -565,32 +569,26 @@ impl<'a> Show for &'a Show+'a { fn fmt(&self, f: &mut Formatter) -> Result { (*self).fmt(f) } } -impl Bool for bool { - fn fmt(&self, f: &mut Formatter) -> Result { - String::fmt(if *self { "true" } else { "false" }, f) - } -} - -impl String for T { +impl Show for bool { fn fmt(&self, f: &mut Formatter) -> Result { - f.pad(self.as_slice()) + Show::fmt(if *self { "true" } else { "false" }, f) } } -impl String for str { +impl Show for str { fn fmt(&self, f: &mut Formatter) -> Result { f.pad(self) } } -impl Char for char { +impl Show for char { fn fmt(&self, f: &mut Formatter) -> Result { use char::Char; let mut utf8 = [0u8, ..4]; let amt = self.encode_utf8(&mut utf8).unwrap_or(0); let s: &str = unsafe { mem::transmute(utf8[..amt]) }; - String::fmt(s, f) + Show::fmt(s, f) } } @@ -620,7 +618,7 @@ impl<'a, T> Pointer for &'a mut T { } macro_rules! floating(($ty:ident) => { - impl Float for $ty { + impl Show for $ty { fn fmt(&self, fmt: &mut Formatter) -> Result { use num::Float; @@ -688,19 +686,6 @@ floating!(f64) // Implementation of Show for various core types -macro_rules! delegate(($ty:ty to $other:ident) => { - impl Show for $ty { - fn fmt(&self, f: &mut Formatter) -> Result { - $other::fmt(self, f) - } - } -}) -delegate!(str to String) -delegate!(bool to Bool) -delegate!(char to Char) -delegate!(f32 to Float) -delegate!(f64 to Float) - impl Show for *const T { fn fmt(&self, f: &mut Formatter) -> Result { Pointer::fmt(self, f) } } diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index 0a5af56217c..1c856a6e208 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -109,6 +109,7 @@ radix!(UpperHex, 16, "0x", x @ 0 ... 9 => b'0' + x, /// A radix with in the range of `2..36`. #[deriving(Clone, PartialEq)] +#[unstable = "may be renamed or move to a different module"] pub struct Radix { base: u8, } @@ -132,6 +133,7 @@ impl GenericRadix for Radix { } /// A helper type for formatting radixes. +#[unstable = "may be renamed or move to a different module"] pub struct RadixFmt(T, R); /// Constructs a radix formatter in the range of `2..36`. @@ -142,6 +144,7 @@ pub struct RadixFmt(T, R); /// use std::fmt::radix; /// assert_eq!(format!("{}", radix(55i, 36)), "1j".to_string()); /// ``` +#[unstable = "may be renamed or move to a different module"] pub fn radix(x: T, base: u8) -> RadixFmt { RadixFmt(x, Radix::new(base)) } @@ -167,7 +170,6 @@ macro_rules! int_base { macro_rules! integer { ($Int:ident, $Uint:ident) => { int_base!(Show for $Int as $Int -> Decimal) - int_base!(Signed for $Int as $Int -> Decimal) int_base!(Binary for $Int as $Uint -> Binary) int_base!(Octal for $Int as $Uint -> Octal) int_base!(LowerHex for $Int as $Uint -> LowerHex) @@ -175,7 +177,6 @@ macro_rules! integer { radix_fmt!($Int as $Int, fmt_int) int_base!(Show for $Uint as $Uint -> Decimal) - int_base!(Unsigned for $Uint as $Uint -> Decimal) int_base!(Binary for $Uint as $Uint -> Binary) int_base!(Octal for $Uint as $Uint -> Octal) int_base!(LowerHex for $Uint as $Uint -> LowerHex) diff --git a/src/libcore/fmt/rt.rs b/src/libcore/fmt/rt.rs index 0e8504e7ee5..145e78dc668 100644 --- a/src/libcore/fmt/rt.rs +++ b/src/libcore/fmt/rt.rs @@ -14,6 +14,8 @@ //! These definitions are similar to their `ct` equivalents, but differ in that //! these can be statically allocated and are slightly optimized for the runtime +#![experimental = "implementation detail of the `format_args!` macro"] + pub use self::Alignment::*; pub use self::Count::*; pub use self::Position::*; diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 9ba67bb2e47..9016f40b1b8 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -108,7 +108,10 @@ macro_rules! try( /// Writing a formatted string into a writer #[macro_export] macro_rules! write( - ($dst:expr, $($arg:tt)*) => (format_args_method!($dst, write_fmt, $($arg)*)) + ($dst:expr, $($arg:tt)*) => ({ + let dst = &mut *$dst; + format_args!(|args| { dst.write_fmt(args) }, $($arg)*) + }) ) /// Writing a formatted string plus a newline into a writer @@ -119,15 +122,5 @@ macro_rules! writeln( ) ) -/// Write some formatted data into a stream. -/// -/// Identical to the macro in `std::macros` -#[macro_export] -macro_rules! write( - ($dst:expr, $($arg:tt)*) => ({ - format_args_method!($dst, write_fmt, $($arg)*) - }) -) - #[macro_export] macro_rules! unreachable( () => (panic!("unreachable code")) ) diff --git a/src/libcoretest/fmt/num.rs b/src/libcoretest/fmt/num.rs index 868e14b928a..3b43d6ad33b 100644 --- a/src/libcoretest/fmt/num.rs +++ b/src/libcoretest/fmt/num.rs @@ -21,16 +21,16 @@ fn test_format_int() { assert!(format!("{}", 1i16).as_slice() == "1"); assert!(format!("{}", 1i32).as_slice() == "1"); assert!(format!("{}", 1i64).as_slice() == "1"); - assert!(format!("{:d}", -1i).as_slice() == "-1"); - assert!(format!("{:d}", -1i8).as_slice() == "-1"); - assert!(format!("{:d}", -1i16).as_slice() == "-1"); - assert!(format!("{:d}", -1i32).as_slice() == "-1"); - assert!(format!("{:d}", -1i64).as_slice() == "-1"); - assert!(format!("{:t}", 1i).as_slice() == "1"); - assert!(format!("{:t}", 1i8).as_slice() == "1"); - assert!(format!("{:t}", 1i16).as_slice() == "1"); - assert!(format!("{:t}", 1i32).as_slice() == "1"); - assert!(format!("{:t}", 1i64).as_slice() == "1"); + assert!(format!("{}", -1i).as_slice() == "-1"); + assert!(format!("{}", -1i8).as_slice() == "-1"); + assert!(format!("{}", -1i16).as_slice() == "-1"); + assert!(format!("{}", -1i32).as_slice() == "-1"); + assert!(format!("{}", -1i64).as_slice() == "-1"); + assert!(format!("{:b}", 1i).as_slice() == "1"); + assert!(format!("{:b}", 1i8).as_slice() == "1"); + assert!(format!("{:b}", 1i16).as_slice() == "1"); + assert!(format!("{:b}", 1i32).as_slice() == "1"); + assert!(format!("{:b}", 1i64).as_slice() == "1"); assert!(format!("{:x}", 1i).as_slice() == "1"); assert!(format!("{:x}", 1i8).as_slice() == "1"); assert!(format!("{:x}", 1i16).as_slice() == "1"); @@ -52,16 +52,11 @@ fn test_format_int() { assert!(format!("{}", 1u16).as_slice() == "1"); assert!(format!("{}", 1u32).as_slice() == "1"); assert!(format!("{}", 1u64).as_slice() == "1"); - assert!(format!("{:u}", 1u).as_slice() == "1"); - assert!(format!("{:u}", 1u8).as_slice() == "1"); - assert!(format!("{:u}", 1u16).as_slice() == "1"); - assert!(format!("{:u}", 1u32).as_slice() == "1"); - assert!(format!("{:u}", 1u64).as_slice() == "1"); - assert!(format!("{:t}", 1u).as_slice() == "1"); - assert!(format!("{:t}", 1u8).as_slice() == "1"); - assert!(format!("{:t}", 1u16).as_slice() == "1"); - assert!(format!("{:t}", 1u32).as_slice() == "1"); - assert!(format!("{:t}", 1u64).as_slice() == "1"); + assert!(format!("{:b}", 1u).as_slice() == "1"); + assert!(format!("{:b}", 1u8).as_slice() == "1"); + assert!(format!("{:b}", 1u16).as_slice() == "1"); + assert!(format!("{:b}", 1u32).as_slice() == "1"); + assert!(format!("{:b}", 1u64).as_slice() == "1"); assert!(format!("{:x}", 1u).as_slice() == "1"); assert!(format!("{:x}", 1u8).as_slice() == "1"); assert!(format!("{:x}", 1u16).as_slice() == "1"); @@ -79,9 +74,9 @@ fn test_format_int() { assert!(format!("{:o}", 1u64).as_slice() == "1"); // Test a larger number - assert!(format!("{:t}", 55i).as_slice() == "110111"); + assert!(format!("{:b}", 55i).as_slice() == "110111"); assert!(format!("{:o}", 55i).as_slice() == "67"); - assert!(format!("{:d}", 55i).as_slice() == "55"); + assert!(format!("{}", 55i).as_slice() == "55"); assert!(format!("{:x}", 55i).as_slice() == "37"); assert!(format!("{:X}", 55i).as_slice() == "37"); } @@ -89,15 +84,13 @@ fn test_format_int() { #[test] fn test_format_int_zero() { assert!(format!("{}", 0i).as_slice() == "0"); - assert!(format!("{:d}", 0i).as_slice() == "0"); - assert!(format!("{:t}", 0i).as_slice() == "0"); + assert!(format!("{:b}", 0i).as_slice() == "0"); assert!(format!("{:o}", 0i).as_slice() == "0"); assert!(format!("{:x}", 0i).as_slice() == "0"); assert!(format!("{:X}", 0i).as_slice() == "0"); assert!(format!("{}", 0u).as_slice() == "0"); - assert!(format!("{:u}", 0u).as_slice() == "0"); - assert!(format!("{:t}", 0u).as_slice() == "0"); + assert!(format!("{:b}", 0u).as_slice() == "0"); assert!(format!("{:o}", 0u).as_slice() == "0"); assert!(format!("{:x}", 0u).as_slice() == "0"); assert!(format!("{:X}", 0u).as_slice() == "0"); @@ -105,11 +98,11 @@ fn test_format_int_zero() { #[test] fn test_format_int_flags() { - assert!(format!("{:3d}", 1i).as_slice() == " 1"); - assert!(format!("{:>3d}", 1i).as_slice() == " 1"); - assert!(format!("{:>+3d}", 1i).as_slice() == " +1"); - assert!(format!("{:<3d}", 1i).as_slice() == "1 "); - assert!(format!("{:#d}", 1i).as_slice() == "1"); + assert!(format!("{:3}", 1i).as_slice() == " 1"); + assert!(format!("{:>3}", 1i).as_slice() == " 1"); + assert!(format!("{:>+3}", 1i).as_slice() == " +1"); + assert!(format!("{:<3}", 1i).as_slice() == "1 "); + assert!(format!("{:#}", 1i).as_slice() == "1"); assert!(format!("{:#x}", 10i).as_slice() == "0xa"); assert!(format!("{:#X}", 10i).as_slice() == "0xA"); assert!(format!("{:#5x}", 10i).as_slice() == " 0xa"); @@ -119,25 +112,25 @@ fn test_format_int_flags() { assert!(format!("{:<8x}", 10i).as_slice() == "a "); assert!(format!("{:>8x}", 10i).as_slice() == " a"); assert!(format!("{:#08x}", 10i).as_slice() == "0x00000a"); - assert!(format!("{:08d}", -10i).as_slice() == "-0000010"); + assert!(format!("{:08}", -10i).as_slice() == "-0000010"); assert!(format!("{:x}", -1u8).as_slice() == "ff"); assert!(format!("{:X}", -1u8).as_slice() == "FF"); - assert!(format!("{:t}", -1u8).as_slice() == "11111111"); + assert!(format!("{:b}", -1u8).as_slice() == "11111111"); assert!(format!("{:o}", -1u8).as_slice() == "377"); assert!(format!("{:#x}", -1u8).as_slice() == "0xff"); assert!(format!("{:#X}", -1u8).as_slice() == "0xFF"); - assert!(format!("{:#t}", -1u8).as_slice() == "0b11111111"); + assert!(format!("{:#b}", -1u8).as_slice() == "0b11111111"); assert!(format!("{:#o}", -1u8).as_slice() == "0o377"); } #[test] fn test_format_int_sign_padding() { - assert!(format!("{:+5d}", 1i).as_slice() == " +1"); - assert!(format!("{:+5d}", -1i).as_slice() == " -1"); - assert!(format!("{:05d}", 1i).as_slice() == "00001"); - assert!(format!("{:05d}", -1i).as_slice() == "-0001"); - assert!(format!("{:+05d}", 1i).as_slice() == "+0001"); - assert!(format!("{:+05d}", -1i).as_slice() == "-0001"); + assert!(format!("{:+5}", 1i).as_slice() == " +1"); + assert!(format!("{:+5}", -1i).as_slice() == " -1"); + assert!(format!("{:05}", 1i).as_slice() == "00001"); + assert!(format!("{:05}", -1i).as_slice() == "-0001"); + assert!(format!("{:+05}", 1i).as_slice() == "+0001"); + assert!(format!("{:+05}", -1i).as_slice() == "-0001"); } #[test] @@ -169,7 +162,7 @@ mod uint { #[bench] fn format_bin(b: &mut Bencher) { let mut rng = weak_rng(); - b.iter(|| { format!("{:t}", rng.gen::()); }) + b.iter(|| { format!("{:b}", rng.gen::()); }) } #[bench] @@ -181,7 +174,7 @@ mod uint { #[bench] fn format_dec(b: &mut Bencher) { let mut rng = weak_rng(); - b.iter(|| { format!("{:u}", rng.gen::()); }) + b.iter(|| { format!("{}", rng.gen::()); }) } #[bench] @@ -205,7 +198,7 @@ mod int { #[bench] fn format_bin(b: &mut Bencher) { let mut rng = weak_rng(); - b.iter(|| { format!("{:t}", rng.gen::()); }) + b.iter(|| { format!("{:b}", rng.gen::()); }) } #[bench] @@ -217,7 +210,7 @@ mod int { #[bench] fn format_dec(b: &mut Bencher) { let mut rng = weak_rng(); - b.iter(|| { format!("{:d}", rng.gen::()); }) + b.iter(|| { format!("{}", rng.gen::()); }) } #[bench] diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs index e5bd81cb816..568210118a8 100644 --- a/src/libflate/lib.rs +++ b/src/libflate/lib.rs @@ -130,7 +130,7 @@ mod tests { input.len()); let cmp = deflate_bytes(input.as_slice()).expect("deflation failed"); let out = inflate_bytes(cmp.as_slice()).expect("inflation failed"); - debug!("{} bytes deflated to {} ({:.1f}% size)", + debug!("{} bytes deflated to {} ({:.1}% size)", input.len(), cmp.len(), 100.0 * ((cmp.len() as f64) / (input.len() as f64))); assert_eq!(input.as_slice(), out.as_slice()); diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index cd9ef215720..df8cdabbcaa 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -221,7 +221,7 @@ pub fn render_to(output: &mut W) { impl<'a> dot::Labeller<'a, Nd<'a>, Ed<'a>> for Graph { fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new("example3").unwrap() } fn node_id(&'a self, n: &Nd<'a>) -> dot::Id<'a> { - dot::Id::new(format!("N{:u}", n.val0())).unwrap() + dot::Id::new(format!("N{}", n.val0())).unwrap() } fn node_label<'a>(&'a self, n: &Nd<'a>) -> dot::LabelText<'a> { let &(i, _) = n; @@ -635,7 +635,7 @@ mod tests { } fn id_name<'a>(n: &Node) -> Id<'a> { - Id::new(format!("N{:u}", *n)).unwrap() + Id::new(format!("N{}", *n)).unwrap() } impl<'a> Labeller<'a, Node, &'a Edge> for LabelledGraph { diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 2e60ce31d5e..fd2d97d4deb 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -241,13 +241,6 @@ impl fmt::Show for LogLevel { } } -impl fmt::Signed for LogLevel { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let LogLevel(level) = *self; - write!(fmt, "{}", level) - } -} - impl Logger for DefaultLogger { fn log(&mut self, record: &LogRecord) { match writeln!(&mut self.handle, diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 117cca1b8b5..d6a68dd07d7 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -237,7 +237,7 @@ pub trait Rng { /// use std::rand::{task_rng, Rng}; /// /// let mut rng = task_rng(); - /// println!("{:b}", rng.gen_weighted_bool(3)); + /// println!("{}", rng.gen_weighted_bool(3)); /// ``` fn gen_weighted_bool(&mut self, n: uint) -> bool { n == 0 || self.gen_range(0, n) == 0 diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index d7925177c29..62032beaacd 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -102,7 +102,7 @@ pub fn check_crate(tcx: &ty::ctxt) { fn make_stat(bccx: &BorrowckCtxt, stat: uint) -> String { let total = bccx.stats.guaranteed_paths as f64; let perc = if total == 0.0 { 0.0 } else { stat as f64 * 100.0 / total }; - format!("{} ({:.0f}%)", stat, perc) + format!("{} ({:.0}%)", stat, perc) } } diff --git a/src/librustc/middle/cfg/graphviz.rs b/src/librustc/middle/cfg/graphviz.rs index 78b3a1179ca..ba6dd2a5107 100644 --- a/src/librustc/middle/cfg/graphviz.rs +++ b/src/librustc/middle/cfg/graphviz.rs @@ -53,7 +53,7 @@ impl<'a, 'ast> dot::Labeller<'a, Node<'a>, Edge<'a>> for LabelledCFG<'a, 'ast> { fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new(self.name.as_slice()).unwrap() } fn node_id(&'a self, &(i,_): &Node<'a>) -> dot::Id<'a> { - dot::Id::new(format!("N{:u}", i.node_id())).unwrap() + dot::Id::new(format!("N{}", i.node_id())).unwrap() } fn node_label(&'a self, &(i, n): &Node<'a>) -> dot::LabelText<'a> { diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index c733084e981..6881f75ac18 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -81,8 +81,7 @@ impl<'a> fmt::Show for Matrix<'a> { try!(write!(f, "+")); for (column, pat_str) in row.into_iter().enumerate() { try!(write!(f, " ")); - f.width = Some(column_widths[column]); - try!(f.pad(pat_str.as_slice())); + try!(write!(f, "{:1$}", pat_str, column_widths[column])); try!(write!(f, " +")); } try!(write!(f, "\n")); diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 366f4bd0249..141504cb6f7 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -194,7 +194,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { let words_per_id = (bits_per_id + uint::BITS - 1) / uint::BITS; let num_nodes = cfg.graph.all_nodes().len(); - debug!("DataFlowContext::new(analysis_name: {:s}, id_range={}, \ + debug!("DataFlowContext::new(analysis_name: {}, id_range={}, \ bits_per_id={}, words_per_id={}) \ num_nodes: {}", analysis_name, id_range, bits_per_id, words_per_id, @@ -223,7 +223,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { pub fn add_gen(&mut self, id: ast::NodeId, bit: uint) { //! Indicates that `id` generates `bit` - debug!("{:s} add_gen(id={}, bit={})", + debug!("{} add_gen(id={}, bit={})", self.analysis_name, id, bit); assert!(self.nodeid_to_index.contains_key(&id)); assert!(self.bits_per_id > 0); @@ -236,7 +236,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { pub fn add_kill(&mut self, id: ast::NodeId, bit: uint) { //! Indicates that `id` kills `bit` - debug!("{:s} add_kill(id={}, bit={})", + debug!("{} add_kill(id={}, bit={})", self.analysis_name, id, bit); assert!(self.nodeid_to_index.contains_key(&id)); assert!(self.bits_per_id > 0); @@ -249,7 +249,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { fn apply_gen_kill(&self, cfgidx: CFGIndex, bits: &mut [uint]) { //! Applies the gen and kill sets for `cfgidx` to `bits` - debug!("{:s} apply_gen_kill(cfgidx={}, bits={}) [before]", + debug!("{} apply_gen_kill(cfgidx={}, bits={}) [before]", self.analysis_name, cfgidx, mut_bits_to_string(bits)); assert!(self.bits_per_id > 0); @@ -259,7 +259,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { let kills = self.kills.slice(start, end); bitwise(bits, kills, &Subtract); - debug!("{:s} apply_gen_kill(cfgidx={}, bits={}) [after]", + debug!("{} apply_gen_kill(cfgidx={}, bits={}) [after]", self.analysis_name, cfgidx, mut_bits_to_string(bits)); } @@ -316,7 +316,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { temp_bits.as_slice() } }; - debug!("{:s} each_bit_for_node({}, cfgidx={}) bits={}", + debug!("{} each_bit_for_node({}, cfgidx={}) bits={}", self.analysis_name, e, cfgidx, bits_to_string(slice)); self.each_bit(slice, f) } @@ -337,7 +337,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index); let (start, end) = self.compute_id_range(cfgidx); let gens = self.gens.slice(start, end); - debug!("{:s} each_gen_bit(id={}, gens={})", + debug!("{} each_gen_bit(id={}, gens={})", self.analysis_name, id, bits_to_string(gens)); self.each_bit(gens, f) } @@ -385,7 +385,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { //! This is usually called (if it is called at all), after //! all add_gen and add_kill calls, but before propagate. - debug!("{:s} add_kills_from_flow_exits", self.analysis_name); + debug!("{} add_kills_from_flow_exits", self.analysis_name); if self.bits_per_id == 0 { // Skip the surprisingly common degenerate case. (Note // compute_id_range requires self.words_per_id > 0.) @@ -408,7 +408,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { } } None => { - debug!("{:s} add_kills_from_flow_exits flow_exit={} \ + debug!("{} add_kills_from_flow_exits flow_exit={} \ no cfg_idx for exiting_scope={}", self.analysis_name, flow_exit, node_id); } @@ -417,10 +417,10 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { if changed { let bits = self.kills.slice_mut(start, end); - debug!("{:s} add_kills_from_flow_exits flow_exit={} bits={} [before]", + debug!("{} add_kills_from_flow_exits flow_exit={} bits={} [before]", self.analysis_name, flow_exit, mut_bits_to_string(bits)); bits.clone_from_slice(orig_kills.as_slice()); - debug!("{:s} add_kills_from_flow_exits flow_exit={} bits={} [after]", + debug!("{} add_kills_from_flow_exits flow_exit={} bits={} [after]", self.analysis_name, flow_exit, mut_bits_to_string(bits)); } true @@ -453,7 +453,7 @@ impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> { } } - debug!("Dataflow result for {:s}:", self.analysis_name); + debug!("Dataflow result for {}:", self.analysis_name); debug!("{}", { self.pretty_print_to(box io::stderr(), blk).unwrap(); "" @@ -474,7 +474,7 @@ impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> { fn walk_cfg(&mut self, cfg: &cfg::CFG, in_out: &mut [uint]) { - debug!("DataFlowContext::walk_cfg(in_out={}) {:s}", + debug!("DataFlowContext::walk_cfg(in_out={}) {}", bits_to_string(in_out), self.dfcx.analysis_name); assert!(self.dfcx.bits_per_id > 0); @@ -519,7 +519,7 @@ impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> { edge: &cfg::CFGEdge) { let source = edge.source(); let cfgidx = edge.target(); - debug!("{:s} propagate_bits_into_entry_set_for(pred_bits={}, {} to {})", + debug!("{} propagate_bits_into_entry_set_for(pred_bits={}, {} to {})", self.dfcx.analysis_name, bits_to_string(pred_bits), source, cfgidx); assert!(self.dfcx.bits_per_id > 0); @@ -530,7 +530,7 @@ impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> { bitwise(on_entry, pred_bits, &self.dfcx.oper) }; if changed { - debug!("{:s} changed entry set for {} to {}", + debug!("{} changed entry set for {} to {}", self.dfcx.analysis_name, cfgidx, bits_to_string(self.dfcx.on_entry.slice(start, end))); self.changed = true; diff --git a/src/librustc/middle/graph.rs b/src/librustc/middle/graph.rs index d2a7ec1e186..ac132477b87 100644 --- a/src/librustc/middle/graph.rs +++ b/src/librustc/middle/graph.rs @@ -36,7 +36,7 @@ be indexed by the direction (see the type `Direction`). #![allow(dead_code)] // still WIP -use std::fmt::{Formatter, FormatError, Show}; +use std::fmt::{Formatter, Error, Show}; use std::uint; pub struct Graph { @@ -57,7 +57,7 @@ pub struct Edge { } impl Show for Edge { - fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { write!(f, "Edge {{ next_edge: [{}, {}], source: {}, target: {}, data: {} }}", self.next_edge[0], self.next_edge[1], self.source, self.target, self.data) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 9f90afa3749..70567f52c06 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2678,9 +2678,14 @@ impl ops::Sub for TypeContents { } impl fmt::Show for TypeContents { + #[cfg(stage0)] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "TypeContents({:t})", self.bits) } + #[cfg(not(stage0))] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "TypeContents({:b})", self.bits) + } } pub fn type_interior_is_unsafe(cx: &ctxt, t: ty::t) -> bool { diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs index 76250d44baf..dfc9f392452 100644 --- a/src/librustc/middle/typeck/variance.rs +++ b/src/librustc/middle/typeck/variance.rs @@ -603,7 +603,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { let is_inferred; macro_rules! cannot_happen { () => { { - panic!("invalid parent: {:s} for {:s}", + panic!("invalid parent: {} for {}", tcx.map.node_to_string(parent_id), tcx.map.node_to_string(param_id)); } } } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index abf29fe3a4c..47bba3e4327 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -368,7 +368,7 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo if enabled { let loc = llvm::debug_loc_to_string(llcx, opt.debug_loc); - cgcx.handler.note(format!("optimization {:s} for {:s} at {:s}: {:s}", + cgcx.handler.note(format!("optimization {} for {} at {}: {}", opt.kind.describe(), pass_name, if loc.is_empty() { "[unknown]" } else { loc.as_slice() }, diff --git a/src/librustc_trans/driver/mod.rs b/src/librustc_trans/driver/mod.rs index 8985d05b6ca..a73afdf68e3 100644 --- a/src/librustc_trans/driver/mod.rs +++ b/src/librustc_trans/driver/mod.rs @@ -224,13 +224,13 @@ Available lint options: }; println!("Lint checks provided by rustc:\n"); - println!(" {} {:7.7s} {}", padded("name"), "default", "meaning"); - println!(" {} {:7.7s} {}", padded("----"), "-------", "-------"); + println!(" {} {:7.7} {}", padded("name"), "default", "meaning"); + println!(" {} {:7.7} {}", padded("----"), "-------", "-------"); let print_lints = |lints: Vec<&Lint>| { for lint in lints.into_iter() { let name = lint.name_lower().replace("_", "-"); - println!(" {} {:7.7s} {}", + println!(" {} {:7.7} {}", padded(name.as_slice()), lint.default_level.as_str(), lint.desc); } println!("\n"); @@ -293,7 +293,7 @@ fn describe_debug_flags() { for tuple in r.iter() { match *tuple { (ref name, ref desc, _) => { - println!(" -Z {:>20s} -- {}", *name, *desc); + println!(" -Z {:>20} -- {}", *name, *desc); } } } @@ -306,7 +306,7 @@ fn describe_codegen_flags() { Some(..) => (21, "=val"), None => (25, "") }; - println!(" -C {:>width$s}{} -- {}", name.replace("_", "-"), + println!(" -C {:>width$}{} -- {}", name.replace("_", "-"), extra, desc, width=width); } } diff --git a/src/librustc_trans/driver/pretty.rs b/src/librustc_trans/driver/pretty.rs index c20f2e097f3..420a0ed5e8a 100644 --- a/src/librustc_trans/driver/pretty.rs +++ b/src/librustc_trans/driver/pretty.rs @@ -355,8 +355,8 @@ impl UserIdentifiedItem { fn to_one_node_id(self, user_option: &str, sess: &Session, map: &ast_map::Map) -> ast::NodeId { let fail_because = |is_wrong_because| -> ast::NodeId { let message = - format!("{:s} needs NodeId (int) or unique \ - path suffix (b::c::d); got {:s}, which {:s}", + format!("{} needs NodeId (int) or unique \ + path suffix (b::c::d); got {}, which {}", user_option, self.reconstructed_input(), is_wrong_because); diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 9c4a532790d..98cdea73a99 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -3135,7 +3135,7 @@ pub fn trans_crate<'tcx>(analysis: CrateAnalysis<'tcx>) } if shared_ccx.sess().count_llvm_insns() { for (k, v) in shared_ccx.stats().llvm_insns.borrow().iter() { - println!("{:7u} {}", *v, *k); + println!("{:7} {}", *v, *k); } } diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index 02909b0e3a9..58c67c8c091 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -67,7 +67,7 @@ pub enum CleanupScopeKind<'blk, 'tcx: 'blk> { } impl<'blk, 'tcx: 'blk> fmt::Show for CleanupScopeKind<'blk, 'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::FormatError> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { CustomScopeKind => write!(f, "CustomScopeKind"), AstScopeKind(nid) => write!(f, "AstScopeKind({})", nid), diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index 901761ba806..daa5f155d51 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -75,12 +75,6 @@ impl fmt::Show for ItemType { } } -impl fmt::Unsigned for ItemType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - (*self as uint).fmt(f) - } -} - pub fn shortty(item: &clean::Item) -> ItemType { match item.inner { clean::ModuleItem(..) => Module, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 0ecb86d8bdd..5e4ac259e71 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -437,8 +437,8 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::IoResult if i > 0 { try!(write!(&mut w, ",")); } - try!(write!(&mut w, r#"[{:u},"{}","{}",{}"#, - item.ty, item.name, path, + try!(write!(&mut w, r#"[{},"{}","{}",{}"#, + item.ty as uint, item.name, path, item.desc.to_json().to_string())); match item.parent { Some(nodeid) => { @@ -457,8 +457,8 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::IoResult if i > 0 { try!(write!(&mut w, ",")); } - try!(write!(&mut w, r#"[{:u},"{}"]"#, - short, *fqp.last().unwrap())); + try!(write!(&mut w, r#"[{},"{}"]"#, + short as uint, *fqp.last().unwrap())); } try!(write!(&mut w, "]}};")); @@ -2192,7 +2192,7 @@ impl<'a> fmt::Show for Source<'a> { } try!(write!(fmt, "
"));
         for i in range(1, lines + 1) {
-            try!(write!(fmt, "{0:1$u}\n", i, cols));
+            try!(write!(fmt, "{0:1$}\n", i, cols));
         }
         try!(write!(fmt, "
")); try!(write!(fmt, "{}", highlight::highlight(s.as_slice(), None, None))); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 0350fe72e11..4a512ca33fc 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -168,11 +168,11 @@ pub fn main_args(args: &[String]) -> int { if matches.opt_strs("passes").as_slice() == &["list".to_string()] { println!("Available passes for running rustdoc:"); for &(name, _, description) in PASSES.iter() { - println!("{:>20s} - {}", name, description); + println!("{:>20} - {}", name, description); } println!("{}", "\nDefault passes for rustdoc:"); // FIXME: #9970 for &name in DEFAULT_PASSES.iter() { - println!("{:>20s}", name); + println!("{:>20}", name); } return 0; } diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 2968c53de9a..030ee1d4352 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -2403,7 +2403,7 @@ impl ToJson for Option { impl fmt::Show for Json { /// Encodes a json value into a string fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.to_writer(f).map_err(|_| fmt::WriteError) + self.to_writer(f).map_err(|_| fmt::Error) } } diff --git a/src/libstd/fmt.rs b/src/libstd/fmt.rs index e140ddba723..2482fe63028 100644 --- a/src/libstd/fmt.rs +++ b/src/libstd/fmt.rs @@ -38,11 +38,11 @@ Some examples of the `format!` extension are: ```rust # fn main() { format!("Hello"); // => "Hello" -format!("Hello, {:s}!", "world"); // => "Hello, world!" -format!("The number is {:d}", 1i); // => "The number is 1" +format!("Hello, {}!", "world"); // => "Hello, world!" +format!("The number is {}", 1i); // => "The number is 1" format!("{}", (3i, 4i)); // => "(3, 4)" format!("{value}", value=4i); // => "4" -format!("{} {}", 1i, 2i); // => "1 2" +format!("{} {}", 1i, 2u); // => "1 2" # } ``` @@ -94,9 +94,9 @@ For example, the following `format!` expressions all use named argument: ```rust # fn main() { -format!("{argument}", argument = "test"); // => "test" -format!("{name} {}", 1i, name = 2i); // => "2 1" -format!("{a:s} {c:d} {b}", a="a", b=(), c=3i); // => "a 3 ()" +format!("{argument}", argument = "test"); // => "test" +format!("{name} {}", 1i, name = 2i); // => "2 1" +format!("{a} {c} {b}", a="a", b=(), c=3i); // => "a 3 ()" # } ``` @@ -138,23 +138,16 @@ multiple actual types to be formatted via `{:d}` (like `i8` as well as `int`). The current mapping of types to traits is: * *nothing* ⇒ `Show` -* `d` ⇒ `Signed` -* `i` ⇒ `Signed` -* `u` ⇒ `Unsigned` -* `b` ⇒ `Bool` -* `c` ⇒ `Char` * `o` ⇒ `Octal` * `x` ⇒ `LowerHex` * `X` ⇒ `UpperHex` -* `s` ⇒ `String` * `p` ⇒ `Pointer` -* `t` ⇒ `Binary` -* `f` ⇒ `Float` +* `b` ⇒ `Binary` * `e` ⇒ `LowerExp` * `E` ⇒ `UpperExp` What this means is that any type of argument which implements the -`std::fmt::Binary` trait can then be formatted with `{:t}`. Implementations are +`std::fmt::Binary` trait can then be formatted with `{:b}`. Implementations are provided for these traits for a number of primitive types by the standard library as well. If no format is specified (as in `{}` or `{:6}`), then the format trait used is the `Show` trait. This is one of the more commonly @@ -216,7 +209,7 @@ impl fmt::Binary for Vector2D { // Respect the formatting flags by using the helper method // `pad_integral` on the Formatter object. See the method documentation // for details, and the function `pad` can be used to pad strings. - let decimals = f.precision.unwrap_or(3); + let decimals = f.precision().unwrap_or(3); let string = f64::to_str_exact(magnitude, decimals); f.pad_integral(true, "", string.as_bytes()) } @@ -226,7 +219,7 @@ fn main() { let myvector = Vector2D { x: 3, y: 4 }; println!("{}", myvector); // => "(3, 4)" - println!("{:10.3t}", myvector); // => " 5.000" + println!("{:10.3b}", myvector); // => " 5.000" } ``` @@ -418,10 +411,10 @@ use string; use vec::Vec; pub use core::fmt::{Formatter, Result, FormatWriter, rt}; -pub use core::fmt::{Show, Bool, Char, Signed, Unsigned, Octal, Binary}; -pub use core::fmt::{LowerHex, UpperHex, String, Pointer}; -pub use core::fmt::{Float, LowerExp, UpperExp}; -pub use core::fmt::{FormatError, WriteError}; +pub use core::fmt::{Show, Octal, Binary}; +pub use core::fmt::{LowerHex, UpperHex, Pointer}; +pub use core::fmt::{LowerExp, UpperExp}; +pub use core::fmt::Error; pub use core::fmt::{Argument, Arguments, write, radix, Radix, RadixFmt}; #[doc(hidden)] @@ -444,6 +437,8 @@ pub use core::fmt::{argument, argumentstr, argumentuint}; /// let s = format_args!(fmt::format, "Hello, {}!", "world"); /// assert_eq!(s, "Hello, world!".to_string()); /// ``` +#[experimental = "this is an implementation detail of format! and should not \ + be called directly"] pub fn format(args: &Arguments) -> string::String { let mut output = Vec::new(); let _ = write!(&mut output as &mut Writer, "{}", args); @@ -454,7 +449,7 @@ impl<'a> Writer for Formatter<'a> { fn write(&mut self, b: &[u8]) -> io::IoResult<()> { match (*self).write(b) { Ok(()) => Ok(()), - Err(WriteError) => Err(io::standard_error(io::OtherIoError)) + Err(Error) => Err(io::standard_error(io::OtherIoError)) } } } diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 82bfa3c4e80..681400e9db5 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1034,7 +1034,7 @@ pub trait Writer { Ok(()) => Ok(()), Err(e) => { self.error = Err(e); - Err(fmt::WriteError) + Err(fmt::Error) } } } @@ -1081,13 +1081,13 @@ pub trait Writer { /// Write the result of passing n through `int::to_str_bytes`. #[inline] fn write_int(&mut self, n: int) -> IoResult<()> { - write!(self, "{:d}", n) + write!(self, "{}", n) } /// Write the result of passing n through `uint::to_str_bytes`. #[inline] fn write_uint(&mut self, n: uint) -> IoResult<()> { - write!(self, "{:u}", n) + write!(self, "{}", n) } /// Write a little-endian uint (number of bytes depends on system). @@ -1896,10 +1896,8 @@ impl Default for FilePermission { } impl fmt::Show for FilePermission { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.fill = '0'; - formatter.width = Some(4); - (&self.bits as &fmt::Octal).fmt(formatter) + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:04o}", self.bits) } } diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 26e9e70dff3..4e5dd5d8818 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -240,6 +240,7 @@ macro_rules! unimplemented( /// format!("x = {}, y = {y}", 10i, y = 30i); /// ``` #[macro_export] +#[stable] macro_rules! format( ($($arg:tt)*) => ( format_args!(::std::fmt::format, $($arg)*) @@ -259,15 +260,18 @@ macro_rules! format( /// write!(&mut w, "formatted {}", "arguments"); /// ``` #[macro_export] +#[stable] macro_rules! write( ($dst:expr, $($arg:tt)*) => ({ - format_args_method!($dst, write_fmt, $($arg)*) + let dst = &mut *$dst; + format_args!(|args| { dst.write_fmt(args) }, $($arg)*) }) ) /// Equivalent to the `write!` macro, except that a newline is appended after /// the message is written. #[macro_export] +#[stable] macro_rules! writeln( ($dst:expr, $fmt:expr $($arg:tt)*) => ( write!($dst, concat!($fmt, "\n") $($arg)*) @@ -277,6 +281,7 @@ macro_rules! writeln( /// Equivalent to the `println!` macro except that a newline is not printed at /// the end of the message. #[macro_export] +#[stable] macro_rules! print( ($($arg:tt)*) => (format_args!(::std::io::stdio::print_args, $($arg)*)) ) @@ -294,6 +299,7 @@ macro_rules! print( /// println!("format {} arguments", "some"); /// ``` #[macro_export] +#[stable] macro_rules! println( ($($arg:tt)*) => (format_args!(::std::io::stdio::println_args, $($arg)*)) ) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 15e14902727..497a2d49faf 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -95,7 +95,7 @@ impl Ident { } pub fn encode_with_hygiene(&self) -> String { - format!("\x00name_{:u},ctxt_{:u}\x00", + format!("\x00name_{},ctxt_{}\x00", self.name.uint(), self.ctxt) } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 9292825ffe8..8c70a95443b 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -361,9 +361,6 @@ fn initial_syntax_expander_table(ecfg: &expand::ExpansionConfig) -> SyntaxEnv { syntax_expanders.insert(intern("format_args"), builtin_normal_expander( ext::format::expand_format_args)); - syntax_expanders.insert(intern("format_args_method"), - builtin_normal_expander( - ext::format::expand_format_args_method)); syntax_expanders.insert(intern("env"), builtin_normal_expander( ext::env::expand_env)); diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index dccc12e406b..8fccb0755f4 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -887,7 +887,7 @@ impl<'a> MethodDef<'a> { // a series of let statements mapping each self_arg to a uint // corresponding to its variant index. let vi_idents: Vec = self_arg_names.iter() - .map(|name| { let vi_suffix = format!("{:s}_vi", name.as_slice()); + .map(|name| { let vi_suffix = format!("{}_vi", name.as_slice()); cx.ident_of(vi_suffix.as_slice()) }) .collect::>(); diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs index f1b92b4d6bc..b04a800a32d 100644 --- a/src/libsyntax/ext/format.rs +++ b/src/libsyntax/ext/format.rs @@ -237,7 +237,7 @@ impl<'a, 'b> Context<'a, 'b> { match arg { Exact(arg) => { if self.args.len() <= arg { - let msg = format!("invalid reference to argument `{}` ({:s})", + let msg = format!("invalid reference to argument `{}` ({})", arg, self.describe_num_args()); self.ecx.span_err(self.fmtsp, msg.as_slice()); @@ -670,17 +670,11 @@ impl<'a, 'b> Context<'a, 'b> { Known(ref tyname) => { match tyname.as_slice() { "" => "Show", - "b" => "Bool", - "c" => "Char", - "d" | "i" => "Signed", "e" => "LowerExp", "E" => "UpperExp", - "f" => "Float", "o" => "Octal", "p" => "Pointer", - "s" => "String", - "t" => "Binary", - "u" => "Unsigned", + "b" => "Binary", "x" => "LowerHex", "X" => "UpperHex", _ => { @@ -724,18 +718,6 @@ pub fn expand_format_args<'cx>(ecx: &'cx mut ExtCtxt, sp: Span, } } -pub fn expand_format_args_method<'cx>(ecx: &'cx mut ExtCtxt, sp: Span, - tts: &[ast::TokenTree]) -> Box { - - match parse_args(ecx, sp, true, tts) { - (invocation, Some((efmt, args, order, names))) => { - MacExpr::new(expand_preparsed_format_args(ecx, sp, invocation, efmt, - args, order, names)) - } - (_, None) => MacExpr::new(ecx.expr_uint(sp, 2)) - } -} - /// Take the various parts of `format_args!(extra, efmt, args..., /// name=names...)` and construct the appropriate formatting /// expression. diff --git a/src/libsyntax/ext/mtwt.rs b/src/libsyntax/ext/mtwt.rs index b50a4690e42..2ddcab10cda 100644 --- a/src/libsyntax/ext/mtwt.rs +++ b/src/libsyntax/ext/mtwt.rs @@ -131,7 +131,7 @@ fn new_sctable_internal() -> SCTable { pub fn display_sctable(table: &SCTable) { error!("SC table:"); for (idx,val) in table.table.borrow().iter().enumerate() { - error!("{:4u} : {}",idx,val); + error!("{:4} : {}",idx,val); } } diff --git a/src/libterm/terminfo/parm.rs b/src/libterm/terminfo/parm.rs index ec6e286b9b9..f910bfc5bd4 100644 --- a/src/libterm/terminfo/parm.rs +++ b/src/libterm/terminfo/parm.rs @@ -497,8 +497,8 @@ fn format(val: Param, op: FormatOp, flags: Flags) -> Result ,String> { let mut s = match val { Number(d) => { let s = match (op, flags.sign) { - (FormatDigit, true) => format!("{:+d}", d).into_bytes(), - (FormatDigit, false) => format!("{:d}", d).into_bytes(), + (FormatDigit, true) => format!("{:+}", d).into_bytes(), + (FormatDigit, false) => format!("{}", d).into_bytes(), (FormatOctal, _) => format!("{:o}", d).into_bytes(), (FormatHex, _) => format!("{:x}", d).into_bytes(), (FormatHEX, _) => format!("{:X}", d).into_bytes(), diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index d5d0e7aeb17..0ea8ca84ef8 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -687,14 +687,14 @@ impl ConsoleTestState { improved += 1; try!(self.write_plain(format!(": {}", *k).as_slice())); try!(self.write_improved()); - try!(self.write_plain(format!(" by {:.2f}%\n", + try!(self.write_plain(format!(" by {:.2}%\n", pct as f64).as_slice())); } Regression(pct) => { regressed += 1; try!(self.write_plain(format!(": {}", *k).as_slice())); try!(self.write_regressed()); - try!(self.write_plain(format!(" by {:.2f}%\n", + try!(self.write_plain(format!(" by {:.2}%\n", pct as f64).as_slice())); } } diff --git a/src/libtime/lib.rs b/src/libtime/lib.rs index 4fb387db3a2..062035c23f9 100644 --- a/src/libtime/lib.rs +++ b/src/libtime/lib.rs @@ -602,8 +602,8 @@ impl<'a> fmt::Show for TmFmt<'a> { match ch { 'G' => write!(fmt, "{}", year), - 'g' => write!(fmt, "{:02d}", (year % 100 + 100) % 100), - 'V' => write!(fmt, "{:02d}", days / 7 + 1), + 'g' => write!(fmt, "{:02}", (year % 100 + 100) % 100), + 'V' => write!(fmt, "{:02}", days / 7 + 1), _ => Ok(()) } } @@ -663,7 +663,7 @@ impl<'a> fmt::Show for TmFmt<'a> { 11 => "Dec", _ => return die() }, - 'C' => return write!(fmt, "{:02d}", (tm.tm_year as int + 1900) / 100), + 'C' => return write!(fmt, "{:02}", (tm.tm_year as int + 1900) / 100), 'c' => { try!(parse_type(fmt, 'a', tm)); try!(' '.fmt(fmt)); @@ -682,9 +682,9 @@ impl<'a> fmt::Show for TmFmt<'a> { try!('/'.fmt(fmt)); return parse_type(fmt, 'y', tm); } - 'd' => return write!(fmt, "{:02d}", tm.tm_mday), - 'e' => return write!(fmt, "{:2d}", tm.tm_mday), - 'f' => return write!(fmt, "{:09d}", tm.tm_nsec), + 'd' => return write!(fmt, "{:02}", tm.tm_mday), + 'e' => return write!(fmt, "{:2}", tm.tm_mday), + 'f' => return write!(fmt, "{:09}", tm.tm_nsec), 'F' => { try!(parse_type(fmt, 'Y', tm)); try!('-'.fmt(fmt)); @@ -694,23 +694,23 @@ impl<'a> fmt::Show for TmFmt<'a> { } 'G' => return iso_week(fmt, 'G', tm), 'g' => return iso_week(fmt, 'g', tm), - 'H' => return write!(fmt, "{:02d}", tm.tm_hour), + 'H' => return write!(fmt, "{:02}", tm.tm_hour), 'I' => { let mut h = tm.tm_hour; if h == 0 { h = 12 } if h > 12 { h -= 12 } - return write!(fmt, "{:02d}", h) + return write!(fmt, "{:02}", h) } - 'j' => return write!(fmt, "{:03d}", tm.tm_yday + 1), - 'k' => return write!(fmt, "{:2d}", tm.tm_hour), + 'j' => return write!(fmt, "{:03}", tm.tm_yday + 1), + 'k' => return write!(fmt, "{:2}", tm.tm_hour), 'l' => { let mut h = tm.tm_hour; if h == 0 { h = 12 } if h > 12 { h -= 12 } - return write!(fmt, "{:2d}", h) + return write!(fmt, "{:2}", h) } - 'M' => return write!(fmt, "{:02d}", tm.tm_min), - 'm' => return write!(fmt, "{:02d}", tm.tm_mon + 1), + 'M' => return write!(fmt, "{:02}", tm.tm_min), + 'm' => return write!(fmt, "{:02}", tm.tm_mon + 1), 'n' => "\n", 'P' => if (tm.tm_hour as int) < 12 { "am" } else { "pm" }, 'p' => if (tm.tm_hour as int) < 12 { "AM" } else { "PM" }, @@ -728,7 +728,7 @@ impl<'a> fmt::Show for TmFmt<'a> { try!(' '.fmt(fmt)); return parse_type(fmt, 'p', tm); } - 'S' => return write!(fmt, "{:02d}", tm.tm_sec), + 'S' => return write!(fmt, "{:02}", tm.tm_sec), 's' => return write!(fmt, "{}", tm.to_timespec().sec), 'T' | 'X' => { try!(parse_type(fmt, 'H', tm)); @@ -738,7 +738,7 @@ impl<'a> fmt::Show for TmFmt<'a> { return parse_type(fmt, 'S', tm); } 't' => "\t", - 'U' => return write!(fmt, "{:02d}", (tm.tm_yday - tm.tm_wday + 7) / 7), + 'U' => return write!(fmt, "{:02}", (tm.tm_yday - tm.tm_wday + 7) / 7), 'u' => { let i = tm.tm_wday as int; return (if i == 0 { 7 } else { i }).fmt(fmt); @@ -752,19 +752,19 @@ impl<'a> fmt::Show for TmFmt<'a> { return parse_type(fmt, 'Y', tm); } 'W' => { - return write!(fmt, "{:02d}", + return write!(fmt, "{:02}", (tm.tm_yday - (tm.tm_wday - 1 + 7) % 7 + 7) / 7) } 'w' => return (tm.tm_wday as int).fmt(fmt), 'Y' => return (tm.tm_year as int + 1900).fmt(fmt), - 'y' => return write!(fmt, "{:02d}", (tm.tm_year as int + 1900) % 100), + 'y' => return write!(fmt, "{:02}", (tm.tm_year as int + 1900) % 100), 'Z' => if tm.tm_gmtoff == 0_i32 { "GMT"} else { "" }, // FIXME (#2350): support locale 'z' => { let sign = if tm.tm_gmtoff > 0_i32 { '+' } else { '-' }; let mut m = tm.tm_gmtoff.abs() / 60_i32; let h = m / 60_i32; m -= h * 60_i32; - return write!(fmt, "{}{:02d}{:02d}", sign, h, m); + return write!(fmt, "{}{:02}{:02}", sign, h, m); } '+' => return tm.rfc3339().fmt(fmt), '%' => "%", @@ -806,7 +806,7 @@ impl<'a> fmt::Show for TmFmt<'a> { let mut m = self.tm.tm_gmtoff.abs() / 60_i32; let h = m / 60_i32; m -= h * 60_i32; - write!(fmt, "{}{}{:02d}:{:02d}", s, sign, h as int, m as int) + write!(fmt, "{}{}{:02}:{:02}", s, sign, h as int, m as int) } } } diff --git a/src/test/bench/core-set.rs b/src/test/bench/core-set.rs index 15d89bebf75..07300b73c85 100644 --- a/src/test/bench/core-set.rs +++ b/src/test/bench/core-set.rs @@ -148,7 +148,7 @@ fn write_header(header: &str) { } fn write_row(label: &str, value: Duration) { - println!("{:30s} {} s\n", label, value); + println!("{:30} {} s\n", label, value); } fn write_results(label: &str, results: &Results) { diff --git a/src/test/bench/noise.rs b/src/test/bench/noise.rs index 1c530e3851e..419e39b53cf 100644 --- a/src/test/bench/noise.rs +++ b/src/test/bench/noise.rs @@ -115,7 +115,7 @@ fn main() { for y in range(0u, 256) { for x in range(0u, 256) { let idx = (pixels[y*256+x] / 0.2) as uint; - print!("{:c}", symbols[idx]); + print!("{}", symbols[idx]); } print!("\n"); } diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs index e39cd743ad5..4005c11e6b6 100644 --- a/src/test/bench/shootout-k-nucleotide-pipes.rs +++ b/src/test/bench/shootout-k-nucleotide-pipes.rs @@ -63,7 +63,7 @@ fn sort_and_fmt(mm: &HashMap , uint>, total: uint) -> String { let mut buffer = String::new(); for &(ref k, v) in pairs_sorted.iter() { - buffer.push_str(format!("{} {:0.3f}\n", + buffer.push_str(format!("{} {:0.3}\n", k.as_slice() .to_ascii() .to_uppercase() diff --git a/src/test/bench/shootout-k-nucleotide.rs b/src/test/bench/shootout-k-nucleotide.rs index 6ada34a5a58..b030e7bb93e 100644 --- a/src/test/bench/shootout-k-nucleotide.rs +++ b/src/test/bench/shootout-k-nucleotide.rs @@ -266,7 +266,7 @@ fn print_frequencies(frequencies: &Table, frame: uint) { } for &(count, key) in vector.iter().rev() { - println!("{} {:.3f}", + println!("{} {:.3}", key.unpack(frame).as_slice(), (count as f32 * 100.0) / (total_count as f32)); } diff --git a/src/test/bench/shootout-nbody.rs b/src/test/bench/shootout-nbody.rs index 3bcc0c25df8..b62504d7ba8 100644 --- a/src/test/bench/shootout-nbody.rs +++ b/src/test/bench/shootout-nbody.rs @@ -179,11 +179,11 @@ fn main() { let mut bodies = BODIES; offset_momentum(&mut bodies); - println!("{:.9f}", energy(&bodies)); + println!("{:.9}", energy(&bodies)); advance(&mut bodies, 0.01, n); - println!("{:.9f}", energy(&bodies)); + println!("{:.9}", energy(&bodies)); } /// Pop a mutable reference off the head of a slice, mutating the slice to no diff --git a/src/test/bench/shootout-spectralnorm.rs b/src/test/bench/shootout-spectralnorm.rs index acb289aa3ad..f76391b596b 100644 --- a/src/test/bench/shootout-spectralnorm.rs +++ b/src/test/bench/shootout-spectralnorm.rs @@ -59,7 +59,7 @@ fn main() { } else { from_str(args[1].as_slice()).unwrap() }); - println!("{:.9f}", answer); + println!("{:.9}", answer); } fn spectralnorm(n: uint) -> f64 { diff --git a/src/test/compile-fail/ifmt-bad-arg.rs b/src/test/compile-fail/ifmt-bad-arg.rs index 6829b1e2721..db7f49272aa 100644 --- a/src/test/compile-fail/ifmt-bad-arg.rs +++ b/src/test/compile-fail/ifmt-bad-arg.rs @@ -23,8 +23,8 @@ fn main() { format!("{foo}", 1, foo=2); //~ ERROR: argument never used format!("", foo=2); //~ ERROR: named argument never used - format!("{0:d} {0:s}", 1); //~ ERROR: redeclared with type `s` - format!("{foo:d} {foo:s}", foo=1); //~ ERROR: redeclared with type `s` + format!("{0:x} {0:X}", 1); //~ ERROR: redeclared with type `X` + format!("{foo:x} {foo:X}", foo=1); //~ ERROR: redeclared with type `X` format!("{foo}", foo=1, foo=2); //~ ERROR: duplicate argument format!("", foo=1, 2); //~ ERROR: positional arguments cannot follow diff --git a/src/test/compile-fail/ifmt-unimpl.rs b/src/test/compile-fail/ifmt-unimpl.rs index 194047ce848..948040496bd 100644 --- a/src/test/compile-fail/ifmt-unimpl.rs +++ b/src/test/compile-fail/ifmt-unimpl.rs @@ -9,6 +9,6 @@ // except according to those terms. fn main() { - format!("{:d}", "3"); - //~^ ERROR: the trait `core::fmt::Signed` is not implemented + format!("{:X}", "3"); + //~^ ERROR: the trait `core::fmt::UpperHex` is not implemented } diff --git a/src/test/compile-fail/issue-1448-2.rs b/src/test/compile-fail/issue-1448-2.rs index 3daced7a5ac..234fa85c89a 100644 --- a/src/test/compile-fail/issue-1448-2.rs +++ b/src/test/compile-fail/issue-1448-2.rs @@ -13,5 +13,5 @@ fn foo(a: uint) -> uint { a } fn main() { - println!("{:u}", foo(10i)); //~ ERROR mismatched types + println!("{}", foo(10i)); //~ ERROR mismatched types } diff --git a/src/test/compile-fail/issue-14853.rs b/src/test/compile-fail/issue-14853.rs index 4243b98e0dd..6515b34d964 100644 --- a/src/test/compile-fail/issue-14853.rs +++ b/src/test/compile-fail/issue-14853.rs @@ -10,17 +10,18 @@ use std::fmt::Show; +trait Str {} + trait Something { - fn yay(_: Option, thing: &[T]) -> String { - } + fn yay(_: Option, thing: &[T]); } struct X { data: u32 } impl Something for X { - fn yay(_:Option, thing: &[T]) -> String { -//~^ ERROR in method `yay`, type parameter 0 requires bound `core::str::Str`, which is not required - format!("{:s}", thing[0]) + fn yay(_:Option, thing: &[T]) { +//~^ ERROR in method `yay`, type parameter 0 requires bound `Str`, which is not required + } } diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index 59f7eda4161..b78371c51e4 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -22,12 +22,12 @@ struct A; struct B; struct C; -impl fmt::Signed for A { +impl fmt::LowerHex for A { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write("aloha".as_bytes()) } } -impl fmt::Signed for B { +impl fmt::UpperHex for B { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write("adios".as_bytes()) } @@ -55,71 +55,71 @@ pub fn main() { t!(format!("{}", 'a'), "a"); // At least exercise all the formats - t!(format!("{:b}", true), "true"); - t!(format!("{:c}", '☃'), "☃"); - t!(format!("{:d}", 10i), "10"); - t!(format!("{:i}", 10i), "10"); - t!(format!("{:u}", 10u), "10"); + t!(format!("{}", true), "true"); + t!(format!("{}", '☃'), "☃"); + t!(format!("{}", 10i), "10"); + t!(format!("{}", 10i), "10"); + t!(format!("{}", 10u), "10"); t!(format!("{:o}", 10u), "12"); t!(format!("{:x}", 10u), "a"); t!(format!("{:X}", 10u), "A"); - t!(format!("{:s}", "foo"), "foo"); - t!(format!("{:s}", "foo".to_string()), "foo"); + t!(format!("{}", "foo"), "foo"); + t!(format!("{}", "foo".to_string()), "foo"); t!(format!("{:p}", 0x1234 as *const int), "0x1234"); t!(format!("{:p}", 0x1234 as *mut int), "0x1234"); - t!(format!("{:d}", A), "aloha"); - t!(format!("{:d}", B), "adios"); - t!(format!("foo {:s} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃"); + t!(format!("{:x}", A), "aloha"); + t!(format!("{:X}", B), "adios"); + t!(format!("foo {} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃"); t!(format!("{1} {0}", 0i, 1i), "1 0"); t!(format!("{foo} {bar}", foo=0i, bar=1i), "0 1"); t!(format!("{foo} {1} {bar} {0}", 0i, 1i, foo=2i, bar=3i), "2 1 3 0"); t!(format!("{} {0}", "a"), "a a"); t!(format!("{foo_bar}", foo_bar=1i), "1"); - t!(format!("{:d}", 5i + 5i), "10"); + t!(format!("{}", 5i + 5i), "10"); t!(format!("{:#4}", C), "☃123"); let a: &fmt::Show = &1i; t!(format!("{}", a), "1"); // Formatting strings and their arguments - t!(format!("{:s}", "a"), "a"); - t!(format!("{:4s}", "a"), "a "); - t!(format!("{:4s}", "☃"), "☃ "); - t!(format!("{:>4s}", "a"), " a"); - t!(format!("{:<4s}", "a"), "a "); - t!(format!("{:^5s}", "a"), " a "); - t!(format!("{:^5s}", "aa"), " aa "); - t!(format!("{:^4s}", "a"), " a "); - t!(format!("{:^4s}", "aa"), " aa "); - t!(format!("{:.4s}", "a"), "a"); - t!(format!("{:4.4s}", "a"), "a "); - t!(format!("{:4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:<4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:>4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:^4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:>10.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:2.4s}", "aaaaa"), "aaaa"); - t!(format!("{:2.4s}", "aaaa"), "aaaa"); - t!(format!("{:2.4s}", "aaa"), "aaa"); - t!(format!("{:2.4s}", "aa"), "aa"); - t!(format!("{:2.4s}", "a"), "a "); - t!(format!("{:0>2s}", "a"), "0a"); - t!(format!("{:.*s}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:.1$s}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa"); - t!(format!("{:.a$s}", "aaaaaaaaaaaaaaaaaa", a=4), "aaaa"); - t!(format!("{:1$s}", "a", 4), "a "); - t!(format!("{1:0$s}", 4, "a"), "a "); - t!(format!("{:a$s}", "a", a=4), "a "); - t!(format!("{:-#s}", "a"), "a"); - t!(format!("{:+#s}", "a"), "a"); + t!(format!("{}", "a"), "a"); + t!(format!("{:4}", "a"), "a "); + t!(format!("{:4}", "☃"), "☃ "); + t!(format!("{:>4}", "a"), " a"); + t!(format!("{:<4}", "a"), "a "); + t!(format!("{:^5}", "a"), " a "); + t!(format!("{:^5}", "aa"), " aa "); + t!(format!("{:^4}", "a"), " a "); + t!(format!("{:^4}", "aa"), " aa "); + t!(format!("{:.4}", "a"), "a"); + t!(format!("{:4.4}", "a"), "a "); + t!(format!("{:4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:<4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:>4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:^4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:>10.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:2.4}", "aaaaa"), "aaaa"); + t!(format!("{:2.4}", "aaaa"), "aaaa"); + t!(format!("{:2.4}", "aaa"), "aaa"); + t!(format!("{:2.4}", "aa"), "aa"); + t!(format!("{:2.4}", "a"), "a "); + t!(format!("{:0>2}", "a"), "0a"); + t!(format!("{:.*}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:.1$}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa"); + t!(format!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a=4), "aaaa"); + t!(format!("{:1$}", "a", 4), "a "); + t!(format!("{1:0$}", 4, "a"), "a "); + t!(format!("{:a$}", "a", a=4), "a "); + t!(format!("{:-#}", "a"), "a"); + t!(format!("{:+#}", "a"), "a"); // Some float stuff - t!(format!("{:f}", 1.0f32), "1"); - t!(format!("{:f}", 1.0f64), "1"); - t!(format!("{:.3f}", 1.0f64), "1.000"); - t!(format!("{:10.3f}", 1.0f64), " 1.000"); - t!(format!("{:+10.3f}", 1.0f64), " +1.000"); - t!(format!("{:+10.3f}", -1.0f64), " -1.000"); + t!(format!("{:}", 1.0f32), "1"); + t!(format!("{:}", 1.0f64), "1"); + t!(format!("{:.3}", 1.0f64), "1.000"); + t!(format!("{:10.3}", 1.0f64), " 1.000"); + t!(format!("{:+10.3}", 1.0f64), " +1.000"); + t!(format!("{:+10.3}", -1.0f64), " -1.000"); t!(format!("{:e}", 1.2345e6f32), "1.2345e6"); t!(format!("{:e}", 1.2345e6f64), "1.2345e6"); @@ -164,7 +164,7 @@ fn test_write() { { let w = &mut buf as &mut io::Writer; write!(w, "{foo}", foo=4i); - write!(w, "{:s}", "hello"); + write!(w, "{}", "hello"); writeln!(w, "{}", "line"); writeln!(w, "{foo}", foo="bar"); } diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs index bd581dd657f..a29ed712d40 100644 --- a/src/test/run-pass/realloc-16687.rs +++ b/src/test/run-pass/realloc-16687.rs @@ -46,19 +46,19 @@ unsafe fn test_triangle() -> bool { static PRINT : bool = false; unsafe fn allocate(size: uint, align: uint) -> *mut u8 { - if PRINT { println!("allocate(size={:u} align={:u})", size, align); } + if PRINT { println!("allocate(size={} align={})", size, align); } let ret = heap::allocate(size, align); if ret.is_null() { alloc::oom() } - if PRINT { println!("allocate(size={:u} align={:u}) ret: 0x{:010x}", + if PRINT { println!("allocate(size={} align={}) ret: 0x{:010x}", size, align, ret as uint); } ret } unsafe fn deallocate(ptr: *mut u8, size: uint, align: uint) { - if PRINT { println!("deallocate(ptr=0x{:010x} size={:u} align={:u})", + if PRINT { println!("deallocate(ptr=0x{:010x} size={} align={})", ptr as uint, size, align); } @@ -66,7 +66,7 @@ unsafe fn test_triangle() -> bool { } unsafe fn reallocate(ptr: *mut u8, old_size: uint, size: uint, align: uint) -> *mut u8 { if PRINT { - println!("reallocate(ptr=0x{:010x} old_size={:u} size={:u} align={:u})", + println!("reallocate(ptr=0x{:010x} old_size={} size={} align={})", ptr as uint, old_size, size, align); } @@ -74,7 +74,7 @@ unsafe fn test_triangle() -> bool { if ret.is_null() { alloc::oom() } if PRINT { - println!("reallocate(ptr=0x{:010x} old_size={:u} size={:u} align={:u}) \ + println!("reallocate(ptr=0x{:010x} old_size={} size={} align={}) \ ret: 0x{:010x}", ptr as uint, old_size, size, align, ret as uint); } -- cgit 1.4.1-3-g733a5 From b64c7b83dd08c7c3afc643564d65975d57785172 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 8 Nov 2014 06:59:10 -0500 Subject: Refactor QPath to take an ast::TraitRef --- src/librustc/middle/resolve.rs | 63 +--------- src/librustc/middle/subst.rs | 4 + src/librustc/middle/traits/mod.rs | 5 +- src/librustc/middle/traits/select.rs | 2 +- src/librustc/middle/traits/util.rs | 3 +- src/librustc/middle/typeck/astconv.rs | 128 ++++++--------------- src/librustc/middle/typeck/collect.rs | 31 ++--- src/librustc/util/common.rs | 4 + src/libsyntax/ast.rs | 6 +- src/libsyntax/fold.rs | 22 +++- src/libsyntax/parse/parser.rs | 10 +- src/libsyntax/print/pprust.rs | 4 +- src/libsyntax/visit.rs | 4 +- .../associated-types-in-ambiguous-context.rs | 4 +- .../associated-types-in-wrong-context.rs | 4 +- ...alified-path-with-trait-with-type-parameters.rs | 18 +++ 16 files changed, 122 insertions(+), 190 deletions(-) create mode 100644 src/test/run-pass/associated-types-qualified-path-with-trait-with-type-parameters.rs (limited to 'src/libsyntax') diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index baf53cc34ba..f369f00a14e 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -633,6 +633,7 @@ enum TraitReferenceType { TraitDerivation, // trait T : SomeTrait { ... } TraitBoundingTypeParameter, // fn f() { ... } TraitObject, // Box SomeTrait> + TraitQPath, // :: } impl NameBindings { @@ -4532,6 +4533,7 @@ impl<'a> Resolver<'a> { TraitImplementation => "implement", TraitDerivation => "derive", TraitObject => "reference", + TraitQPath => "extract an associated type from", }; let msg = format!("attempt to {} a nonexistent trait `{}`", usage_str, path_str); @@ -4969,65 +4971,8 @@ impl<'a> Resolver<'a> { } TyQPath(ref qpath) => { - self.resolve_type(&*qpath.for_type); - - let current_module = self.current_module.clone(); - let module_path: Vec<_> = - qpath.trait_name - .segments - .iter() - .map(|ps| ps.identifier.name) - .collect(); - match self.resolve_module_path( - current_module, - module_path.as_slice(), - UseLexicalScope, - qpath.trait_name.span, - PathSearch) { - Success((ref module, _)) if module.kind.get() == - TraitModuleKind => { - match self.resolve_definition_of_name_in_module( - (*module).clone(), - qpath.item_name.name, - TypeNS) { - ChildNameDefinition(def, lp) | - ImportNameDefinition(def, lp) => { - match def { - DefAssociatedTy(trait_type_id) => { - let def = DefAssociatedTy( - trait_type_id); - self.record_def(ty.id, (def, lp)); - } - _ => { - self.resolve_error( - ty.span, - "not an associated type"); - } - } - } - NoNameDefinition => { - self.resolve_error(ty.span, - "unresolved associated \ - type"); - } - } - } - Success(..) => self.resolve_error(ty.span, "not a trait"), - Indeterminate => { - self.session.span_bug(ty.span, - "indeterminate result when \ - resolving associated type") - } - Failed(error) => { - let (span, help) = match error { - Some((span, msg)) => (span, format!("; {}", msg)), - None => (ty.span, String::new()), - }; - self.resolve_error(span, - format!("unresolved trait: {}", - help).as_slice()) - } - } + self.resolve_type(&*qpath.self_type); + self.resolve_trait_reference(ty.id, &*qpath.trait_ref, TraitQPath); } TyClosure(ref c) | TyProc(ref c) => { diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index bac417c8218..b030867fc84 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -100,6 +100,10 @@ impl<'tcx> Substs<'tcx> { regions_is_noop && self.types.is_empty() } + pub fn type_for_def(&self, ty_param_def: &ty::TypeParameterDef) -> Ty<'tcx> { + *self.types.get(ty_param_def.space, ty_param_def.index) + } + pub fn has_regions_escaping_depth(&self, depth: uint) -> bool { self.types.iter().any(|&t| ty::type_escapes_depth(t, depth)) || { match self.regions { diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index c5eacf35da9..d34d413225e 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -25,6 +25,7 @@ use std::rc::Rc; use std::slice::Items; use syntax::ast; use syntax::codemap::{Span, DUMMY_SP}; +use util::common::ErrorReported; pub use self::fulfill::FulfillmentContext; pub use self::select::SelectionContext; @@ -95,10 +96,6 @@ pub enum ObligationCauseCode<'tcx> { FieldSized, } -// An error has already been reported to the user, so no need to continue checking. -#[deriving(Clone,Show)] -pub struct ErrorReported; - pub type Obligations<'tcx> = subst::VecPerParamSpace>; pub type Selection<'tcx> = Vtable<'tcx, Obligation<'tcx>>; diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index b884cb535d7..9cb7023e1b5 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -17,7 +17,6 @@ use self::Candidate::*; use self::BuiltinBoundConditions::*; use self::EvaluationResult::*; -use super::{ErrorReported}; use super::{Obligation, ObligationCause}; use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch}; @@ -38,6 +37,7 @@ use std::cell::RefCell; use std::collections::hash_map::HashMap; use std::rc::Rc; use syntax::ast; +use util::common::ErrorReported; use util::ppaux::Repr; pub struct SelectionContext<'cx, 'tcx:'cx> { diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index dfd436bdc4d..ec49d501056 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -18,9 +18,10 @@ use std::fmt; use std::rc::Rc; use syntax::ast; use syntax::codemap::Span; +use util::common::ErrorReported; use util::ppaux::Repr; -use super::{ErrorReported, Obligation, ObligationCause, VtableImpl, +use super::{Obligation, ObligationCause, VtableImpl, VtableParam, VtableParamData, VtableImplData}; /////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index ea652bc7e65..637c1f58157 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -207,7 +207,6 @@ fn ast_path_substs_for_ty<'tcx,AC,RS>( decl_def_id: ast::DefId, decl_generics: &ty::Generics<'tcx>, self_ty: Option>, - associated_ty: Option>, path: &ast::Path) -> Substs<'tcx> where AC: AstConv<'tcx>, RS: RegionScope @@ -243,7 +242,7 @@ fn ast_path_substs_for_ty<'tcx,AC,RS>( }; create_substs_for_ast_path(this, rscope, path.span, decl_def_id, - decl_generics, self_ty, types, regions, associated_ty) + decl_generics, self_ty, types, regions) } fn create_substs_for_ast_path<'tcx,AC,RS>( @@ -254,8 +253,7 @@ fn create_substs_for_ast_path<'tcx,AC,RS>( decl_generics: &ty::Generics<'tcx>, self_ty: Option>, types: Vec>, - regions: Vec, - associated_ty: Option>) + regions: Vec) -> Substs<'tcx> where AC: AstConv<'tcx>, RS: RegionScope { @@ -366,9 +364,9 @@ fn create_substs_for_ast_path<'tcx,AC,RS>( substs.types.push( AssocSpace, this.associated_type_binding(span, - associated_ty, + self_ty, decl_def_id, - param.def_id)) + param.def_id)); } return substs; @@ -417,19 +415,17 @@ pub fn instantiate_poly_trait_ref<'tcx,AC,RS>( this: &AC, rscope: &RS, ast_trait_ref: &ast::PolyTraitRef, - self_ty: Option>, - associated_type: Option>) + self_ty: Option>) -> Rc> where AC: AstConv<'tcx>, RS: RegionScope { - instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref, self_ty, associated_type) + instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref, self_ty) } pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC, rscope: &RS, ast_trait_ref: &ast::TraitRef, - self_ty: Option>, - associated_type: Option>) + self_ty: Option>) -> Rc> where AC: AstConv<'tcx>, RS: RegionScope @@ -444,8 +440,8 @@ pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC, ast_trait_ref.path.span, ast_trait_ref.ref_id) { def::DefTrait(trait_def_id) => { - let trait_ref = Rc::new(ast_path_to_trait_ref(this, rscope, trait_def_id, self_ty, - associated_type, &ast_trait_ref.path)); + let trait_ref = Rc::new(ast_path_to_trait_ref(this, rscope, trait_def_id, + self_ty, &ast_trait_ref.path)); this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id, trait_ref.clone()); trait_ref @@ -463,7 +459,6 @@ fn ast_path_to_trait_ref<'tcx,AC,RS>( rscope: &RS, trait_def_id: ast::DefId, self_ty: Option>, - associated_type: Option>, path: &ast::Path) -> ty::TraitRef<'tcx> where AC: AstConv<'tcx>, RS: RegionScope @@ -493,8 +488,7 @@ fn ast_path_to_trait_ref<'tcx,AC,RS>( &trait_def.generics, self_ty, types, - regions, - associated_type); + regions); ty::TraitRef::new(trait_def_id, substs) } @@ -517,7 +511,6 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( did, &generics, None, - None, path); let ty = decl_ty.subst(tcx, &substs); TypeAndSubsts { substs: substs, ty: ty } @@ -558,7 +551,7 @@ pub fn ast_path_to_ty_relaxed<'tcx,AC,RS>( Substs::new(VecPerParamSpace::params_from_type(type_params), VecPerParamSpace::params_from_type(region_params)) } else { - ast_path_substs_for_ty(this, rscope, did, &generics, None, None, path) + ast_path_substs_for_ty(this, rscope, did, &generics, None, path) }; let ty = decl_ty.subst(tcx, &substs); @@ -726,7 +719,6 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( rscope, trait_def_id, None, - None, path); let empty_vec = []; let bounds = match *opt_bounds { None => empty_vec.as_slice(), @@ -750,61 +742,37 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( constr(ast_ty_to_ty(this, rscope, a_seq_ty)) } -fn associated_ty_to_ty<'tcx,AC,RS>(this: &AC, - rscope: &RS, - trait_path: &ast::Path, - for_ast_type: &ast::Ty, - trait_type_id: ast::DefId, - span: Span) - -> Ty<'tcx> - where AC: AstConv<'tcx>, RS: RegionScope +fn qpath_to_ty<'tcx,AC,RS>(this: &AC, + rscope: &RS, + ast_ty: &ast::Ty, // the TyQPath + qpath: &ast::QPath) + -> Ty<'tcx> + where AC: AstConv<'tcx>, RS: RegionScope { - debug!("associated_ty_to_ty(trait_path={}, for_ast_type={}, trait_type_id={})", - trait_path.repr(this.tcx()), - for_ast_type.repr(this.tcx()), - trait_type_id.repr(this.tcx())); - - // Find the trait that this associated type belongs to. - let trait_did = match ty::impl_or_trait_item(this.tcx(), - trait_type_id).container() { - ty::ImplContainer(_) => { - this.tcx().sess.span_bug(span, - "associated_ty_to_ty(): impl associated \ - types shouldn't go through this \ - function") - } - ty::TraitContainer(trait_id) => trait_id, - }; + debug!("qpath_to_ty(ast_ty={})", + ast_ty.repr(this.tcx())); - let for_type = ast_ty_to_ty(this, rscope, for_ast_type); - if !this.associated_types_of_trait_are_valid(for_type, trait_did) { - this.tcx().sess.span_err(span, - "this associated type is not \ - allowed in this context"); - return ty::mk_err() - } + let self_type = ast_ty_to_ty(this, rscope, &*qpath.self_type); + + debug!("qpath_to_ty: self_type={}", self_type.repr(this.tcx())); - let trait_ref = ast_path_to_trait_ref(this, + let trait_ref = instantiate_trait_ref(this, rscope, - trait_did, - None, - Some(for_type), - trait_path); - - debug!("associated_ty_to_ty(trait_ref={})", - trait_ref.repr(this.tcx())); - - let trait_def = this.get_trait_def(trait_did); - for type_parameter in trait_def.generics.types.iter() { - if type_parameter.def_id == trait_type_id { - debug!("associated_ty_to_ty(type_parameter={} substs={})", - type_parameter.repr(this.tcx()), - trait_ref.substs.repr(this.tcx())); - return *trait_ref.substs.types.get(type_parameter.space, - type_parameter.index) + &*qpath.trait_ref, + Some(self_type)); + + debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(this.tcx())); + + let trait_def = this.get_trait_def(trait_ref.def_id); + + for ty_param_def in trait_def.generics.types.get_slice(AssocSpace).iter() { + if ty_param_def.name == qpath.item_name.name { + debug!("qpath_to_ty: corresponding ty_param_def={}", ty_param_def); + return trait_ref.substs.type_for_def(ty_param_def); } } - this.tcx().sess.span_bug(span, + + this.tcx().sess.span_bug(ast_ty.span, "this associated type didn't get added \ as a parameter for some reason") } @@ -931,7 +899,6 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( rscope, trait_def_id, None, - None, path); let empty_bounds: &[ast::TyParamBound] = &[]; let ast_bounds = match *bounds { @@ -996,26 +963,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( } } ast::TyQPath(ref qpath) => { - match tcx.def_map.borrow().get(&ast_ty.id) { - None => { - tcx.sess.span_bug(ast_ty.span, - "unbound qualified path") - } - Some(&def::DefAssociatedTy(trait_type_id)) => { - associated_ty_to_ty(this, - rscope, - &qpath.trait_name, - &*qpath.for_type, - trait_type_id, - ast_ty.span) - } - Some(_) => { - tcx.sess.span_err(ast_ty.span, - "this qualified path does not name \ - an associated type"); - ty::mk_err() - } - } + qpath_to_ty(this, rscope, ast_ty, &**qpath) } ast::TyFixedLengthVec(ref ty, ref e) => { match const_eval::eval_const_expr_partial(tcx, &**e) { @@ -1411,7 +1359,7 @@ fn conv_ty_poly_trait_ref<'tcx, AC, RS>( let main_trait_bound = match partitioned_bounds.trait_bounds.remove(0) { Some(trait_bound) => { - Some(instantiate_poly_trait_ref(this, rscope, trait_bound, None, None)) + Some(instantiate_poly_trait_ref(this, rscope, trait_bound, None)) } None => { this.tcx().sess.span_err( diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index b0e8b664d06..90ad0d2f3e5 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -684,7 +684,11 @@ fn find_associated_type_in_generics<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Option>, associated_type_id: ast::DefId, generics: &ty::Generics<'tcx>) - -> Ty<'tcx> { + -> Ty<'tcx> +{ + debug!("find_associated_type_in_generics(ty={}, associated_type_id={}, generics={}", + ty.repr(tcx), associated_type_id.repr(tcx), generics.repr(tcx)); + let ty = match ty { None => { tcx.sess.span_bug(span, @@ -703,20 +707,22 @@ fn find_associated_type_in_generics<'tcx>(tcx: &ty::ctxt<'tcx>, for type_parameter in generics.types.iter() { if type_parameter.def_id == associated_type_id && type_parameter.associated_with == Some(param_id) { - return ty::mk_param_from_def(tcx, type_parameter) + return ty::mk_param_from_def(tcx, type_parameter); } } - tcx.sess.span_bug(span, - "find_associated_type_in_generics(): didn't \ - find associated type anywhere in the generics \ - list") + tcx.sess.span_err( + span, + format!("no suitable bound on `{}`", + ty.user_string(tcx))[]); + ty::mk_err() } _ => { - tcx.sess.span_bug(span, - "find_associated_type_in_generics(): self type \ - is not a parameter") - + tcx.sess.span_err( + span, + "it is currently unsupported to access associated types except \ + through a type parameter; this restriction will be lifted in time"); + ty::mk_err() } } } @@ -1155,7 +1161,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { for trait_ref in opt_trait_ref.iter() { astconv::instantiate_trait_ref(&icx, &ExplicitRscope, trait_ref, - Some(selfty), None); + Some(selfty)); } }, ast::ItemTrait(_, _, _, ref trait_methods) => { @@ -1627,7 +1633,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ccx, subst::AssocSpace, &associated_type.ty_param, - generics.types.len(subst::TypeSpace), + generics.types.len(subst::AssocSpace), &ast_generics.where_clause, Some(local_def(trait_id))); ccx.tcx.ty_param_defs.borrow_mut().insert(associated_type.ty_param.id, @@ -2019,7 +2025,6 @@ fn conv_param_bounds<'tcx,AC>(this: &AC, astconv::instantiate_poly_trait_ref(this, &ExplicitRscope, bound, - Some(param_ty.to_ty(this.tcx())), Some(param_ty.to_ty(this.tcx()))) }) .collect(); diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 06154f68613..cdbe107e11c 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -20,6 +20,10 @@ use syntax::ast; use syntax::visit; use syntax::visit::Visitor; +// An error has already been reported to the user, so no need to continue checking. +#[deriving(Clone,Show)] +pub struct ErrorReported; + pub fn time(do_it: bool, what: &str, u: U, f: |U| -> T) -> T { local_data_key!(depth: uint); if !do_it { return f(u); } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 15e14902727..61e56f0cc42 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -706,11 +706,11 @@ pub enum Expr_ { /// /// as SomeTrait>::SomeAssociatedItem /// ^~~~~ ^~~~~~~~~ ^~~~~~~~~~~~~~~~~~ -/// for_type trait_name item_name +/// self_type trait_name item_name #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub struct QPath { - pub for_type: P, - pub trait_name: Path, + pub self_type: P, + pub trait_ref: P, pub item_name: Ident, } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index b3137ff5f7e..2e6ee49f0ff 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -142,6 +142,10 @@ pub trait Folder { noop_fold_ty(t, self) } + fn fold_qpath(&mut self, t: P) -> P { + noop_fold_qpath(t, self) + } + fn fold_mod(&mut self, m: Mod) -> Mod { noop_fold_mod(m, self) } @@ -435,12 +439,8 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { fld.fold_opt_bounds(bounds), id) } - TyQPath(ref qpath) => { - TyQPath(P(QPath { - for_type: fld.fold_ty(qpath.for_type.clone()), - trait_name: fld.fold_path(qpath.trait_name.clone()), - item_name: fld.fold_ident(qpath.item_name.clone()), - })) + TyQPath(qpath) => { + TyQPath(fld.fold_qpath(qpath)) } TyFixedLengthVec(ty, e) => { TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e)) @@ -456,6 +456,16 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { }) } +pub fn noop_fold_qpath(qpath: P, fld: &mut T) -> P { + qpath.map(|qpath| { + QPath { + self_type: fld.fold_ty(qpath.self_type), + trait_ref: qpath.trait_ref.map(|tr| fld.fold_trait_ref(tr)), + item_name: fld.fold_ident(qpath.item_name), + } + }) +} + pub fn noop_fold_foreign_mod(ForeignMod {abi, view_items, items}: ForeignMod, fld: &mut T) -> ForeignMod { ForeignMod { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 50b1a2204b0..d3ae9838c6d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1502,17 +1502,17 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(keywords::Proc) { self.parse_proc_type(Vec::new()) } else if self.token == token::Lt { - // QUALIFIED PATH + // QUALIFIED PATH `::item` self.bump(); - let for_type = self.parse_ty(true); + let self_type = self.parse_ty(true); self.expect_keyword(keywords::As); - let trait_name = self.parse_path(LifetimeAndTypesWithoutColons); + let trait_ref = self.parse_trait_ref(); self.expect(&token::Gt); self.expect(&token::ModSep); let item_name = self.parse_ident(); TyQPath(P(QPath { - for_type: for_type, - trait_name: trait_name.path, + self_type: self_type, + trait_ref: P(trait_ref), item_name: item_name, })) } else if self.token == token::ModSep || diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index e6e0c33a42d..fa6b70389b4 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -744,10 +744,10 @@ impl<'a> State<'a> { } ast::TyQPath(ref qpath) => { try!(word(&mut self.s, "<")); - try!(self.print_type(&*qpath.for_type)); + try!(self.print_type(&*qpath.self_type)); try!(space(&mut self.s)); try!(self.word_space("as")); - try!(self.print_path(&qpath.trait_name, false)); + try!(self.print_trait_ref(&*qpath.trait_ref)); try!(word(&mut self.s, ">")); try!(word(&mut self.s, "::")); try!(self.print_ident(qpath.item_name)); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index efe1e18eda9..bbbec5e0626 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -403,8 +403,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { } } TyQPath(ref qpath) => { - visitor.visit_ty(&*qpath.for_type); - visitor.visit_path(&qpath.trait_name, typ.id); + visitor.visit_ty(&*qpath.self_type); + visitor.visit_trait_ref(&*qpath.trait_ref); visitor.visit_ident(typ.span, qpath.item_name); } TyFixedLengthVec(ref ty, ref expression) => { diff --git a/src/test/compile-fail/associated-types-in-ambiguous-context.rs b/src/test/compile-fail/associated-types-in-ambiguous-context.rs index a2c01fe62f6..24de1fa2f78 100644 --- a/src/test/compile-fail/associated-types-in-ambiguous-context.rs +++ b/src/test/compile-fail/associated-types-in-ambiguous-context.rs @@ -20,12 +20,12 @@ fn get(x: T, y: U) -> Get::Value {} trait Other { fn uhoh(&self, foo: U, bar: ::Value) {} - //~^ ERROR this associated type is not allowed in this context + //~^ ERROR no suitable bound on `Self` } impl Other for T { fn uhoh(&self, foo: U, bar: <(T, U) as Get>::Value) {} - //~^ ERROR this associated type is not allowed in this context + //~^ ERROR currently unsupported } trait Grab { diff --git a/src/test/compile-fail/associated-types-in-wrong-context.rs b/src/test/compile-fail/associated-types-in-wrong-context.rs index 8fbfc33896b..8cab2759ad5 100644 --- a/src/test/compile-fail/associated-types-in-wrong-context.rs +++ b/src/test/compile-fail/associated-types-in-wrong-context.rs @@ -16,7 +16,7 @@ trait Get { } fn get(x: int) -> ::Value {} -//~^ ERROR this associated type is not allowed in this context +//~^ ERROR unsupported struct Struct { x: int, @@ -24,7 +24,7 @@ struct Struct { impl Struct { fn uhoh(foo: ::Value) {} - //~^ ERROR this associated type is not allowed in this context + //~^ ERROR no suitable bound on `T` } fn main() { diff --git a/src/test/run-pass/associated-types-qualified-path-with-trait-with-type-parameters.rs b/src/test/run-pass/associated-types-qualified-path-with-trait-with-type-parameters.rs new file mode 100644 index 00000000000..1b4eb2604a8 --- /dev/null +++ b/src/test/run-pass/associated-types-qualified-path-with-trait-with-type-parameters.rs @@ -0,0 +1,18 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_types)] + +trait Foo { + type Bar; + fn get_bar() -> >::Bar; +} + +fn main() { } -- cgit 1.4.1-3-g733a5 From 6679595853705ca11f64984a055be60233321a4a Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 19 Nov 2014 15:48:38 +1100 Subject: Parse and store suffixes on literals. This adds an optional suffix at the end of a literal token: `"foo"bar`. An actual use of a suffix in a expression (or other literal that the compiler reads) is rejected in the parser. This doesn't switch the handling of numbers to this system, and doesn't outlaw illegal suffixes for them yet. --- src/librustdoc/html/highlight.rs | 18 +++-- src/libsyntax/ast.rs | 2 +- src/libsyntax/diagnostics/plugin.rs | 2 +- src/libsyntax/ext/quote.rs | 33 +++++---- src/libsyntax/parse/lexer/mod.rs | 112 ++++++++++++++++++++++-------- src/libsyntax/parse/parser.rs | 109 +++++++++++++++++++++-------- src/libsyntax/parse/token.rs | 19 ++++- src/libsyntax/print/pprust.rs | 34 +++++---- src/test/compile-fail/bad-lit-suffixes.rs | 36 ++++++++++ 9 files changed, 268 insertions(+), 97 deletions(-) create mode 100644 src/test/compile-fail/bad-lit-suffixes.rs (limited to 'src/libsyntax') diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 527ef553d99..111650f565c 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -128,13 +128,17 @@ fn doit(sess: &parse::ParseSess, mut lexer: lexer::StringReader, } } - // text literals - token::Literal(token::Byte(..)) | token::Literal(token::Char(..)) | - token::Literal(token::Binary(..)) | token::Literal(token::BinaryRaw(..)) | - token::Literal(token::Str_(..)) | token::Literal(token::StrRaw(..)) => "string", - - // number literals - token::Literal(token::Integer(..)) | token::Literal(token::Float(..)) => "number", + token::Literal(lit, _suf) => { + match lit { + // text literals + token::Byte(..) | token::Char(..) | + token::Binary(..) | token::BinaryRaw(..) | + token::Str_(..) | token::StrRaw(..) => "string", + + // number literals + token::Integer(..) | token::Float(..) => "number", + } + } // keywords are also included in the identifier set token::Ident(ident, _is_mod_sep) => { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 2158bdb416c..7b16c087859 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -838,7 +838,7 @@ impl TokenTree { tts: vec![TtToken(sp, token::Ident(token::str_to_ident("doc"), token::Plain)), TtToken(sp, token::Eq), - TtToken(sp, token::Literal(token::Str_(name)))], + TtToken(sp, token::Literal(token::Str_(name), None))], close_span: sp, })) } diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index b928fc778e8..281bde3129a 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -87,7 +87,7 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt, }, [ast::TtToken(_, token::Ident(ref code, _)), ast::TtToken(_, token::Comma), - ast::TtToken(_, token::Literal(token::StrRaw(description, _)))] => { + ast::TtToken(_, token::Literal(token::StrRaw(description, _), None))] => { (code, Some(description)) } _ => unreachable!() diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index ec51ce00605..eaa3632cf49 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -543,10 +543,13 @@ fn mk_delim(cx: &ExtCtxt, sp: Span, delim: token::DelimToken) -> P { #[allow(non_upper_case_globals)] fn mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P { macro_rules! mk_lit { - ($name: expr, $($args: expr),*) => {{ + ($name: expr, $suffix: expr, $($args: expr),*) => {{ let inner = cx.expr_call(sp, mk_token_path(cx, sp, $name), vec![$($args),*]); - - cx.expr_call(sp, mk_token_path(cx, sp, "Literal"), vec![inner]) + let suffix = match $suffix { + Some(name) => cx.expr_some(sp, mk_name(cx, sp, ast::Ident::new(name))), + None => cx.expr_none(sp) + }; + cx.expr_call(sp, mk_token_path(cx, sp, "Literal"), vec![inner, suffix]) }} } match *tok { @@ -567,32 +570,32 @@ fn mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P { vec![mk_delim(cx, sp, delim)]); } - token::Literal(token::Byte(i)) => { + token::Literal(token::Byte(i), suf) => { let e_byte = mk_name(cx, sp, i.ident()); - return mk_lit!("Byte", e_byte); + return mk_lit!("Byte", suf, e_byte); } - token::Literal(token::Char(i)) => { + token::Literal(token::Char(i), suf) => { let e_char = mk_name(cx, sp, i.ident()); - return mk_lit!("Char", e_char); + return mk_lit!("Char", suf, e_char); } - token::Literal(token::Integer(i)) => { + token::Literal(token::Integer(i), suf) => { let e_int = mk_name(cx, sp, i.ident()); - return mk_lit!("Integer", e_int); + return mk_lit!("Integer", suf, e_int); } - token::Literal(token::Float(fident)) => { + token::Literal(token::Float(fident), suf) => { let e_fident = mk_name(cx, sp, fident.ident()); - return mk_lit!("Float", e_fident); + return mk_lit!("Float", suf, e_fident); } - token::Literal(token::Str_(ident)) => { - return mk_lit!("Str_", mk_name(cx, sp, ident.ident())) + token::Literal(token::Str_(ident), suf) => { + return mk_lit!("Str_", suf, mk_name(cx, sp, ident.ident())) } - token::Literal(token::StrRaw(ident, n)) => { - return mk_lit!("StrRaw", mk_name(cx, sp, ident.ident()), cx.expr_uint(sp, n)) + token::Literal(token::StrRaw(ident, n), suf) => { + return mk_lit!("StrRaw", suf, mk_name(cx, sp, ident.ident()), cx.expr_uint(sp, n)) } token::Ident(ident, style) => { diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index b7598c7c428..55c4335941d 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -369,6 +369,25 @@ impl<'a> StringReader<'a> { self.nextnextch() == Some(c) } + /// Eats *, if possible. + fn scan_optional_raw_name(&mut self) -> Option { + if !ident_start(self.curr) { + return None + } + let start = self.last_pos; + while ident_continue(self.curr) { + self.bump(); + } + + self.with_str_from(start, |string| { + if string == "_" { + None + } else { + Some(token::intern(string)) + } + }) + } + /// PRECONDITION: self.curr is not whitespace /// Eats any kind of comment. fn scan_comment(&mut self) -> Option { @@ -638,7 +657,7 @@ impl<'a> StringReader<'a> { } /// Lex a LIT_INTEGER or a LIT_FLOAT - fn scan_number(&mut self, c: char) -> token::Token { + fn scan_number(&mut self, c: char) -> token::Lit { let mut num_digits; let mut base = 10; let start_bpos = self.last_pos; @@ -655,17 +674,17 @@ impl<'a> StringReader<'a> { } 'u' | 'i' => { self.scan_int_suffix(); - return token::Literal(token::Integer(self.name_from(start_bpos))); + return token::Integer(self.name_from(start_bpos)); }, 'f' => { let last_pos = self.last_pos; self.scan_float_suffix(); self.check_float_base(start_bpos, last_pos, base); - return token::Literal(token::Float(self.name_from(start_bpos))); + return token::Float(self.name_from(start_bpos)); } _ => { // just a 0 - return token::Literal(token::Integer(self.name_from(start_bpos))); + return token::Integer(self.name_from(start_bpos)); } } } else if c.is_digit_radix(10) { @@ -678,7 +697,7 @@ impl<'a> StringReader<'a> { self.err_span_(start_bpos, self.last_pos, "no valid digits found for number"); // eat any suffix self.scan_int_suffix(); - return token::Literal(token::Integer(token::intern("0"))); + return token::Integer(token::intern("0")); } // might be a float, but don't be greedy if this is actually an @@ -696,13 +715,13 @@ impl<'a> StringReader<'a> { } let last_pos = self.last_pos; self.check_float_base(start_bpos, last_pos, base); - return token::Literal(token::Float(self.name_from(start_bpos))); + return token::Float(self.name_from(start_bpos)); } else if self.curr_is('f') { // or it might be an integer literal suffixed as a float self.scan_float_suffix(); let last_pos = self.last_pos; self.check_float_base(start_bpos, last_pos, base); - return token::Literal(token::Float(self.name_from(start_bpos))); + return token::Float(self.name_from(start_bpos)); } else { // it might be a float if it has an exponent if self.curr_is('e') || self.curr_is('E') { @@ -710,11 +729,11 @@ impl<'a> StringReader<'a> { self.scan_float_suffix(); let last_pos = self.last_pos; self.check_float_base(start_bpos, last_pos, base); - return token::Literal(token::Float(self.name_from(start_bpos))); + return token::Float(self.name_from(start_bpos)); } // but we certainly have an integer! self.scan_int_suffix(); - return token::Literal(token::Integer(self.name_from(start_bpos))); + return token::Integer(self.name_from(start_bpos)); } } @@ -967,7 +986,9 @@ impl<'a> StringReader<'a> { } if is_dec_digit(c) { - return self.scan_number(c.unwrap()); + let num = self.scan_number(c.unwrap()); + let suffix = self.scan_optional_raw_name(); + return token::Literal(num, suffix) } if self.read_embedded_ident { @@ -1126,17 +1147,19 @@ impl<'a> StringReader<'a> { } let id = if valid { self.name_from(start) } else { token::intern("0") }; self.bump(); // advance curr past token - return token::Literal(token::Char(id)); + let suffix = self.scan_optional_raw_name(); + return token::Literal(token::Char(id), suffix); } 'b' => { self.bump(); - return match self.curr { + let lit = match self.curr { Some('\'') => self.scan_byte(), Some('"') => self.scan_byte_string(), Some('r') => self.scan_raw_byte_string(), _ => unreachable!() // Should have been a token::Ident above. }; - + let suffix = self.scan_optional_raw_name(); + return token::Literal(lit, suffix); } '"' => { let start_bpos = self.last_pos; @@ -1157,7 +1180,8 @@ impl<'a> StringReader<'a> { let id = if valid { self.name_from(start_bpos + BytePos(1)) } else { token::intern("??") }; self.bump(); - return token::Literal(token::Str_(id)); + let suffix = self.scan_optional_raw_name(); + return token::Literal(token::Str_(id), suffix); } 'r' => { let start_bpos = self.last_pos; @@ -1224,7 +1248,8 @@ impl<'a> StringReader<'a> { } else { token::intern("??") }; - return token::Literal(token::StrRaw(id, hash_count)); + let suffix = self.scan_optional_raw_name(); + return token::Literal(token::StrRaw(id, hash_count), suffix); } '-' => { if self.nextch_is('>') { @@ -1293,7 +1318,7 @@ impl<'a> StringReader<'a> { || (self.curr_is('#') && self.nextch_is('!') && !self.nextnextch_is('[')) } - fn scan_byte(&mut self) -> token::Token { + fn scan_byte(&mut self) -> token::Lit { self.bump(); let start = self.last_pos; @@ -1314,10 +1339,10 @@ impl<'a> StringReader<'a> { let id = if valid { self.name_from(start) } else { token::intern("??") }; self.bump(); // advance curr past token - return token::Literal(token::Byte(id)); + return token::Byte(id); } - fn scan_byte_string(&mut self) -> token::Token { + fn scan_byte_string(&mut self) -> token::Lit { self.bump(); let start = self.last_pos; let mut valid = true; @@ -1336,10 +1361,10 @@ impl<'a> StringReader<'a> { } let id = if valid { self.name_from(start) } else { token::intern("??") }; self.bump(); - return token::Literal(token::Binary(id)); + return token::Binary(id); } - fn scan_raw_byte_string(&mut self) -> token::Token { + fn scan_raw_byte_string(&mut self) -> token::Lit { let start_bpos = self.last_pos; self.bump(); let mut hash_count = 0u; @@ -1387,9 +1412,9 @@ impl<'a> StringReader<'a> { self.bump(); } self.bump(); - return token::Literal(token::BinaryRaw(self.name_from_to(content_start_bpos, - content_end_bpos), - hash_count)); + return token::BinaryRaw(self.name_from_to(content_start_bpos, + content_end_bpos), + hash_count); } } @@ -1536,17 +1561,17 @@ mod test { #[test] fn character_a() { assert_eq!(setup(&mk_sh(), "'a'".to_string()).next_token().tok, - token::Literal(token::Char(token::intern("a")))); + token::Literal(token::Char(token::intern("a")), None)); } #[test] fn character_space() { assert_eq!(setup(&mk_sh(), "' '".to_string()).next_token().tok, - token::Literal(token::Char(token::intern(" ")))); + token::Literal(token::Char(token::intern(" ")), None)); } #[test] fn character_escaped() { assert_eq!(setup(&mk_sh(), "'\\n'".to_string()).next_token().tok, - token::Literal(token::Char(token::intern("\\n")))); + token::Literal(token::Char(token::intern("\\n")), None)); } #[test] fn lifetime_name() { @@ -1558,7 +1583,38 @@ mod test { assert_eq!(setup(&mk_sh(), "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token() .tok, - token::Literal(token::StrRaw(token::intern("\"#a\\b\x00c\""), 3))); + token::Literal(token::StrRaw(token::intern("\"#a\\b\x00c\""), 3), None)); + } + + #[test] fn literal_suffixes() { + macro_rules! test { + ($input: expr, $tok_type: ident, $tok_contents: expr) => {{ + assert_eq!(setup(&mk_sh(), format!("{}suffix", $input)).next_token().tok, + token::Literal(token::$tok_type(token::intern($tok_contents)), + Some(token::intern("suffix")))); + // with a whitespace separator: + assert_eq!(setup(&mk_sh(), format!("{} suffix", $input)).next_token().tok, + token::Literal(token::$tok_type(token::intern($tok_contents)), + None)); + }} + } + + test!("'a'", Char, "a"); + test!("b'a'", Byte, "a"); + test!("\"a\"", Str_, "a"); + test!("b\"a\"", Binary, "a"); + test!("1234", Integer, "1234"); + test!("0b101", Integer, "0b101"); + test!("0xABC", Integer, "0xABC"); + test!("1.0", Float, "1.0"); + test!("1.0e10", Float, "1.0e10"); + + assert_eq!(setup(&mk_sh(), "r###\"raw\"###suffix".to_string()).next_token().tok, + token::Literal(token::StrRaw(token::intern("raw"), 3), + Some(token::intern("suffix")))); + assert_eq!(setup(&mk_sh(), "br###\"raw\"###suffix".to_string()).next_token().tok, + token::Literal(token::BinaryRaw(token::intern("raw"), 3), + Some(token::intern("suffix")))); } #[test] fn line_doc_comments() { @@ -1574,7 +1630,7 @@ mod test { token::Comment => { }, _ => panic!("expected a comment!") } - assert_eq!(lexer.next_token().tok, token::Literal(token::Char(token::intern("a")))); + assert_eq!(lexer.next_token().tok, token::Literal(token::Char(token::intern("a")), None)); } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4edcb182e53..b9e1fe07e71 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -646,6 +646,20 @@ impl<'a> Parser<'a> { } } + pub fn expect_no_suffix(&mut self, sp: Span, kind: &str, suffix: Option) { + match suffix { + None => {/* everything ok */} + Some(suf) => { + let text = suf.as_str(); + if text.is_empty() { + self.span_bug(sp, "found empty non-None literal suffix") + } + self.span_err(sp, &*format!("a {} with a suffix is illegal", kind)); + } + } + } + + /// Attempt to consume a `<`. If `<<` is seen, replace it with a single /// `<` and continue. If a `<` is not seen, return false. /// @@ -968,6 +982,9 @@ impl<'a> Parser<'a> { pub fn span_err(&mut self, sp: Span, m: &str) { self.sess.span_diagnostic.span_err(sp, m) } + pub fn span_bug(&mut self, sp: Span, m: &str) -> ! { + self.sess.span_diagnostic.span_bug(sp, m) + } pub fn abort_if_errors(&mut self) { self.sess.span_diagnostic.handler().abort_if_errors(); } @@ -1640,24 +1657,40 @@ impl<'a> Parser<'a> { /// Matches token_lit = LIT_INTEGER | ... pub fn lit_from_token(&mut self, tok: &token::Token) -> Lit_ { match *tok { - token::Literal(token::Byte(i)) => LitByte(parse::byte_lit(i.as_str()).val0()), - token::Literal(token::Char(i)) => LitChar(parse::char_lit(i.as_str()).val0()), - token::Literal(token::Integer(s)) => parse::integer_lit(s.as_str(), - &self.sess.span_diagnostic, - self.last_span), - token::Literal(token::Float(s)) => parse::float_lit(s.as_str()), - token::Literal(token::Str_(s)) => { - LitStr(token::intern_and_get_ident(parse::str_lit(s.as_str()).as_slice()), - ast::CookedStr) - } - token::Literal(token::StrRaw(s, n)) => { - LitStr(token::intern_and_get_ident(parse::raw_str_lit(s.as_str()).as_slice()), - ast::RawStr(n)) + token::Literal(lit, suf) => { + let (suffix_illegal, out) = match lit { + token::Byte(i) => (true, LitByte(parse::byte_lit(i.as_str()).val0())), + token::Char(i) => (true, LitChar(parse::char_lit(i.as_str()).val0())), + token::Integer(s) => (false, parse::integer_lit(s.as_str(), + &self.sess.span_diagnostic, + self.last_span)), + token::Float(s) => (false, parse::float_lit(s.as_str())), + token::Str_(s) => { + (true, + LitStr(token::intern_and_get_ident(parse::str_lit(s.as_str()).as_slice()), + ast::CookedStr)) + } + token::StrRaw(s, n) => { + (true, + LitStr( + token::intern_and_get_ident( + parse::raw_str_lit(s.as_str()).as_slice()), + ast::RawStr(n))) + } + token::Binary(i) => + (true, LitBinary(parse::binary_lit(i.as_str()))), + token::BinaryRaw(i, _) => + (true, + LitBinary(Rc::new(i.as_str().as_bytes().iter().map(|&x| x).collect()))), + }; + + if suffix_illegal { + let sp = self.last_span; + self.expect_no_suffix(sp, &*format!("{} literal", lit.short_name()), suf) + } + + out } - token::Literal(token::Binary(i)) => - LitBinary(parse::binary_lit(i.as_str())), - token::Literal(token::BinaryRaw(i, _)) => - LitBinary(Rc::new(i.as_str().as_bytes().iter().map(|&x| x).collect())), _ => { self.unexpected_last(tok); } } } @@ -2424,7 +2457,10 @@ impl<'a> Parser<'a> { } } } - token::Literal(token::Integer(n)) => { + token::Literal(token::Integer(n), suf) => { + let sp = self.span; + self.expect_no_suffix(sp, "tuple index", suf); + let index = n.as_str(); let dot = self.last_span.hi; hi = self.span.hi; @@ -2449,7 +2485,7 @@ impl<'a> Parser<'a> { } } } - token::Literal(token::Float(n)) => { + token::Literal(token::Float(n), _suf) => { self.bump(); let last_span = self.last_span; let fstr = n.as_str(); @@ -5085,12 +5121,17 @@ impl<'a> Parser<'a> { self.expect(&token::Semi); (path, the_ident) }, - token::Literal(token::Str_(..)) | token::Literal(token::StrRaw(..)) => { - let path = self.parse_str(); + token::Literal(token::Str_(..), suf) | token::Literal(token::StrRaw(..), suf) => { + let sp = self.span; + self.expect_no_suffix(sp, "extern crate name", suf); + // forgo the internal suffix check of `parse_str` to + // avoid repeats (this unwrap will always succeed due + // to the restriction of the `match`) + let (s, style, _) = self.parse_optional_str().unwrap(); self.expect_keyword(keywords::As); let the_ident = self.parse_ident(); self.expect(&token::Semi); - (Some(path), the_ident) + (Some((s, style)), the_ident) }, _ => { let span = self.span; @@ -5267,7 +5308,9 @@ impl<'a> Parser<'a> { /// the `extern` keyword, if one is found. fn parse_opt_abi(&mut self) -> Option { match self.token { - token::Literal(token::Str_(s)) | token::Literal(token::StrRaw(s, _)) => { + token::Literal(token::Str_(s), suf) | token::Literal(token::StrRaw(s, _), suf) => { + let sp = self.span; + self.expect_no_suffix(sp, "ABI spec", suf); self.bump(); let the_string = s.as_str(); match abi::lookup(the_string) { @@ -5902,21 +5945,27 @@ impl<'a> Parser<'a> { } pub fn parse_optional_str(&mut self) - -> Option<(InternedString, ast::StrStyle)> { - let (s, style) = match self.token { - token::Literal(token::Str_(s)) => (self.id_to_interned_str(s.ident()), ast::CookedStr), - token::Literal(token::StrRaw(s, n)) => { - (self.id_to_interned_str(s.ident()), ast::RawStr(n)) + -> Option<(InternedString, ast::StrStyle, Option)> { + let ret = match self.token { + token::Literal(token::Str_(s), suf) => { + (self.id_to_interned_str(s.ident()), ast::CookedStr, suf) + } + token::Literal(token::StrRaw(s, n), suf) => { + (self.id_to_interned_str(s.ident()), ast::RawStr(n), suf) } _ => return None }; self.bump(); - Some((s, style)) + Some(ret) } pub fn parse_str(&mut self) -> (InternedString, StrStyle) { match self.parse_optional_str() { - Some(s) => { s } + Some((s, style, suf)) => { + let sp = self.last_span; + self.expect_no_suffix(sp, "str literal", suf); + (s, style) + } _ => self.fatal("expected string literal") } } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index bfa6ca798b2..4272b57a4dc 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -72,6 +72,19 @@ pub enum Lit { BinaryRaw(ast::Name, uint), /* raw binary str delimited by n hash symbols */ } +impl Lit { + pub fn short_name(&self) -> &'static str { + match *self { + Byte(_) => "byte", + Char(_) => "char", + Integer(_) => "integer", + Float(_) => "float", + Str_(_) | StrRaw(..) => "str", + Binary(_) | BinaryRaw(..) => "binary str" + } + } +} + #[allow(non_camel_case_types)] #[deriving(Clone, Encodable, Decodable, PartialEq, Eq, Hash, Show)] pub enum Token { @@ -111,7 +124,7 @@ pub enum Token { CloseDelim(DelimToken), /* Literals */ - Literal(Lit), + Literal(Lit, Option), /* Name components */ Ident(ast::Ident, IdentStyle), @@ -151,7 +164,7 @@ impl Token { Ident(_, _) => true, Underscore => true, Tilde => true, - Literal(_) => true, + Literal(_, _) => true, Pound => true, At => true, Not => true, @@ -172,7 +185,7 @@ impl Token { /// Returns `true` if the token is any literal pub fn is_lit(&self) -> bool { match *self { - Literal(_) => true, + Literal(_, _) => true, _ => false, } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 7997c1ba4ef..642ffa3745d 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -236,18 +236,28 @@ pub fn token_to_string(tok: &Token) -> String { token::Question => "?".into_string(), /* Literals */ - token::Literal(token::Byte(b)) => format!("b'{}'", b.as_str()), - token::Literal(token::Char(c)) => format!("'{}'", c.as_str()), - token::Literal(token::Float(c)) => c.as_str().into_string(), - token::Literal(token::Integer(c)) => c.as_str().into_string(), - token::Literal(token::Str_(s)) => format!("\"{}\"", s.as_str()), - token::Literal(token::StrRaw(s, n)) => format!("r{delim}\"{string}\"{delim}", - delim="#".repeat(n), - string=s.as_str()), - token::Literal(token::Binary(v)) => format!("b\"{}\"", v.as_str()), - token::Literal(token::BinaryRaw(s, n)) => format!("br{delim}\"{string}\"{delim}", - delim="#".repeat(n), - string=s.as_str()), + token::Literal(lit, suf) => { + let mut out = match lit { + token::Byte(b) => format!("b'{}'", b.as_str()), + token::Char(c) => format!("'{}'", c.as_str()), + token::Float(c) => c.as_str().into_string(), + token::Integer(c) => c.as_str().into_string(), + token::Str_(s) => format!("\"{}\"", s.as_str()), + token::StrRaw(s, n) => format!("r{delim}\"{string}\"{delim}", + delim="#".repeat(n), + string=s.as_str()), + token::Binary(v) => format!("b\"{}\"", v.as_str()), + token::BinaryRaw(s, n) => format!("br{delim}\"{string}\"{delim}", + delim="#".repeat(n), + string=s.as_str()), + }; + + if let Some(s) = suf { + out.push_str(s.as_str()) + } + + out + } /* Name components */ token::Ident(s, _) => token::get_ident(s).get().into_string(), diff --git a/src/test/compile-fail/bad-lit-suffixes.rs b/src/test/compile-fail/bad-lit-suffixes.rs new file mode 100644 index 00000000000..e48bb807488 --- /dev/null +++ b/src/test/compile-fail/bad-lit-suffixes.rs @@ -0,0 +1,36 @@ +// Copyright 2014 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. + + +extern crate + "foo"suffix //~ ERROR extern crate name with a suffix is illegal + as foo; + +extern + "C"suffix //~ ERROR ABI spec with a suffix is illegal + fn foo() {} + +extern + "C"suffix //~ ERROR ABI spec with a suffix is illegal +{} + +fn main() { + ""suffix; //~ ERROR str literal with a suffix is illegal + b""suffix; //~ ERROR binary str literal with a suffix is illegal + r#""#suffix; //~ ERROR str literal with a suffix is illegal + br#""#suffix; //~ ERROR binary str literal with a suffix is illegal + 'a'suffix; //~ ERROR char literal with a suffix is illegal + b'a'suffix; //~ ERROR byte literal with a suffix is illegal + + 1234suffix; + 0b101suffix; + 1.0suffix; + 1.0e10suffix; +} -- cgit 1.4.1-3-g733a5 From 606a309d4aeb09ba88a0962c633a5b3fd4b300f6 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 19 Nov 2014 20:22:54 +1100 Subject: Switch numeric suffix parsing to use the new system. This moves errors and all handling of numeric suffixes into the parser rather than the lexer. --- src/libsyntax/parse/lexer/mod.rs | 74 +-------------- src/libsyntax/parse/mod.rs | 145 ++++++++++++++++-------------- src/libsyntax/parse/parser.rs | 25 ++++-- src/test/compile-fail/bad-lit-suffixes.rs | 13 ++- 4 files changed, 108 insertions(+), 149 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 55c4335941d..fbca4868255 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -672,16 +672,6 @@ impl<'a> StringReader<'a> { '0'...'9' | '_' | '.' => { num_digits = self.scan_digits(10) + 1; } - 'u' | 'i' => { - self.scan_int_suffix(); - return token::Integer(self.name_from(start_bpos)); - }, - 'f' => { - let last_pos = self.last_pos; - self.scan_float_suffix(); - self.check_float_base(start_bpos, last_pos, base); - return token::Float(self.name_from(start_bpos)); - } _ => { // just a 0 return token::Integer(self.name_from(start_bpos)); @@ -695,8 +685,6 @@ impl<'a> StringReader<'a> { if num_digits == 0 { self.err_span_(start_bpos, self.last_pos, "no valid digits found for number"); - // eat any suffix - self.scan_int_suffix(); return token::Integer(token::intern("0")); } @@ -711,28 +699,19 @@ impl<'a> StringReader<'a> { if self.curr.unwrap_or('\0').is_digit_radix(10) { self.scan_digits(10); self.scan_float_exponent(); - self.scan_float_suffix(); } let last_pos = self.last_pos; self.check_float_base(start_bpos, last_pos, base); return token::Float(self.name_from(start_bpos)); - } else if self.curr_is('f') { - // or it might be an integer literal suffixed as a float - self.scan_float_suffix(); - let last_pos = self.last_pos; - self.check_float_base(start_bpos, last_pos, base); - return token::Float(self.name_from(start_bpos)); } else { // it might be a float if it has an exponent if self.curr_is('e') || self.curr_is('E') { self.scan_float_exponent(); - self.scan_float_suffix(); let last_pos = self.last_pos; self.check_float_base(start_bpos, last_pos, base); return token::Float(self.name_from(start_bpos)); } // but we certainly have an integer! - self.scan_int_suffix(); return token::Integer(self.name_from(start_bpos)); } } @@ -869,55 +848,6 @@ impl<'a> StringReader<'a> { true } - /// Scan over an int literal suffix. - fn scan_int_suffix(&mut self) { - match self.curr { - Some('i') | Some('u') => { - self.bump(); - - if self.curr_is('8') { - self.bump(); - } else if self.curr_is('1') { - if !self.nextch_is('6') { - self.err_span_(self.last_pos, self.pos, - "illegal int suffix"); - } else { - self.bump(); self.bump(); - } - } else if self.curr_is('3') { - if !self.nextch_is('2') { - self.err_span_(self.last_pos, self.pos, - "illegal int suffix"); - } else { - self.bump(); self.bump(); - } - } else if self.curr_is('6') { - if !self.nextch_is('4') { - self.err_span_(self.last_pos, self.pos, - "illegal int suffix"); - } else { - self.bump(); self.bump(); - } - } - }, - _ => { } - } - } - - /// Scan over a float literal suffix - fn scan_float_suffix(&mut self) { - if self.curr_is('f') { - if (self.nextch_is('3') && self.nextnextch_is('2')) - || (self.nextch_is('6') && self.nextnextch_is('4')) { - self.bump(); - self.bump(); - self.bump(); - } else { - self.err_span_(self.last_pos, self.pos, "illegal float suffix"); - } - } - } - /// Scan over a float exponent. fn scan_float_exponent(&mut self) { if self.curr_is('e') || self.curr_is('E') { @@ -988,6 +918,7 @@ impl<'a> StringReader<'a> { if is_dec_digit(c) { let num = self.scan_number(c.unwrap()); let suffix = self.scan_optional_raw_name(); + debug!("next_token_inner: scanned number {}, {}", num, suffix); return token::Literal(num, suffix) } @@ -1609,6 +1540,9 @@ mod test { test!("1.0", Float, "1.0"); test!("1.0e10", Float, "1.0e10"); + assert_eq!(setup(&mk_sh(), "2u".to_string()).next_token().tok, + token::Literal(token::Integer(token::intern("2")), + Some(token::intern("u")))); assert_eq!(setup(&mk_sh(), "r###\"raw\"###suffix".to_string()).next_token().tok, token::Literal(token::StrRaw(token::intern("raw"), 3), Some(token::intern("suffix")))); diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 2810db4eadd..d111108269d 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -511,28 +511,41 @@ pub fn raw_str_lit(lit: &str) -> String { res } -pub fn float_lit(s: &str) -> ast::Lit_ { - debug!("float_lit: {}", s); - // FIXME #2252: bounds checking float literals is defered until trans - let s2 = s.chars().filter(|&c| c != '_').collect::(); - let s = s2.as_slice(); - - let mut ty = None; - - if s.ends_with("f32") { - ty = Some(ast::TyF32); - } else if s.ends_with("f64") { - ty = Some(ast::TyF64); - } +// check if `s` looks like i32 or u1234 etc. +fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { + s.len() > 1 && + first_chars.contains(&s.char_at(0)) && + s.slice_from(1).chars().all(|c| '0' <= c && c <= '9') +} +fn filtered_float_lit(data: token::InternedString, suffix: Option<&str>, + sd: &SpanHandler, sp: Span) -> ast::Lit_ { + debug!("filtered_float_lit: {}, {}", data, suffix); + match suffix { + Some("f32") => ast::LitFloat(data, ast::TyF32), + Some("f64") => ast::LitFloat(data, ast::TyF64), + Some(suf) => { + if suf.len() >= 2 && looks_like_width_suffix(&['f'], suf) { + // if it looks like a width, lets try to be helpful. + sd.span_err(sp, &*format!("illegal width `{}` for float literal, \ + valid widths are 32 and 64", suf.slice_from(1))); + } else { + sd.span_err(sp, &*format!("illegal suffix `{}` for float literal, \ + valid suffixes are `f32` and `f64`", suf)); + } - match ty { - Some(t) => { - ast::LitFloat(token::intern_and_get_ident(s.slice_to(s.len() - t.suffix_len())), t) - }, - None => ast::LitFloatUnsuffixed(token::intern_and_get_ident(s)) + ast::LitFloatUnsuffixed(data) + } + None => ast::LitFloatUnsuffixed(data) } } +pub fn float_lit(s: &str, suffix: Option<&str>, sd: &SpanHandler, sp: Span) -> ast::Lit_ { + debug!("float_lit: {}, {}", s, suffix); + // FIXME #2252: bounds checking float literals is defered until trans + let s = s.chars().filter(|&c| c != '_').collect::(); + let data = token::intern_and_get_ident(&*s); + filtered_float_lit(data, suffix, sd, sp) +} /// Parse a string representing a byte literal into its final form. Similar to `char_lit` pub fn byte_lit(lit: &str) -> (u8, uint) { @@ -626,24 +639,19 @@ pub fn binary_lit(lit: &str) -> Rc> { Rc::new(res) } -pub fn integer_lit(s: &str, sd: &SpanHandler, sp: Span) -> ast::Lit_ { +pub fn integer_lit(s: &str, suffix: Option<&str>, sd: &SpanHandler, sp: Span) -> ast::Lit_ { // s can only be ascii, byte indexing is fine let s2 = s.chars().filter(|&c| c != '_').collect::(); let mut s = s2.as_slice(); - debug!("parse_integer_lit: {}", s); - - if s.len() == 1 { - let n = (s.char_at(0)).to_digit(10).unwrap(); - return ast::LitInt(n as u64, ast::UnsuffixedIntLit(ast::Sign::new(n))); - } + debug!("integer_lit: {}, {}", s, suffix); let mut base = 10; let orig = s; let mut ty = ast::UnsuffixedIntLit(ast::Plus); - if s.char_at(0) == '0' { + if s.char_at(0) == '0' && s.len() > 1 { match s.char_at(1) { 'x' => base = 16, 'o' => base = 8, @@ -652,57 +660,56 @@ pub fn integer_lit(s: &str, sd: &SpanHandler, sp: Span) -> ast::Lit_ { } } + // 1f64 and 2f32 etc. are valid float literals. + match suffix { + Some(suf) if looks_like_width_suffix(&['f'], suf) => { + match base { + 16u => sd.span_err(sp, "hexadecimal float literal is not supported"), + 8u => sd.span_err(sp, "octal float literal is not supported"), + 2u => sd.span_err(sp, "binary float literal is not supported"), + _ => () + } + let ident = token::intern_and_get_ident(&*s); + return filtered_float_lit(ident, suffix, sd, sp) + } + _ => {} + } + if base != 10 { s = s.slice_from(2); } - let last = s.len() - 1; - match s.char_at(last) { - 'i' => ty = ast::SignedIntLit(ast::TyI, ast::Plus), - 'u' => ty = ast::UnsignedIntLit(ast::TyU), - '8' => { - if s.len() > 2 { - match s.char_at(last - 1) { - 'i' => ty = ast::SignedIntLit(ast::TyI8, ast::Plus), - 'u' => ty = ast::UnsignedIntLit(ast::TyU8), - _ => { } - } - } - }, - '6' => { - if s.len() > 3 && s.char_at(last - 1) == '1' { - match s.char_at(last - 2) { - 'i' => ty = ast::SignedIntLit(ast::TyI16, ast::Plus), - 'u' => ty = ast::UnsignedIntLit(ast::TyU16), - _ => { } - } - } - }, - '2' => { - if s.len() > 3 && s.char_at(last - 1) == '3' { - match s.char_at(last - 2) { - 'i' => ty = ast::SignedIntLit(ast::TyI32, ast::Plus), - 'u' => ty = ast::UnsignedIntLit(ast::TyU32), - _ => { } - } - } - }, - '4' => { - if s.len() > 3 && s.char_at(last - 1) == '6' { - match s.char_at(last - 2) { - 'i' => ty = ast::SignedIntLit(ast::TyI64, ast::Plus), - 'u' => ty = ast::UnsignedIntLit(ast::TyU64), - _ => { } + if let Some(suf) = suffix { + if suf.is_empty() { sd.span_bug(sp, "found empty literal suffix in Some")} + ty = match suf { + "i" => ast::SignedIntLit(ast::TyI, ast::Plus), + "i8" => ast::SignedIntLit(ast::TyI8, ast::Plus), + "i16" => ast::SignedIntLit(ast::TyI16, ast::Plus), + "i32" => ast::SignedIntLit(ast::TyI32, ast::Plus), + "i64" => ast::SignedIntLit(ast::TyI64, ast::Plus), + "u" => ast::UnsignedIntLit(ast::TyU), + "u8" => ast::UnsignedIntLit(ast::TyU8), + "u16" => ast::UnsignedIntLit(ast::TyU16), + "u32" => ast::UnsignedIntLit(ast::TyU32), + "u64" => ast::UnsignedIntLit(ast::TyU64), + _ => { + // i and u look like widths, so lets + // give an error message along those lines + if looks_like_width_suffix(&['i', 'u'], suf) { + sd.span_err(sp, &*format!("illegal width `{}` for integer literal; \ + valid widths are 8, 16, 32 and 64", + suf.slice_from(1))); + } else { + sd.span_err(sp, &*format!("illegal suffix `{}` for numeric literal", suf)); } + + ty } - }, - _ => { } + } } - debug!("The suffix is {}, base {}, the new string is {}, the original \ - string was {}", ty, base, s, orig); - - s = s.slice_to(s.len() - ty.suffix_len()); + debug!("integer_lit: the type is {}, base {}, the new string is {}, the original \ + string was {}, the original suffix was {}", ty, base, s, orig, suffix); let res: u64 = match ::std::num::from_str_radix(s, base) { Some(r) => r, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b9e1fe07e71..85364b8f65f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -652,9 +652,9 @@ impl<'a> Parser<'a> { Some(suf) => { let text = suf.as_str(); if text.is_empty() { - self.span_bug(sp, "found empty non-None literal suffix") + self.span_bug(sp, "found empty literal suffix in Some") } - self.span_err(sp, &*format!("a {} with a suffix is illegal", kind)); + self.span_err(sp, &*format!("{} with a suffix is illegal", kind)); } } } @@ -1661,10 +1661,23 @@ impl<'a> Parser<'a> { let (suffix_illegal, out) = match lit { token::Byte(i) => (true, LitByte(parse::byte_lit(i.as_str()).val0())), token::Char(i) => (true, LitChar(parse::char_lit(i.as_str()).val0())), - token::Integer(s) => (false, parse::integer_lit(s.as_str(), - &self.sess.span_diagnostic, - self.last_span)), - token::Float(s) => (false, parse::float_lit(s.as_str())), + + // there are some valid suffixes for integer and + // float literals, so all the handling is done + // internally. + token::Integer(s) => { + (false, parse::integer_lit(s.as_str(), + suf.as_ref().map(|s| s.as_str()), + &self.sess.span_diagnostic, + self.last_span)) + } + token::Float(s) => { + (false, parse::float_lit(s.as_str(), + suf.as_ref().map(|s| s.as_str()), + &self.sess.span_diagnostic, + self.last_span)) + } + token::Str_(s) => { (true, LitStr(token::intern_and_get_ident(parse::str_lit(s.as_str()).as_slice()), diff --git a/src/test/compile-fail/bad-lit-suffixes.rs b/src/test/compile-fail/bad-lit-suffixes.rs index e48bb807488..e142365a8ca 100644 --- a/src/test/compile-fail/bad-lit-suffixes.rs +++ b/src/test/compile-fail/bad-lit-suffixes.rs @@ -29,8 +29,13 @@ fn main() { 'a'suffix; //~ ERROR char literal with a suffix is illegal b'a'suffix; //~ ERROR byte literal with a suffix is illegal - 1234suffix; - 0b101suffix; - 1.0suffix; - 1.0e10suffix; + 1234u1024; //~ ERROR illegal width `1024` for integer literal + 1234i1024; //~ ERROR illegal width `1024` for integer literal + 1234f1024; //~ ERROR illegal width `1024` for float literal + 1234.5f1024; //~ ERROR illegal width `1024` for float literal + + 1234suffix; //~ ERROR illegal suffix `suffix` for numeric literal + 0b101suffix; //~ ERROR illegal suffix `suffix` for numeric literal + 1.0suffix; //~ ERROR illegal suffix `suffix` for numeric literal + 1.0e10suffix; //~ ERROR illegal suffix `suffix` for numeric literal } -- cgit 1.4.1-3-g733a5 From ee66c841655c3abb528841704d991c4a5a67ff9d Mon Sep 17 00:00:00 2001 From: Jakub Bukaj Date: Wed, 19 Nov 2014 23:06:53 +0100 Subject: Fixes to the roll-up --- src/doc/guide-error-handling.md | 13 +++++++------ src/libsyntax/visit.rs | 2 +- src/test/compile-fail/bad-lit-suffixes.rs | 4 ++-- src/test/compile-fail/issue-19086.rs | 10 ++++++---- 4 files changed, 16 insertions(+), 13 deletions(-) (limited to 'src/libsyntax') diff --git a/src/doc/guide-error-handling.md b/src/doc/guide-error-handling.md index 427ca4ba1a1..e2a706e59f0 100644 --- a/src/doc/guide-error-handling.md +++ b/src/doc/guide-error-handling.md @@ -84,6 +84,8 @@ While we know that we've covered all possible cases, Rust can't tell. It doesn't know that probability is between 0.0 and 1.0. So we add another case: ```rust +use Event::NewRelease; + enum Event { NewRelease, } @@ -106,7 +108,7 @@ fn descriptive_probability(event: Event) -> &'static str { } fn main() { - std::io::println(descriptive_probability(NewRelease)); + println!("{}", descriptive_probability(NewRelease)); } ``` @@ -151,15 +153,14 @@ enum Version { Version1, Version2 } #[deriving(Show)] enum ParseError { InvalidHeaderLength, InvalidVersion } - fn parse_version(header: &[u8]) -> Result { if header.len() < 1 { - return Err(InvalidHeaderLength); + return Err(ParseError::InvalidHeaderLength); } match header[0] { - 1 => Ok(Version1), - 2 => Ok(Version2), - _ => Err(InvalidVersion) + 1 => Ok(Version::Version1), + 2 => Ok(Version::Version2), + _ => Err(ParseError::InvalidVersion) } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 1eae5286d79..41a7ce7d78e 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -212,7 +212,7 @@ pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) { pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v LifetimeDef) { - visitor.visit_lifetime_ref(&lifetime_def.lifetime); + visitor.visit_name(lifetime_def.lifetime.span, lifetime_def.lifetime.name); for bound in lifetime_def.bounds.iter() { visitor.visit_lifetime_ref(bound); } diff --git a/src/test/compile-fail/bad-lit-suffixes.rs b/src/test/compile-fail/bad-lit-suffixes.rs index e142365a8ca..d10337e768c 100644 --- a/src/test/compile-fail/bad-lit-suffixes.rs +++ b/src/test/compile-fail/bad-lit-suffixes.rs @@ -36,6 +36,6 @@ fn main() { 1234suffix; //~ ERROR illegal suffix `suffix` for numeric literal 0b101suffix; //~ ERROR illegal suffix `suffix` for numeric literal - 1.0suffix; //~ ERROR illegal suffix `suffix` for numeric literal - 1.0e10suffix; //~ ERROR illegal suffix `suffix` for numeric literal + 1.0suffix; //~ ERROR illegal suffix `suffix` for float literal + 1.0e10suffix; //~ ERROR illegal suffix `suffix` for float literal } diff --git a/src/test/compile-fail/issue-19086.rs b/src/test/compile-fail/issue-19086.rs index 9fd1f228984..69201859457 100644 --- a/src/test/compile-fail/issue-19086.rs +++ b/src/test/compile-fail/issue-19086.rs @@ -8,11 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn main() { - enum Foo { - FooB { x: i32, y: i32 } - } +use Foo::FooB; +enum Foo { + FooB { x: i32, y: i32 } +} + +fn main() { let f = FooB { x: 3, y: 4 }; match f { FooB(a, b) => println!("{} {}", a, b), -- cgit 1.4.1-3-g733a5