From fd9c71072d174de01dc89cab3c93a7d3083d7331 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Thu, 3 May 2018 22:24:50 +0900 Subject: [PATCH 1/2] rustdoc: Resolve nested `impl Trait`s --- src/librustdoc/clean/mod.rs | 63 ++++++++++++------------ src/test/rustdoc/universal-impl-trait.rs | 7 +++ 2 files changed, 39 insertions(+), 31 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f63c20fb37e92..4b2dd50935bcd 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1729,8 +1729,18 @@ pub struct Generics { impl Clean for hir::Generics { fn clean(&self, cx: &DocContext) -> Generics { + let mut params = Vec::with_capacity(self.params.len()); + for p in &self.params { + let p = p.clean(cx); + if let GenericParam::Type(ref tp) = p { + if tp.synthetic == Some(hir::SyntheticTyParamKind::ImplTrait) { + cx.impl_trait_bounds.borrow_mut().insert(tp.did, tp.bounds.clone()); + } + } + params.push(p); + } let mut g = Generics { - params: self.params.clean(cx), + params, where_predicates: self.where_clause.predicates.clean(cx) }; @@ -1843,9 +1853,11 @@ pub struct Method { impl<'a> Clean for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId) { fn clean(&self, cx: &DocContext) -> Method { - let generics = self.1.clean(cx); + let (generics, decl) = enter_impl_trait(cx, || { + (self.1.clean(cx), (&*self.0.decl, self.2).clean(cx)) + }); Method { - decl: enter_impl_trait(cx, &generics.params, || (&*self.0.decl, self.2).clean(cx)), + decl, generics, unsafety: self.0.unsafety, constness: self.0.constness, @@ -1873,8 +1885,9 @@ pub struct Function { impl Clean for doctree::Function { fn clean(&self, cx: &DocContext) -> Item { - let generics = self.generics.clean(cx); - let decl = enter_impl_trait(cx, &generics.params, || (&self.decl, self.body).clean(cx)); + let (generics, decl) = enter_impl_trait(cx, || { + (self.generics.clean(cx), (&self.decl, self.body).clean(cx)) + }); Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), @@ -2113,12 +2126,12 @@ impl Clean for hir::TraitItem { MethodItem((sig, &self.generics, body).clean(cx)) } hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref names)) => { - let generics = self.generics.clean(cx); + let (generics, decl) = enter_impl_trait(cx, || { + (self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx)) + }); TyMethodItem(TyMethod { unsafety: sig.unsafety.clone(), - decl: enter_impl_trait(cx, &generics.params, || { - (&*sig.decl, &names[..]).clean(cx) - }), + decl, generics, abi: sig.abi }) @@ -3389,12 +3402,12 @@ pub struct BareFunctionDecl { impl Clean for hir::BareFnTy { fn clean(&self, cx: &DocContext) -> BareFunctionDecl { - let generic_params = self.generic_params.clean(cx); + let (generic_params, decl) = enter_impl_trait(cx, || { + (self.generic_params.clean(cx), (&*self.decl, &self.arg_names[..]).clean(cx)) + }); BareFunctionDecl { unsafety: self.unsafety, - decl: enter_impl_trait(cx, &generic_params, || { - (&*self.decl, &self.arg_names[..]).clean(cx) - }), + decl, generic_params, abi: self.abi, } @@ -3696,11 +3709,11 @@ impl Clean for hir::ForeignItem { fn clean(&self, cx: &DocContext) -> Item { let inner = match self.node { hir::ForeignItemFn(ref decl, ref names, ref generics) => { - let generics = generics.clean(cx); + let (generics, decl) = enter_impl_trait(cx, || { + (generics.clean(cx), (&**decl, &names[..]).clean(cx)) + }); ForeignFunctionItem(Function { - decl: enter_impl_trait(cx, &generics.params, || { - (&**decl, &names[..]).clean(cx) - }), + decl, generics, unsafety: hir::Unsafety::Unsafe, abi: Abi::Rust, @@ -4003,23 +4016,11 @@ pub fn def_id_to_path(cx: &DocContext, did: DefId, name: Option) -> Vec< once(crate_name).chain(relative).collect() } -pub fn enter_impl_trait(cx: &DocContext, gps: &[GenericParam], f: F) -> R +pub fn enter_impl_trait(cx: &DocContext, f: F) -> R where F: FnOnce() -> R, { - let bounds = gps.iter() - .filter_map(|p| { - if let GenericParam::Type(ref tp) = *p { - if tp.synthetic == Some(hir::SyntheticTyParamKind::ImplTrait) { - return Some((tp.did, tp.bounds.clone())); - } - } - - None - }) - .collect::>>(); - - let old_bounds = mem::replace(&mut *cx.impl_trait_bounds.borrow_mut(), bounds); + let old_bounds = mem::replace(&mut *cx.impl_trait_bounds.borrow_mut(), Default::default()); let r = f(); assert!(cx.impl_trait_bounds.borrow().is_empty()); *cx.impl_trait_bounds.borrow_mut() = old_bounds; diff --git a/src/test/rustdoc/universal-impl-trait.rs b/src/test/rustdoc/universal-impl-trait.rs index 4cf99562c5299..af51ff3d9419e 100644 --- a/src/test/rustdoc/universal-impl-trait.rs +++ b/src/test/rustdoc/universal-impl-trait.rs @@ -11,6 +11,8 @@ #![feature(universal_impl_trait)] #![crate_name = "foo"] +use std::io::Read; + // @has foo/fn.foo.html // @has - //pre 'foo(' // @matches - '_x: impl S { // @matches - '_baz:.+struct\.S\.html.+impl .+trait\.Clone\.html' pub fn baz(_baz: S) { } + + // @has - 'qux(' + // @matches - 'trait\.Read\.html' + pub fn qux(_qux: impl IntoIterator>) { + } } // @has - 'method(' From efa8a29ed6accce23aba54a38cbb26f30768fa34 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Sun, 6 May 2018 10:55:10 +0900 Subject: [PATCH 2/2] Fix assertion message generation --- src/libsyntax/lib.rs | 1 + src/libsyntax/print/pprust.rs | 2 +- src/libsyntax_ext/assert.rs | 61 ++-------------------------- src/test/compile-fail/issue-50471.rs | 19 +++++++++ 4 files changed, 25 insertions(+), 58 deletions(-) create mode 100644 src/test/compile-fail/issue-50471.rs diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index dc349c1a3e6a1..14533dda6fccc 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -27,6 +27,7 @@ #![cfg_attr(stage0, feature(i128_type))] #![feature(const_atomic_usize_new)] #![feature(rustc_attrs)] +#![feature(str_escape)] // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. #[allow(unused_extern_crates)] diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index ae045fc095a50..9d03e0b5a2827 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -651,7 +651,7 @@ pub trait PrintState<'a> { style: ast::StrStyle) -> io::Result<()> { let st = match style { ast::StrStyle::Cooked => { - (format!("\"{}\"", parse::escape_default(st))) + (format!("\"{}\"", st.escape_debug())) } ast::StrStyle::Raw(n) => { (format!("r{delim}\"{string}\"{delim}", diff --git a/src/libsyntax_ext/assert.rs b/src/libsyntax_ext/assert.rs index 8b29e6adeb9eb..d87bf24662022 100644 --- a/src/libsyntax_ext/assert.rs +++ b/src/libsyntax_ext/assert.rs @@ -41,16 +41,13 @@ pub fn expand_assert<'cx>( tts: if let Some(ts) = custom_msg_args { ts.into() } else { - // `expr_to_string` escapes the string literals with `.escape_default()` - // which escapes all non-ASCII characters with `\u`. - let escaped_expr = escape_format_string(&unescape_printable_unicode( - &pprust::expr_to_string(&cond_expr), - )); - TokenStream::from(TokenTree::Token( DUMMY_SP, token::Literal( - token::Lit::Str_(Name::intern(&format!("assertion failed: {}", escaped_expr))), + token::Lit::Str_(Name::intern(&format!( + "assertion failed: {}", + pprust::expr_to_string(&cond_expr).escape_debug() + ))), None, ), )).into() @@ -70,53 +67,3 @@ pub fn expand_assert<'cx>( ); MacEager::expr(if_expr) } - -/// Escapes a string for use as a formatting string. -fn escape_format_string(s: &str) -> String { - let mut res = String::with_capacity(s.len()); - for c in s.chars() { - res.extend(c.escape_debug()); - match c { - '{' | '}' => res.push(c), - _ => {} - } - } - res -} - -#[test] -fn test_escape_format_string() { - assert!(escape_format_string(r"foo{}\") == r"foo{{}}\\"); -} - -/// Unescapes the escaped unicodes (`\u{...}`) that are printable. -fn unescape_printable_unicode(mut s: &str) -> String { - use std::{char, u32}; - - let mut res = String::with_capacity(s.len()); - - loop { - if let Some(start) = s.find(r"\u{") { - res.push_str(&s[0..start]); - s = &s[start..]; - s.find('}') - .and_then(|end| { - let v = u32::from_str_radix(&s[3..end], 16).ok()?; - let c = char::from_u32(v)?; - // Escape unprintable characters. - res.extend(c.escape_debug()); - s = &s[end + 1..]; - Some(()) - }) - .expect("lexer should have rejected invalid escape sequences"); - } else { - res.push_str(s); - return res; - } - } -} - -#[test] -fn test_unescape_printable_unicode() { - assert!(unescape_printable_unicode(r"\u{2603}\n\u{0}") == r"☃\n\u{0}"); -} diff --git a/src/test/compile-fail/issue-50471.rs b/src/test/compile-fail/issue-50471.rs new file mode 100644 index 0000000000000..c74ba8847c1e6 --- /dev/null +++ b/src/test/compile-fail/issue-50471.rs @@ -0,0 +1,19 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// must-compile-successfully + +fn main() { + assert!({false}); + + assert!(r"\u{41}" == "A"); + + assert!(r"\u{".is_empty()); +}