From 9fd075f5af12afe91a6be7398cfc85b2903c28bb Mon Sep 17 00:00:00 2001
From: Alex Crichton
Date: Thu, 5 Jun 2014 10:07:19 -0700
Subject: [PATCH 01/16] rustc: Encode argument names for traits
This ensures that rustdoc can properly document inlined traits across crates.
Closes #14670
---
src/librustc/metadata/encoder.rs | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index 2cc06f7a32dde..e2d0a858d42b4 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -1196,6 +1196,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
&Required(ref tm) => {
encode_attributes(ebml_w, tm.attrs.as_slice());
encode_method_sort(ebml_w, 'r');
+ encode_method_argument_names(ebml_w, &*tm.decl);
}
&Provided(m) => {
@@ -1210,6 +1211,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
encode_method_sort(ebml_w, 'p');
encode_inlined_item(ecx, ebml_w,
IIMethodRef(def_id, true, m));
+ encode_method_argument_names(ebml_w, &*m.decl);
}
}
From f35328caed68528380cf5f19e4c04eba70f03638 Mon Sep 17 00:00:00 2001
From: Alex Crichton
Date: Thu, 5 Jun 2014 12:23:34 -0700
Subject: [PATCH 02/16] rustc: Avoid UB with signed division/remainder
Division and remainder by 0 are undefined behavior, and are detected at runtime.
This commit adds support for ensuring that MIN / -1 is also checked for at
runtime, as this would cause signed overflow, or undefined behvaior.
Closes #8460
---
src/librustc/middle/trans/base.rs | 83 +++++++++++++++++++++++--------
src/librustc/middle/trans/expr.rs | 8 +--
src/test/run-pass/issue-8460.rs | 35 +++++++++++++
3 files changed, 102 insertions(+), 24 deletions(-)
create mode 100644 src/test/run-pass/issue-8460.rs
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 96d059c2f84ce..9be07eaaca934 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -80,6 +80,7 @@ use libc::{c_uint, uint64_t};
use std::c_str::ToCStr;
use std::cell::{Cell, RefCell};
use std::rc::Rc;
+use std::{i8, i16, i32, i64};
use syntax::abi::{X86, X86_64, Arm, Mips, Rust, RustIntrinsic};
use syntax::ast_util::{local_def, is_local};
use syntax::attr::AttrMetaMethods;
@@ -777,35 +778,77 @@ pub fn cast_shift_rhs(op: ast::BinOp,
}
}
-pub fn fail_if_zero<'a>(
+pub fn fail_if_zero_or_overflows<'a>(
cx: &'a Block<'a>,
span: Span,
divrem: ast::BinOp,
+ lhs: ValueRef,
rhs: ValueRef,
rhs_t: ty::t)
-> &'a Block<'a> {
- let text = if divrem == ast::BiDiv {
- "attempted to divide by zero"
+ let (zero_text, overflow_text) = if divrem == ast::BiDiv {
+ ("attempted to divide by zero",
+ "attempted to divide with overflow")
} else {
- "attempted remainder with a divisor of zero"
+ ("attempted remainder with a divisor of zero",
+ "attempted remainder with overflow")
};
- let is_zero = match ty::get(rhs_t).sty {
- ty::ty_int(t) => {
- let zero = C_integral(Type::int_from_ty(cx.ccx(), t), 0u64, false);
- ICmp(cx, lib::llvm::IntEQ, rhs, zero)
- }
- ty::ty_uint(t) => {
- let zero = C_integral(Type::uint_from_ty(cx.ccx(), t), 0u64, false);
- ICmp(cx, lib::llvm::IntEQ, rhs, zero)
- }
- _ => {
- cx.sess().bug(format!("fail-if-zero on unexpected type: {}",
- ty_to_str(cx.tcx(), rhs_t)).as_slice());
- }
+ let (is_zero, is_signed) = match ty::get(rhs_t).sty {
+ ty::ty_int(t) => {
+ let zero = C_integral(Type::int_from_ty(cx.ccx(), t), 0u64, false);
+ (ICmp(cx, lib::llvm::IntEQ, rhs, zero), true)
+ }
+ ty::ty_uint(t) => {
+ let zero = C_integral(Type::uint_from_ty(cx.ccx(), t), 0u64, false);
+ (ICmp(cx, lib::llvm::IntEQ, rhs, zero), false)
+ }
+ _ => {
+ cx.sess().bug(format!("fail-if-zero on unexpected type: {}",
+ ty_to_str(cx.tcx(), rhs_t)).as_slice());
+ }
};
- with_cond(cx, is_zero, |bcx| {
- controlflow::trans_fail(bcx, span, InternedString::new(text))
- })
+ let bcx = with_cond(cx, is_zero, |bcx| {
+ controlflow::trans_fail(bcx, span, InternedString::new(zero_text))
+ });
+
+ // To quote LLVM's documentation for the sdiv instruction:
+ //
+ // Division by zero leads to undefined behavior. Overflow also leads
+ // to undefined behavior; this is a rare case, but can occur, for
+ // example, by doing a 32-bit division of -2147483648 by -1.
+ //
+ // In order to avoid undefined behavior, we perform runtime checks for
+ // signed division/remainder which would trigger overflow. For unsigned
+ // integers, no action beyond checking for zero need be taken.
+ if is_signed {
+ let (llty, min) = match ty::get(rhs_t).sty {
+ ty::ty_int(t) => {
+ let llty = Type::int_from_ty(cx.ccx(), t);
+ let min = match t {
+ ast::TyI if llty == Type::i32(cx.ccx()) => i32::MIN as u64,
+ ast::TyI => i64::MIN as u64,
+ ast::TyI8 => i8::MIN as u64,
+ ast::TyI16 => i16::MIN as u64,
+ ast::TyI32 => i32::MIN as u64,
+ ast::TyI64 => i64::MIN as u64,
+ };
+ (llty, min)
+ }
+ _ => unreachable!(),
+ };
+ let minus_one = ICmp(bcx, lib::llvm::IntEQ, rhs,
+ C_integral(llty, -1, false));
+ with_cond(bcx, minus_one, |bcx| {
+ let is_min = ICmp(bcx, lib::llvm::IntEQ, lhs,
+ C_integral(llty, min, true));
+ with_cond(bcx, is_min, |bcx| {
+ controlflow::trans_fail(bcx, span,
+ InternedString::new(overflow_text))
+ })
+ })
+ } else {
+ bcx
+ }
}
pub fn trans_external_path(ccx: &CrateContext, did: ast::DefId, t: ty::t) -> ValueRef {
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index d9ae9b0838170..9f90de61cfeb6 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -1297,8 +1297,8 @@ fn trans_eager_binop<'a>(
FDiv(bcx, lhs, rhs)
} else {
// Only zero-check integers; fp /0 is NaN
- bcx = base::fail_if_zero(bcx, binop_expr.span,
- op, rhs, rhs_t);
+ bcx = base::fail_if_zero_or_overflows(bcx, binop_expr.span,
+ op, lhs, rhs, rhs_t);
if is_signed {
SDiv(bcx, lhs, rhs)
} else {
@@ -1311,8 +1311,8 @@ fn trans_eager_binop<'a>(
FRem(bcx, lhs, rhs)
} else {
// Only zero-check integers; fp %0 is NaN
- bcx = base::fail_if_zero(bcx, binop_expr.span,
- op, rhs, rhs_t);
+ bcx = base::fail_if_zero_or_overflows(bcx, binop_expr.span,
+ op, lhs, rhs, rhs_t);
if is_signed {
SRem(bcx, lhs, rhs)
} else {
diff --git a/src/test/run-pass/issue-8460.rs b/src/test/run-pass/issue-8460.rs
new file mode 100644
index 0000000000000..762152c92038f
--- /dev/null
+++ b/src/test/run-pass/issue-8460.rs
@@ -0,0 +1,35 @@
+// 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.
+
+use std::{int, i8, i16, i32, i64};
+use std::task;
+
+fn main() {
+ assert!(task::try(proc() int::MIN / -1).is_err());
+ assert!(task::try(proc() i8::MIN / -1).is_err());
+ assert!(task::try(proc() i16::MIN / -1).is_err());
+ assert!(task::try(proc() i32::MIN / -1).is_err());
+ assert!(task::try(proc() i64::MIN / -1).is_err());
+ assert!(task::try(proc() 1i / 0).is_err());
+ assert!(task::try(proc() 1i8 / 0).is_err());
+ assert!(task::try(proc() 1i16 / 0).is_err());
+ assert!(task::try(proc() 1i32 / 0).is_err());
+ assert!(task::try(proc() 1i64 / 0).is_err());
+ assert!(task::try(proc() int::MIN % -1).is_err());
+ assert!(task::try(proc() i8::MIN % -1).is_err());
+ assert!(task::try(proc() i16::MIN % -1).is_err());
+ assert!(task::try(proc() i32::MIN % -1).is_err());
+ assert!(task::try(proc() i64::MIN % -1).is_err());
+ assert!(task::try(proc() 1i % 0).is_err());
+ assert!(task::try(proc() 1i8 % 0).is_err());
+ assert!(task::try(proc() 1i16 % 0).is_err());
+ assert!(task::try(proc() 1i32 % 0).is_err());
+ assert!(task::try(proc() 1i64 % 0).is_err());
+}
From 735e518a815bd06fa99ea343351041ba22751fe4 Mon Sep 17 00:00:00 2001
From: Luqman Aden
Date: Thu, 5 Jun 2014 18:06:33 -0400
Subject: [PATCH 03/16] librustc: Update AutoObject adjustment in writeback.
---
src/librustc/middle/typeck/check/regionck.rs | 2 +-
src/librustc/middle/typeck/check/writeback.rs | 9 +++++-
src/test/run-pass/issue-11612.rs | 30 +++++++++++++++++++
3 files changed, 39 insertions(+), 2 deletions(-)
create mode 100644 src/test/run-pass/issue-11612.rs
diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs
index e1db465424af8..e488a946d4a14 100644
--- a/src/librustc/middle/typeck/check/regionck.rs
+++ b/src/librustc/middle/typeck/check/regionck.rs
@@ -432,7 +432,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
// function check_cast_for_escaping_regions() in kind.rs
// explaining how it goes about doing that.
- let source_ty = rcx.fcx.expr_ty(expr);
+ let source_ty = rcx.resolve_node_type(expr.id);
constrain_regions_in_type(rcx, trait_region,
infer::RelateObjectBound(expr.span), source_ty);
}
diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs
index 63dc122f7cbf6..b93550384ae3b 100644
--- a/src/librustc/middle/typeck/check/writeback.rs
+++ b/src/librustc/middle/typeck/check/writeback.rs
@@ -260,7 +260,14 @@ impl<'cx> WritebackCx<'cx> {
})
}
- adjustment => adjustment
+ ty::AutoObject(trait_store, bb, def_id, substs) => {
+ ty::AutoObject(
+ self.resolve(&trait_store, reason),
+ self.resolve(&bb, reason),
+ def_id,
+ self.resolve(&substs, reason)
+ )
+ }
};
debug!("Adjustments for node {}: {:?}", id, resolved_adjustment);
self.tcx().adjustments.borrow_mut().insert(
diff --git a/src/test/run-pass/issue-11612.rs b/src/test/run-pass/issue-11612.rs
new file mode 100644
index 0000000000000..5fb2274a446fe
--- /dev/null
+++ b/src/test/run-pass/issue-11612.rs
@@ -0,0 +1,30 @@
+// 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.
+
+// #11612
+// We weren't updating the auto adjustments with all the resolved
+// type information after type check.
+
+trait A {}
+
+struct B<'a, T> {
+ f: &'a T
+}
+
+impl<'a, T> A for B<'a, T> {}
+
+fn foo(_: &A) {}
+
+fn bar(b: &B) {
+ foo(b); // Coercion should work
+ foo(b as &A); // Explicit cast should work as well
+}
+
+fn main() {}
From 6a43af3f84ef97d4d0e5b55c5336a4256bd1ebb7 Mon Sep 17 00:00:00 2001
From: Michael Woerister
Date: Thu, 5 Jun 2014 10:24:34 +0200
Subject: [PATCH 04/16] Add workaround for archive reading bug in LLDB.
LLDB contains a bug that makes it crash if an archive it reads
contains a file the name of which is exactly 16 bytes long. This
bug recently has made it impossible to debug Rust applications with
LLDB because some standard libraries triggered it indirectly:
For rlibs, rustc includes the LLVM bytecode in the archive, giving
it the extension ".bc.deflate". For liballoc (for example) this
results in the 16 character filename "alloc.bc.deflate", which is
bad.
This commit replaces the ".bc.deflate" suffix with
".bytecode.deflate" which itself is already longer than 16 bytes,
thus making sure that the bug won't be run into anymore.
The bug could still be run into with 14 character filenames because
then the .o files will trigger it. However, this is much more rare
and working around it would introduce more complexity than necessary
at the moment. It can always be done later on, if the need arises.
Fixes #14356.
---
src/librustc/back/archive.rs | 2 +-
src/librustc/back/link.rs | 6 +++++-
src/librustc/back/lto.rs | 4 ++--
3 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/src/librustc/back/archive.rs b/src/librustc/back/archive.rs
index 0b6540640b4cf..edb0a538a03dc 100644
--- a/src/librustc/back/archive.rs
+++ b/src/librustc/back/archive.rs
@@ -109,7 +109,7 @@ impl<'a> Archive<'a> {
pub fn add_rlib(&mut self, rlib: &Path, name: &str,
lto: bool) -> io::IoResult<()> {
let object = format!("{}.o", name);
- let bytecode = format!("{}.bc.deflate", name);
+ let bytecode = format!("{}.bytecode.deflate", name);
let mut ignore = vec!(bytecode.as_slice(), METADATA_FILENAME);
if lto {
ignore.push(object.as_slice());
diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs
index 546182aac34e2..b432034b81b56 100644
--- a/src/librustc/back/link.rs
+++ b/src/librustc/back/link.rs
@@ -958,8 +958,12 @@ fn link_rlib<'a>(sess: &'a Session,
// For LTO purposes, the bytecode of this library is also inserted
// into the archive.
+ // Note that we make sure that the bytecode filename in the archive is always at least
+ // 16 bytes long by adding a 16 byte extension to it. This is to work around a bug in
+ // LLDB that would cause it to crash if the name of a file in an archive was exactly
+ // 16 bytes.
let bc = obj_filename.with_extension("bc");
- let bc_deflated = obj_filename.with_extension("bc.deflate");
+ let bc_deflated = obj_filename.with_extension("bytecode.deflate");
match fs::File::open(&bc).read_to_end().and_then(|data| {
fs::File::create(&bc_deflated)
.write(match flate::deflate_bytes(data.as_slice()) {
diff --git a/src/librustc/back/lto.rs b/src/librustc/back/lto.rs
index 09dfc91896795..7449622366fc2 100644
--- a/src/librustc/back/lto.rs
+++ b/src/librustc/back/lto.rs
@@ -55,10 +55,10 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
let archive = ArchiveRO::open(&path).expect("wanted an rlib");
debug!("reading {}", name);
let bc = time(sess.time_passes(),
- format!("read {}.bc.deflate", name).as_slice(),
+ format!("read {}.bytecode.deflate", name).as_slice(),
(),
|_| {
- archive.read(format!("{}.bc.deflate",
+ archive.read(format!("{}.bytecode.deflate",
name).as_slice())
});
let bc = bc.expect("missing compressed bytecode in archive!");
From 2290dbb8cc9c72e1b6b64b7325430f031e2cd87b Mon Sep 17 00:00:00 2001
From: Alex Crichton
Date: Thu, 5 Jun 2014 15:31:45 -0700
Subject: [PATCH 05/16] rustc: Avoid 16-byte filenames in rlibs
In addition to avoiding 16-byte filenames with bytecode files, this commit also
avoids 16-byte filenames with object files pulled in from native libraries.
---
src/librustc/back/archive.rs | 9 +++++++++
src/librustc/back/link.rs | 9 +++++----
2 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/src/librustc/back/archive.rs b/src/librustc/back/archive.rs
index edb0a538a03dc..4d921fb97dc50 100644
--- a/src/librustc/back/archive.rs
+++ b/src/librustc/back/archive.rs
@@ -166,6 +166,15 @@ impl<'a> Archive<'a> {
if filename.contains(".SYMDEF") { continue }
let filename = format!("r-{}-{}", name, filename);
+ // LLDB (as mentioned in back::link) crashes on filenames of exactly
+ // 16 bytes in length. If we're including an object file with
+ // exactly 16-bytes of characters, give it some prefix so that it's
+ // not 16 bytes.
+ let filename = if filename.len() == 16 {
+ format!("lldb-fix-{}", filename)
+ } else {
+ filename
+ };
let new_filename = file.with_filename(filename);
try!(fs::rename(file, &new_filename));
inputs.push(new_filename);
diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs
index b432034b81b56..14369c7bbcd23 100644
--- a/src/librustc/back/link.rs
+++ b/src/librustc/back/link.rs
@@ -958,10 +958,11 @@ fn link_rlib<'a>(sess: &'a Session,
// For LTO purposes, the bytecode of this library is also inserted
// into the archive.
- // Note that we make sure that the bytecode filename in the archive is always at least
- // 16 bytes long by adding a 16 byte extension to it. This is to work around a bug in
- // LLDB that would cause it to crash if the name of a file in an archive was exactly
- // 16 bytes.
+ //
+ // Note that we make sure that the bytecode filename in the archive
+ // is never exactly 16 bytes long by adding a 16 byte extension to
+ // it. This is to work around a bug in LLDB that would cause it to
+ // crash if the name of a file in an archive was exactly 16 bytes.
let bc = obj_filename.with_extension("bc");
let bc_deflated = obj_filename.with_extension("bytecode.deflate");
match fs::File::open(&bc).read_to_end().and_then(|data| {
From 06f3f9a0c9f25c92b7362a4af6067df8902bd057 Mon Sep 17 00:00:00 2001
From: Alex Crichton
Date: Thu, 5 Jun 2014 17:20:59 -0700
Subject: [PATCH 06/16] rustdoc: Inline static documentation across crates
---
src/librustdoc/clean/inline.rs | 14 ++++++++++++
src/librustdoc/html/format.rs | 41 ++++++++++++++++------------------
src/librustdoc/html/render.rs | 5 +++--
3 files changed, 36 insertions(+), 24 deletions(-)
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 9db9a0e7612a6..e9ea3a7b304e0 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -88,6 +88,10 @@ fn try_inline_def(cx: &core::DocContext,
record_extern_fqn(cx, did, clean::TypeModule);
clean::ModuleItem(build_module(cx, tcx, did))
}
+ ast::DefStatic(did, mtbl) => {
+ record_extern_fqn(cx, did, clean::TypeStatic);
+ clean::StaticItem(build_static(tcx, did, mtbl))
+ }
_ => return None,
};
let fqn = csearch::get_item_path(tcx, did);
@@ -343,3 +347,13 @@ fn build_module(cx: &core::DocContext, tcx: &ty::ctxt,
is_crate: false,
}
}
+
+fn build_static(tcx: &ty::ctxt,
+ did: ast::DefId,
+ mutable: bool) -> clean::Static {
+ clean::Static {
+ type_: ty::lookup_item_type(tcx, did).ty.clean(),
+ mutability: if mutable {clean::Mutable} else {clean::Immutable},
+ expr: "\n\n\n".to_string(), // trigger the "[definition]" links
+ }
+}
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 51d2a67d6cbf4..1706f00b70a6f 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -35,6 +35,8 @@ pub struct VisSpace(pub Option);
pub struct FnStyleSpace(pub ast::FnStyle);
/// Wrapper struct for properly emitting a method declaration.
pub struct Method<'a>(pub &'a clean::SelfTy, pub &'a clean::FnDecl);
+/// Similar to VisSpace, but used for mutability
+pub struct MutableSpace(pub clean::Mutability);
impl VisSpace {
pub fn get(&self) -> Option {
@@ -438,24 +440,14 @@ impl fmt::Show for clean::Type {
clean::Unique(ref t) => write!(f, "~{}", **t),
clean::Managed(ref t) => write!(f, "@{}", **t),
clean::RawPointer(m, ref t) => {
- write!(f, "*{}{}",
- match m {
- clean::Mutable => "mut ",
- clean::Immutable => "",
- }, **t)
+ write!(f, "*{}{}", MutableSpace(m), **t)
}
clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
let lt = match *l {
Some(ref l) => format!("{} ", *l),
_ => "".to_string(),
};
- write!(f, "&{}{}{}",
- lt,
- match mutability {
- clean::Mutable => "mut ",
- clean::Immutable => "",
- },
- **ty)
+ write!(f, "&{}{}{}", lt, MutableSpace(mutability), **ty)
}
}
}
@@ -494,17 +486,13 @@ impl<'a> fmt::Show for Method<'a> {
clean::SelfStatic => {},
clean::SelfValue => args.push_str("self"),
clean::SelfOwned => args.push_str("~self"),
- clean::SelfBorrowed(Some(ref lt), clean::Immutable) => {
- args.push_str(format!("&{} self", *lt).as_slice());
- }
- clean::SelfBorrowed(Some(ref lt), clean::Mutable) => {
- args.push_str(format!("&{} mut self", *lt).as_slice());
- }
- clean::SelfBorrowed(None, clean::Mutable) => {
- args.push_str("&mut self");
+ clean::SelfBorrowed(Some(ref lt), mtbl) => {
+ args.push_str(format!("&{} {}self", *lt,
+ MutableSpace(mtbl)).as_slice());
}
- clean::SelfBorrowed(None, clean::Immutable) => {
- args.push_str("&self");
+ clean::SelfBorrowed(None, mtbl) => {
+ args.push_str(format!("&{}self",
+ MutableSpace(mtbl)).as_slice());
}
}
for (i, input) in d.inputs.values.iter().enumerate() {
@@ -605,3 +593,12 @@ impl fmt::Show for clean::ViewListIdent {
}
}
}
+
+impl fmt::Show for MutableSpace {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ MutableSpace(clean::Immutable) => Ok(()),
+ MutableSpace(clean::Mutable) => write!(f, "mut "),
+ }
+ }
+}
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 4ef3297912f9e..086232104e36d 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -51,7 +51,7 @@ use rustc::util::nodemap::NodeSet;
use clean;
use doctree;
use fold::DocFolder;
-use html::format::{VisSpace, Method, FnStyleSpace};
+use html::format::{VisSpace, Method, FnStyleSpace, MutableSpace};
use html::highlight;
use html::item_type::{ItemType, shortty};
use html::item_type;
@@ -1441,11 +1441,12 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
try!(write!(w, "
- {}static {}: {} {} |
+ {}static {}{}: {} {} |
{} |
",
VisSpace(myitem.visibility),
+ MutableSpace(s.mutability),
*myitem.name.get_ref(),
s.type_,
Initializer(s.expr.as_slice(), Item { cx: cx, item: myitem }),
From 1bc29924dc8f88c2c118b688f25ffa7c6a212276 Mon Sep 17 00:00:00 2001
From: fort
Date: Thu, 5 Jun 2014 18:13:30 -0700
Subject: [PATCH 07/16] Remove reference to ~str in documentation
---
src/libstd/macros.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs
index 0b9fc250636f4..b555c966d2d0e 100644
--- a/src/libstd/macros.rs
+++ b/src/libstd/macros.rs
@@ -212,7 +212,7 @@ macro_rules! unimplemented(
() => (fail!("not yet implemented"))
)
-/// Use the syntax described in `std::fmt` to create a value of type `~str`.
+/// Use the syntax described in `std::fmt` to create a value of type `String`.
/// See `std::fmt` for more information.
///
/// # Example
From 1bde6e3fcb32ca00cf8a8dfa0977e47f7f4a77bf Mon Sep 17 00:00:00 2001
From: Aaron Turon
Date: Thu, 5 Jun 2014 23:18:51 -0700
Subject: [PATCH 08/16] Rename Iterator::len to count
This commit carries out the request from issue #14678:
> The method `Iterator::len()` is surprising, as all the other uses of
> `len()` do not consume the value. `len()` would make more sense to be
> called `count()`, but that would collide with the current
> `Iterator::count(|T| -> bool) -> unit` method. That method, however, is
> a bit redundant, and can be easily replaced with
> `iter.filter(|x| x < 5).count()`.
> After this change, we could then define the `len()` method
> on `iter::ExactSize`.
Closes #14678.
[breaking-change]
---
src/compiletest/runtest.rs | 2 +-
src/libcollections/bitv.rs | 8 ++---
src/libcollections/dlist.rs | 8 ++---
src/libcollections/slice.rs | 2 +-
src/libcollections/smallintmap.rs | 2 +-
src/libcollections/str.rs | 34 +++++++++---------
src/libcollections/vec.rs | 14 ++++----
src/libcore/iter.rs | 48 ++++++++++++-------------
src/libcore/slice.rs | 3 +-
src/libcore/str.rs | 3 +-
src/librustc/metadata/encoder.rs | 2 +-
src/librustc/middle/entry.rs | 2 +-
src/librustc/middle/typeck/astconv.rs | 6 ++--
src/librustc/middle/typeck/check/mod.rs | 4 +--
src/librustc/util/ppaux.rs | 2 +-
src/librustdoc/html/render.rs | 2 +-
src/librustdoc/html/toc.rs | 2 +-
src/libstd/num/strconv.rs | 1 -
src/libstd/rand/mod.rs | 12 +++----
src/libstd/rt/backtrace.rs | 2 +-
src/test/run-pass/issue-13204.rs | 2 +-
21 files changed, 78 insertions(+), 83 deletions(-)
diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs
index 10428244b7115..8da984a414bda 100644
--- a/src/compiletest/runtest.rs
+++ b/src/compiletest/runtest.rs
@@ -1545,7 +1545,7 @@ fn disassemble_extract(config: &Config, _props: &TestProps,
fn count_extracted_lines(p: &Path) -> uint {
let x = File::open(&p.with_extension("ll")).read_to_end().unwrap();
let x = str::from_utf8(x.as_slice()).unwrap();
- x.lines().len()
+ x.lines().count()
}
diff --git a/src/libcollections/bitv.rs b/src/libcollections/bitv.rs
index 11c777034fe6e..58f081b25e3e5 100644
--- a/src/libcollections/bitv.rs
+++ b/src/libcollections/bitv.rs
@@ -241,17 +241,17 @@ enum Op {Union, Intersect, Assign, Difference}
/// bv.set(5, true);
/// bv.set(7, true);
/// println!("{}", bv.to_str());
-/// println!("total bits set to true: {}", bv.iter().count(|x| x));
+/// println!("total bits set to true: {}", bv.iter().filter(|x| *x).count());
///
/// // flip all values in bitvector, producing non-primes less than 10
/// bv.negate();
/// println!("{}", bv.to_str());
-/// println!("total bits set to true: {}", bv.iter().count(|x| x));
+/// println!("total bits set to true: {}", bv.iter().filter(|x| *x).count());
///
/// // reset bitvector to empty
/// bv.clear();
/// println!("{}", bv.to_str());
-/// println!("total bits set to true: {}", bv.iter().count(|x| x));
+/// println!("total bits set to true: {}", bv.iter().filter(|x| *x).count());
/// ```
#[deriving(Clone)]
pub struct Bitv {
@@ -461,7 +461,7 @@ impl Bitv {
/// bv.set(5, true);
/// bv.set(8, true);
/// // Count bits set to 1; result should be 5
- /// println!("{}", bv.iter().count(|x| x));
+ /// println!("{}", bv.iter().filter(|x| *x).count());
/// ```
#[inline]
pub fn iter<'a>(&'a self) -> Bits<'a> {
diff --git a/src/libcollections/dlist.rs b/src/libcollections/dlist.rs
index 8e3a49eecf339..94c617b58e8d2 100644
--- a/src/libcollections/dlist.rs
+++ b/src/libcollections/dlist.rs
@@ -1131,7 +1131,7 @@ mod tests {
let v = &[0, ..128];
let m: DList = v.iter().map(|&x|x).collect();
b.iter(|| {
- assert!(m.iter().len() == 128);
+ assert!(m.iter().count() == 128);
})
}
#[bench]
@@ -1139,7 +1139,7 @@ mod tests {
let v = &[0, ..128];
let mut m: DList = v.iter().map(|&x|x).collect();
b.iter(|| {
- assert!(m.mut_iter().len() == 128);
+ assert!(m.mut_iter().count() == 128);
})
}
#[bench]
@@ -1147,7 +1147,7 @@ mod tests {
let v = &[0, ..128];
let m: DList = v.iter().map(|&x|x).collect();
b.iter(|| {
- assert!(m.iter().rev().len() == 128);
+ assert!(m.iter().rev().count() == 128);
})
}
#[bench]
@@ -1155,7 +1155,7 @@ mod tests {
let v = &[0, ..128];
let mut m: DList = v.iter().map(|&x|x).collect();
b.iter(|| {
- assert!(m.mut_iter().rev().len() == 128);
+ assert!(m.mut_iter().rev().count() == 128);
})
}
}
diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs
index 0b339a9726294..e631b8b77cf9c 100644
--- a/src/libcollections/slice.rs
+++ b/src/libcollections/slice.rs
@@ -2155,7 +2155,7 @@ mod tests {
#[test]
fn test_mut_splitator() {
let mut xs = [0,1,0,2,3,0,0,4,5,0];
- assert_eq!(xs.mut_split(|x| *x == 0).len(), 6);
+ assert_eq!(xs.mut_split(|x| *x == 0).count(), 6);
for slice in xs.mut_split(|x| *x == 0) {
slice.reverse();
}
diff --git a/src/libcollections/smallintmap.rs b/src/libcollections/smallintmap.rs
index 829986e64ee66..f3118181bdcdd 100644
--- a/src/libcollections/smallintmap.rs
+++ b/src/libcollections/smallintmap.rs
@@ -31,7 +31,7 @@ pub struct SmallIntMap {
impl Container for SmallIntMap {
/// Return the number of elements in the map
fn len(&self) -> uint {
- self.v.iter().count(|elt| elt.is_some())
+ self.v.iter().filter(|elt| elt.is_some()).count()
}
/// Return true if there are no elements in the map
diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs
index ab1b1d1bd816b..5fd133b450f76 100644
--- a/src/libcollections/str.rs
+++ b/src/libcollections/str.rs
@@ -2181,7 +2181,7 @@ mod bench {
let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
let len = s.char_len();
- b.iter(|| assert_eq!(s.chars().len(), len));
+ b.iter(|| assert_eq!(s.chars().count(), len));
}
#[bench]
@@ -2194,7 +2194,7 @@ mod bench {
Mary had a little lamb, Little lamb";
let len = s.char_len();
- b.iter(|| assert_eq!(s.chars().len(), len));
+ b.iter(|| assert_eq!(s.chars().count(), len));
}
#[bench]
@@ -2202,7 +2202,7 @@ mod bench {
let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
let len = s.char_len();
- b.iter(|| assert_eq!(s.chars().rev().len(), len));
+ b.iter(|| assert_eq!(s.chars().rev().count(), len));
}
#[bench]
@@ -2210,7 +2210,7 @@ mod bench {
let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
let len = s.char_len();
- b.iter(|| assert_eq!(s.char_indices().len(), len));
+ b.iter(|| assert_eq!(s.char_indices().count(), len));
}
#[bench]
@@ -2218,14 +2218,14 @@ mod bench {
let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
let len = s.char_len();
- b.iter(|| assert_eq!(s.char_indices().rev().len(), len));
+ b.iter(|| assert_eq!(s.char_indices().rev().count(), len));
}
#[bench]
fn split_unicode_ascii(b: &mut Bencher) {
let s = "ประเทศไทย中华Việt Namประเทศไทย中华Việt Nam";
- b.iter(|| assert_eq!(s.split('V').len(), 3));
+ b.iter(|| assert_eq!(s.split('V').count(), 3));
}
#[bench]
@@ -2240,16 +2240,16 @@ mod bench {
}
let s = "ประเทศไทย中华Việt Namประเทศไทย中华Việt Nam";
- b.iter(|| assert_eq!(s.split(NotAscii('V')).len(), 3));
+ b.iter(|| assert_eq!(s.split(NotAscii('V')).count(), 3));
}
#[bench]
fn split_ascii(b: &mut Bencher) {
let s = "Mary had a little lamb, Little lamb, little-lamb.";
- let len = s.split(' ').len();
+ let len = s.split(' ').count();
- b.iter(|| assert_eq!(s.split(' ').len(), len));
+ b.iter(|| assert_eq!(s.split(' ').count(), len));
}
#[bench]
@@ -2264,34 +2264,34 @@ mod bench {
fn only_ascii(&self) -> bool { false }
}
let s = "Mary had a little lamb, Little lamb, little-lamb.";
- let len = s.split(' ').len();
+ let len = s.split(' ').count();
- b.iter(|| assert_eq!(s.split(NotAscii(' ')).len(), len));
+ b.iter(|| assert_eq!(s.split(NotAscii(' ')).count(), len));
}
#[bench]
fn split_extern_fn(b: &mut Bencher) {
let s = "Mary had a little lamb, Little lamb, little-lamb.";
- let len = s.split(' ').len();
+ let len = s.split(' ').count();
fn pred(c: char) -> bool { c == ' ' }
- b.iter(|| assert_eq!(s.split(pred).len(), len));
+ b.iter(|| assert_eq!(s.split(pred).count(), len));
}
#[bench]
fn split_closure(b: &mut Bencher) {
let s = "Mary had a little lamb, Little lamb, little-lamb.";
- let len = s.split(' ').len();
+ let len = s.split(' ').count();
- b.iter(|| assert_eq!(s.split(|c: char| c == ' ').len(), len));
+ b.iter(|| assert_eq!(s.split(|c: char| c == ' ').count(), len));
}
#[bench]
fn split_slice(b: &mut Bencher) {
let s = "Mary had a little lamb, Little lamb, little-lamb.";
- let len = s.split(' ').len();
+ let len = s.split(' ').count();
- b.iter(|| assert_eq!(s.split(&[' ']).len(), len));
+ b.iter(|| assert_eq!(s.split(&[' ']).count(), len));
}
#[bench]
diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs
index aa80a131811c2..6ca21262f51cc 100644
--- a/src/libcollections/vec.rs
+++ b/src/libcollections/vec.rs
@@ -1772,23 +1772,23 @@ mod tests {
assert_eq!(v.pop(), Some(()));
assert_eq!(v.pop(), None);
- assert_eq!(v.iter().len(), 0);
+ assert_eq!(v.iter().count(), 0);
v.push(());
- assert_eq!(v.iter().len(), 1);
+ assert_eq!(v.iter().count(), 1);
v.push(());
- assert_eq!(v.iter().len(), 2);
+ assert_eq!(v.iter().count(), 2);
for &() in v.iter() {}
- assert_eq!(v.mut_iter().len(), 2);
+ assert_eq!(v.mut_iter().count(), 2);
v.push(());
- assert_eq!(v.mut_iter().len(), 3);
+ assert_eq!(v.mut_iter().count(), 3);
v.push(());
- assert_eq!(v.mut_iter().len(), 4);
+ assert_eq!(v.mut_iter().count(), 4);
for &() in v.mut_iter() {}
unsafe { v.set_len(0); }
- assert_eq!(v.mut_iter().len(), 0);
+ assert_eq!(v.mut_iter().count(), 0);
}
#[test]
diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs
index 875c852d8ae61..64c53b658eff1 100644
--- a/src/libcore/iter.rs
+++ b/src/libcore/iter.rs
@@ -529,11 +529,11 @@ pub trait Iterator {
/// ```rust
/// let a = [1, 2, 3, 4, 5];
/// let mut it = a.iter();
- /// assert!(it.len() == 5);
- /// assert!(it.len() == 0);
+ /// assert!(it.count() == 5);
+ /// assert!(it.count() == 0);
/// ```
#[inline]
- fn len(&mut self) -> uint {
+ fn count(&mut self) -> uint {
self.fold(0, |cnt, _x| cnt + 1)
}
@@ -591,16 +591,6 @@ pub trait Iterator {
None
}
- /// Count the number of elements satisfying the specified predicate
- #[inline]
- fn count(&mut self, predicate: |A| -> bool) -> uint {
- let mut i = 0;
- for x in *self {
- if predicate(x) { i += 1 }
- }
- i
- }
-
/// Return the element that gives the maximum value from the
/// specified function.
///
@@ -738,6 +728,14 @@ pub trait ExactSize : DoubleEndedIterator {
}
None
}
+
+ #[inline]
+ /// Return the exact length of the iterator.
+ fn len(&self) -> uint {
+ let (lower, upper) = self.size_hint();
+ assert!(upper == Some(lower));
+ lower
+ }
}
// All adaptors that preserve the size of the wrapped iterator are fine
@@ -2594,9 +2592,9 @@ mod tests {
#[test]
fn test_iterator_len() {
let v = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
- assert_eq!(v.slice(0, 4).iter().len(), 4);
- assert_eq!(v.slice(0, 10).iter().len(), 10);
- assert_eq!(v.slice(0, 0).iter().len(), 0);
+ assert_eq!(v.slice(0, 4).iter().count(), 4);
+ assert_eq!(v.slice(0, 10).iter().count(), 10);
+ assert_eq!(v.slice(0, 0).iter().count(), 0);
}
#[test]
@@ -2712,9 +2710,9 @@ mod tests {
#[test]
fn test_count() {
let xs = &[1, 2, 2, 1, 5, 9, 0, 2];
- assert_eq!(xs.iter().count(|x| *x == 2), 3);
- assert_eq!(xs.iter().count(|x| *x == 5), 1);
- assert_eq!(xs.iter().count(|x| *x == 95), 0);
+ assert_eq!(xs.iter().filter(|x| **x == 2).count(), 3);
+ assert_eq!(xs.iter().filter(|x| **x == 5).count(), 1);
+ assert_eq!(xs.iter().filter(|x| **x == 95).count(), 0);
}
#[test]
@@ -3044,10 +3042,10 @@ mod tests {
assert!(range(-10i, -1).collect::>() ==
vec![-10, -9, -8, -7, -6, -5, -4, -3, -2]);
assert!(range(0i, 5).rev().collect::>() == vec![4, 3, 2, 1, 0]);
- assert_eq!(range(200, -5).len(), 0);
- assert_eq!(range(200, -5).rev().len(), 0);
- assert_eq!(range(200, 200).len(), 0);
- assert_eq!(range(200, 200).rev().len(), 0);
+ assert_eq!(range(200, -5).count(), 0);
+ assert_eq!(range(200, -5).rev().count(), 0);
+ assert_eq!(range(200, 200).count(), 0);
+ assert_eq!(range(200, 200).rev().count(), 0);
assert_eq!(range(0i, 100).size_hint(), (100, Some(100)));
// this test is only meaningful when sizeof uint < sizeof u64
@@ -3062,8 +3060,8 @@ mod tests {
vec![0i, 1, 2, 3, 4, 5]);
assert!(range_inclusive(0i, 5).rev().collect::>() ==
vec![5i, 4, 3, 2, 1, 0]);
- assert_eq!(range_inclusive(200, -5).len(), 0);
- assert_eq!(range_inclusive(200, -5).rev().len(), 0);
+ assert_eq!(range_inclusive(200, -5).count(), 0);
+ assert_eq!(range_inclusive(200, -5).rev().count(), 0);
assert!(range_inclusive(200, 200).collect::>() == vec![200]);
assert!(range_inclusive(200, 200).rev().collect::>() == vec![200]);
}
diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs
index 0257911e8c086..4dea1fd75a4bf 100644
--- a/src/libcore/slice.rs
+++ b/src/libcore/slice.rs
@@ -252,7 +252,7 @@ pub mod traits {
use super::*;
use cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering, Equiv};
- use iter::{order, Iterator};
+ use iter::order;
use container::Container;
impl<'a,T:PartialEq> PartialEq for &'a [T] {
@@ -1141,7 +1141,6 @@ impl<'a, T:Clone> MutableCloneableVector for &'a mut [T] {
/// Unsafe operations
pub mod raw {
use mem::transmute;
- use iter::Iterator;
use ptr::RawPtr;
use raw::Slice;
use option::{None, Option, Some};
diff --git a/src/libcore/str.rs b/src/libcore/str.rs
index c08f30152d592..936b698d4b10a 100644
--- a/src/libcore/str.rs
+++ b/src/libcore/str.rs
@@ -867,7 +867,6 @@ static TAG_CONT_U8: u8 = 128u8;
pub mod raw {
use mem;
use container::Container;
- use iter::Iterator;
use ptr::RawPtr;
use raw::Slice;
use slice::{ImmutableVector};
@@ -1725,7 +1724,7 @@ impl<'a> StrSlice<'a> for &'a str {
fn is_alphanumeric(&self) -> bool { self.chars().all(char::is_alphanumeric) }
#[inline]
- fn char_len(&self) -> uint { self.chars().len() }
+ fn char_len(&self) -> uint { self.chars().count() }
#[inline]
fn slice(&self, begin: uint, end: uint) -> &'a str {
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index e2d0a858d42b4..cd2f3360f830d 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -351,7 +351,7 @@ fn encode_enum_variant_info(ecx: &EncodeContext,
fn encode_path + Clone>(ebml_w: &mut Encoder,
mut path: PI) {
ebml_w.start_tag(tag_path);
- ebml_w.wr_tagged_u32(tag_path_len, path.clone().len() as u32);
+ ebml_w.wr_tagged_u32(tag_path_len, path.clone().count() as u32);
for pe in path {
let tag = match pe {
ast_map::PathMod(_) => tag_path_elem_mod,
diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs
index 1b7ed90237fd9..9a5f226bb73ce 100644
--- a/src/librustc/middle/entry.rs
+++ b/src/librustc/middle/entry.rs
@@ -82,7 +82,7 @@ fn find_item(item: &Item, ctxt: &mut EntryContext) {
ItemFn(..) => {
if item.ident.name == ctxt.main_name {
ctxt.ast_map.with_path(item.id, |mut path| {
- if path.len() == 1 {
+ if path.count() == 1 {
// This is a top-level function so can be 'main'
if ctxt.main_fn.is_none() {
ctxt.main_fn = Some((item.id, item.span));
diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs
index f8821a86e7177..bdb23aea06708 100644
--- a/src/librustc/middle/typeck/astconv.rs
+++ b/src/librustc/middle/typeck/astconv.rs
@@ -191,11 +191,11 @@ fn ast_path_substs(
};
// Convert the type parameters supplied by the user.
- let supplied_ty_param_count = path.segments.iter().flat_map(|s| s.types.iter()).len();
+ let supplied_ty_param_count = path.segments.iter().flat_map(|s| s.types.iter()).count();
let formal_ty_param_count = decl_generics.type_param_defs().len();
let required_ty_param_count = decl_generics.type_param_defs().iter()
.take_while(|x| x.default.is_none())
- .len();
+ .count();
if supplied_ty_param_count < required_ty_param_count {
let expected = if required_ty_param_count < formal_ty_param_count {
"expected at least"
@@ -407,7 +407,7 @@ pub fn ast_ty_to_builtin_ty 1 {
+ .count() > 1 {
this.tcx()
.sess
.span_err(path.span,
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index a09c92d4db01f..d25fc9cc5bcdb 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -1615,7 +1615,7 @@ fn check_type_parameter_positions_in_path(function_context: &FnCtxt,
let formal_ty_param_count = generics.type_param_defs().len();
let required_ty_param_count = generics.type_param_defs().iter()
.take_while(|x| x.default.is_none())
- .len();
+ .count();
let supplied_ty_param_count = trait_segment.types.len();
if supplied_ty_param_count < required_ty_param_count {
let msg = if required_ty_param_count < generics.type_param_defs().len() {
@@ -3876,7 +3876,7 @@ pub fn instantiate_path(fcx: &FnCtxt,
let ty_param_count = tpt.generics.type_param_defs().len();
let ty_param_req = tpt.generics.type_param_defs().iter()
.take_while(|x| x.default.is_none())
- .len();
+ .count();
let mut ty_substs_len = 0;
for segment in pth.segments.iter() {
ty_substs_len += segment.types.len()
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index a9ac1e76f1187..eb84ed32335b9 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -456,7 +456,7 @@ pub fn parameterized(cx: &ctxt,
Some(default) => default.subst(cx, &substs) == actual,
None => false
}
- }).len()
+ }).count()
} else {
0
};
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 086232104e36d..20d4d677bc08b 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -2043,7 +2043,7 @@ fn build_sidebar(m: &clean::Module) -> HashMap> {
impl<'a> fmt::Show for Source<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let Source(s) = *self;
- let lines = s.lines().len();
+ let lines = s.lines().count();
let mut cols = 0;
let mut tmp = lines;
while tmp > 0 {
diff --git a/src/librustdoc/html/toc.rs b/src/librustdoc/html/toc.rs
index 2356d4c754fa9..5bc6d8031ac29 100644
--- a/src/librustdoc/html/toc.rs
+++ b/src/librustdoc/html/toc.rs
@@ -32,7 +32,7 @@ pub struct Toc {
impl Toc {
fn count_entries_with_level(&self, level: u32) -> uint {
- self.entries.iter().count(|e| e.level == level)
+ self.entries.iter().filter(|e| e.level == level).count()
}
}
diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs
index 54ca579780490..133a8db90facc 100644
--- a/src/libstd/num/strconv.rs
+++ b/src/libstd/num/strconv.rs
@@ -13,7 +13,6 @@
use char;
use clone::Clone;
use container::Container;
-use iter::Iterator;
use num::{NumCast, Zero, One, cast, Int};
use num::{Float, FPNaN, FPInfinite, ToPrimitive};
use num;
diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs
index 61a2ffd383d0a..ee1935628871e 100644
--- a/src/libstd/rand/mod.rs
+++ b/src/libstd/rand/mod.rs
@@ -353,17 +353,17 @@ mod test {
#[test]
fn test_gen_ascii_str() {
let mut r = task_rng();
- assert_eq!(r.gen_ascii_chars().take(0).len(), 0u);
- assert_eq!(r.gen_ascii_chars().take(10).len(), 10u);
- assert_eq!(r.gen_ascii_chars().take(16).len(), 16u);
+ assert_eq!(r.gen_ascii_chars().take(0).count(), 0u);
+ assert_eq!(r.gen_ascii_chars().take(10).count(), 10u);
+ assert_eq!(r.gen_ascii_chars().take(16).count(), 16u);
}
#[test]
fn test_gen_vec() {
let mut r = task_rng();
- assert_eq!(r.gen_iter::().take(0).len(), 0u);
- assert_eq!(r.gen_iter::().take(10).len(), 10u);
- assert_eq!(r.gen_iter::().take(16).len(), 16u);
+ assert_eq!(r.gen_iter::().take(0).count(), 0u);
+ assert_eq!(r.gen_iter::().take(10).count(), 10u);
+ assert_eq!(r.gen_iter::().take(16).count(), 16u);
}
#[test]
diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs
index ac421bf78be7e..fe6d84d4d2e2a 100644
--- a/src/libstd/rt/backtrace.rs
+++ b/src/libstd/rt/backtrace.rs
@@ -84,7 +84,7 @@ fn demangle(writer: &mut Writer, s: &str) -> IoResult<()> {
if i == 0 {
valid = chars.next().is_none();
break
- } else if chars.by_ref().take(i - 1).len() != i - 1 {
+ } else if chars.by_ref().take(i - 1).count() != i - 1 {
valid = false;
}
}
diff --git a/src/test/run-pass/issue-13204.rs b/src/test/run-pass/issue-13204.rs
index 5fb9119849cab..f9b542dea56f0 100644
--- a/src/test/run-pass/issue-13204.rs
+++ b/src/test/run-pass/issue-13204.rs
@@ -14,7 +14,7 @@
pub trait Foo {
fn bar<'a, I: Iterator<&'a ()>>(&self, it: I) -> uint {
let mut xs = it.filter(|_| true);
- xs.len()
+ xs.count()
}
}
From b662aa5ec0eb1971111bf10f9c3ef2a8f226bb0a Mon Sep 17 00:00:00 2001
From: Steven Fackler
Date: Thu, 5 Jun 2014 23:22:01 -0700
Subject: [PATCH 09/16] Implement Eq for HashSet and HashMap
Also fix documentation references to PartialEq.
---
src/libstd/collections/hashmap.rs | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/src/libstd/collections/hashmap.rs b/src/libstd/collections/hashmap.rs
index 5dba7a533a1db..571c579470441 100644
--- a/src/libstd/collections/hashmap.rs
+++ b/src/libstd/collections/hashmap.rs
@@ -684,8 +684,8 @@ impl DefaultResizePolicy {
/// denial-of-service attacks (Hash DoS). This behaviour can be
/// overridden with one of the constructors.
///
-/// It is required that the keys implement the `PartialEq` and `Hash` traits, although
-/// this can frequently be achieved by using `#[deriving(PartialEq, Hash)]`.
+/// It is required that the keys implement the `Eq` and `Hash` traits, although
+/// this can frequently be achieved by using `#[deriving(Eq, Hash)]`.
///
/// Relevant papers/articles:
///
@@ -1422,6 +1422,8 @@ impl, V: PartialEq, S, H: Hasher> PartialEq for HashMap, V: Eq, S, H: Hasher> Eq for HashMap {}
+
impl + Show, V: Show, S, H: Hasher> Show for HashMap {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, r"\{"));
@@ -1486,7 +1488,7 @@ pub type SetMoveItems =
/// An implementation of a hash set using the underlying representation of a
/// HashMap where the value is (). As with the `HashMap` type, a `HashSet`
-/// requires that the elements implement the `PartialEq` and `Hash` traits.
+/// requires that the elements implement the `Eq` and `Hash` traits.
#[deriving(Clone)]
pub struct HashSet {
map: HashMap
@@ -1500,6 +1502,8 @@ impl, S, H: Hasher> PartialEq for HashSet {
}
}
+impl, S, H: Hasher> Eq for HashSet {}
+
impl, S, H: Hasher> Container for HashSet {
fn len(&self) -> uint { self.map.len() }
}
From 1f4d8f924e78408bc4b10a29da9c42ce29bd725c Mon Sep 17 00:00:00 2001
From: Huon Wilson
Date: Sat, 7 Jun 2014 00:49:19 +1000
Subject: [PATCH 10/16] url: encode small bytes correctly.
Previously, bytes less than 16 would be encoded as %X, rather than %XX,
since the output width was left to be automatic.
---
src/liburl/lib.rs | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/liburl/lib.rs b/src/liburl/lib.rs
index 12db15df31109..65b5a8428bdd2 100644
--- a/src/liburl/lib.rs
+++ b/src/liburl/lib.rs
@@ -161,10 +161,10 @@ fn encode_inner(s: &str, full_url: bool) -> String {
out.push_char(ch);
}
- _ => out.push_str(format!("%{:X}", ch as uint).as_slice())
+ _ => out.push_str(format!("%{:02X}", ch as uint).as_slice())
}
} else {
- out.push_str(format!("%{:X}", ch as uint).as_slice());
+ out.push_str(format!("%{:02X}", ch as uint).as_slice());
}
}
}
@@ -1178,6 +1178,8 @@ mod tests {
assert_eq!(encode("@"), "@".to_string());
assert_eq!(encode("["), "[".to_string());
assert_eq!(encode("]"), "]".to_string());
+ assert_eq!(encode("\0"), "%00".to_string());
+ assert_eq!(encode("\n"), "%0A".to_string());
}
#[test]
@@ -1207,6 +1209,8 @@ mod tests {
assert_eq!(encode_component("@"), "%40".to_string());
assert_eq!(encode_component("["), "%5B".to_string());
assert_eq!(encode_component("]"), "%5D".to_string());
+ assert_eq!(encode_component("\0"), "%00".to_string());
+ assert_eq!(encode_component("\n"), "%0A".to_string());
}
#[test]
From cb12e7ab743e4a0118a3de53a437a70cf332e5b1 Mon Sep 17 00:00:00 2001
From: Alex Crichton
Date: Fri, 6 Jun 2014 09:22:19 -0700
Subject: [PATCH 11/16] mk: Run doc tests with --cfg dox
There were a few examples in the macros::builtin module that weren't being run
because they were being #[cfg]'d out.
Closes #14697
---
mk/tests.mk | 2 +-
src/libstd/macros.rs | 6 +++++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/mk/tests.mk b/mk/tests.mk
index c67fa0042f814..dacea3a4bfc49 100644
--- a/mk/tests.mk
+++ b/mk/tests.mk
@@ -818,7 +818,7 @@ endif
ifeq ($(2),$$(CFG_BUILD))
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-crate-$(4)): $$(CRATEDOCTESTDEP_$(1)_$(2)_$(3)_$(4))
@$$(call E, run doc-crate-$(4) [$(2)])
- $$(Q)$$(RUSTDOC_$(1)_T_$(2)_H_$(3)) --test \
+ $$(Q)$$(RUSTDOC_$(1)_T_$(2)_H_$(3)) --test --cfg dox \
$$(CRATEFILE_$(4)) --test-args "$$(TESTARGS)" && touch $$@
else
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-crate-$(4)):
diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs
index b555c966d2d0e..805da8021ed2c 100644
--- a/src/libstd/macros.rs
+++ b/src/libstd/macros.rs
@@ -465,7 +465,7 @@ pub mod builtin {
/// ```
/// let rust = bytes!("r", 'u', "st", 255);
/// assert_eq!(rust[1], 'u' as u8);
- /// assert_eq!(rust[5], 255);
+ /// assert_eq!(rust[4], 255);
/// ```
#[macro_export]
macro_rules! bytes( ($($e:expr),*) => ({ /* compiler built-in */ }) )
@@ -482,10 +482,14 @@ pub mod builtin {
/// # Example
///
/// ```
+ /// #![feature(concat_idents)]
+ ///
+ /// # fn main() {
/// fn foobar() -> int { 23 }
///
/// let f = concat_idents!(foo, bar);
/// println!("{}", f());
+ /// # }
/// ```
#[macro_export]
macro_rules! concat_idents( ($($e:ident),*) => ({ /* compiler built-in */ }) )
From d4dec4701a5e5e6fb4f66c838b9646bc1c1f711b Mon Sep 17 00:00:00 2001
From: Alex Crichton
Date: Fri, 6 Jun 2014 17:48:46 -0700
Subject: [PATCH 12/16] rustc: Preserve reachable extern fns with LTO
All rust functions are internal implementation details with respect to the ABI
exposed by crates, but extern fns are public components of the ABI and shouldn't
be stripped. This commit serializes reachable extern fns to metadata, so when
LTO is performed all of their symbols are not stripped.
Closes #14500
---
src/librustc/metadata/common.rs | 3 +++
src/librustc/metadata/csearch.rs | 7 +++++++
src/librustc/metadata/decoder.rs | 14 ++++++++++++++
src/librustc/metadata/encoder.rs | 25 +++++++++++++++++++++++++
src/librustc/middle/trans/base.rs | 11 +++++++++++
src/test/run-make/issue-14500/Makefile | 14 ++++++++++++++
src/test/run-make/issue-14500/bar.rs | 11 +++++++++++
src/test/run-make/issue-14500/foo.c | 16 ++++++++++++++++
src/test/run-make/issue-14500/foo.rs | 12 ++++++++++++
src/test/run-make/lto-smoke-c/Makefile | 15 +--------------
src/test/run-make/tools.mk | 14 ++++++++++++++
11 files changed, 128 insertions(+), 14 deletions(-)
create mode 100644 src/test/run-make/issue-14500/Makefile
create mode 100644 src/test/run-make/issue-14500/bar.rs
create mode 100644 src/test/run-make/issue-14500/foo.c
create mode 100644 src/test/run-make/issue-14500/foo.rs
diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs
index 8aeef3dca9867..6287683c1a141 100644
--- a/src/librustc/metadata/common.rs
+++ b/src/librustc/metadata/common.rs
@@ -209,6 +209,9 @@ pub static tag_dylib_dependency_formats: uint = 0x67;
pub static tag_method_argument_names: uint = 0x8e;
pub static tag_method_argument_name: uint = 0x8f;
+pub static tag_reachable_extern_fns: uint = 0x90;
+pub static tag_reachable_extern_fn_id: uint = 0x91;
+
#[deriving(Clone, Show)]
pub struct LinkMeta {
pub crateid: CrateId,
diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs
index 74a804763e83e..c7ad74dce571c 100644
--- a/src/librustc/metadata/csearch.rs
+++ b/src/librustc/metadata/csearch.rs
@@ -314,3 +314,10 @@ pub fn get_method_arg_names(cstore: &cstore::CStore, did: ast::DefId)
let cdata = cstore.get_crate_data(did.krate);
decoder::get_method_arg_names(&*cdata, did.node)
}
+
+pub fn get_reachable_extern_fns(cstore: &cstore::CStore, cnum: ast::CrateNum)
+ -> Vec
+{
+ let cdata = cstore.get_crate_data(cnum);
+ decoder::get_reachable_extern_fns(&*cdata)
+}
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index 6469462734e55..c67b5bf1a6007 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -1325,3 +1325,17 @@ pub fn get_method_arg_names(cdata: Cmd, id: ast::NodeId) -> Vec {
}
return ret;
}
+
+pub fn get_reachable_extern_fns(cdata: Cmd) -> Vec {
+ let mut ret = Vec::new();
+ let items = reader::get_doc(ebml::Doc::new(cdata.data()),
+ tag_reachable_extern_fns);
+ reader::tagged_docs(items, tag_reachable_extern_fn_id, |doc| {
+ ret.push(ast::DefId {
+ krate: cdata.cnum,
+ node: reader::doc_as_u32(doc),
+ });
+ true
+ });
+ return ret;
+}
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index cd2f3360f830d..37cb75e4697b3 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -75,6 +75,7 @@ pub struct EncodeParams<'a> {
pub link_meta: &'a LinkMeta,
pub cstore: &'a cstore::CStore,
pub encode_inlined_item: EncodeInlinedItem<'a>,
+ pub reachable: &'a NodeSet,
}
pub struct EncodeContext<'a> {
@@ -87,6 +88,7 @@ pub struct EncodeContext<'a> {
pub cstore: &'a cstore::CStore,
pub encode_inlined_item: RefCell>,
pub type_abbrevs: tyencode::abbrev_map,
+ pub reachable: &'a NodeSet,
}
fn encode_name(ebml_w: &mut Encoder, name: Name) {
@@ -1702,6 +1704,26 @@ fn encode_misc_info(ecx: &EncodeContext,
ebml_w.end_tag();
}
+fn encode_reachable_extern_fns(ecx: &EncodeContext, ebml_w: &mut Encoder) {
+ ebml_w.start_tag(tag_reachable_extern_fns);
+
+ for id in ecx.reachable.iter() {
+ match ecx.tcx.map.find(*id) {
+ Some(ast_map::NodeItem(i)) => {
+ match i.node {
+ ast::ItemFn(_, _, abi, _, _) if abi != abi::Rust => {
+ ebml_w.wr_tagged_u32(tag_reachable_extern_fn_id, *id);
+ }
+ _ => {}
+ }
+ }
+ _ => {}
+ }
+ }
+
+ ebml_w.end_tag();
+}
+
fn encode_crate_dep(ebml_w: &mut Encoder,
dep: decoder::CrateDep) {
ebml_w.start_tag(tag_crate_dep);
@@ -1801,6 +1823,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
encode_inlined_item,
link_meta,
non_inlineable_statics,
+ reachable,
..
} = parms;
let ecx = EncodeContext {
@@ -1813,6 +1836,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
cstore: cstore,
encode_inlined_item: RefCell::new(encode_inlined_item),
type_abbrevs: RefCell::new(HashMap::new()),
+ reachable: reachable,
};
let mut ebml_w = writer::Encoder::new(wr);
@@ -1864,6 +1888,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
// Encode miscellaneous info.
i = ebml_w.writer.tell().unwrap();
encode_misc_info(&ecx, krate, &mut ebml_w);
+ encode_reachable_extern_fns(&ecx, &mut ebml_w);
stats.misc_bytes = ebml_w.writer.tell().unwrap() - i;
// Encode and index the items.
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 9be07eaaca934..09f5d2a350769 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -2238,6 +2238,7 @@ pub fn crate_ctxt_to_encode_parms<'r>(cx: &'r CrateContext, ie: encoder::EncodeI
link_meta: &cx.link_meta,
cstore: &cx.sess().cstore,
encode_inlined_item: ie,
+ reachable: &cx.reachable,
}
}
@@ -2374,6 +2375,16 @@ pub fn trans_crate(krate: ast::Crate,
ccx.item_symbols.borrow().find(id).map(|s| s.to_string())
}).collect();
+ // For the purposes of LTO, we add to the reachable set all of the upstream
+ // reachable extern fns. These functions are all part of the public ABI of
+ // the final product, so LTO needs to preserve them.
+ ccx.sess().cstore.iter_crate_data(|cnum, _| {
+ let syms = csearch::get_reachable_extern_fns(&ccx.sess().cstore, cnum);
+ reachable.extend(syms.move_iter().map(|did| {
+ csearch::get_symbol(&ccx.sess().cstore, did)
+ }));
+ });
+
// Make sure that some other crucial symbols are not eliminated from the
// module. This includes the main function, the crate map (used for debug
// log settings and I/O), and finally the curious rust_stack_exhausted
diff --git a/src/test/run-make/issue-14500/Makefile b/src/test/run-make/issue-14500/Makefile
new file mode 100644
index 0000000000000..c1087b0f55ecf
--- /dev/null
+++ b/src/test/run-make/issue-14500/Makefile
@@ -0,0 +1,14 @@
+-include ../tools.mk
+
+# Test to make sure that reachable extern fns are always available in final
+# productcs, including when LTO is used. In this test, the `foo` crate has a
+# reahable symbol, and is a dependency of the `bar` crate. When the `bar` crate
+# is compiled with LTO, it shouldn't strip the symbol from `foo`, and that's the
+# only way that `foo.c` will successfully compile.
+
+all:
+ $(RUSTC) foo.rs --crate-type=rlib
+ $(RUSTC) bar.rs --crate-type=staticlib -Zlto -L. -o $(TMPDIR)/libbar.a
+ $(CC) foo.c -lbar -o $(call RUN_BINFILE,foo) $(EXTRACFLAGS)
+ $(call RUN,foo)
+
diff --git a/src/test/run-make/issue-14500/bar.rs b/src/test/run-make/issue-14500/bar.rs
new file mode 100644
index 0000000000000..4b4916fe96d63
--- /dev/null
+++ b/src/test/run-make/issue-14500/bar.rs
@@ -0,0 +1,11 @@
+// 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;
diff --git a/src/test/run-make/issue-14500/foo.c b/src/test/run-make/issue-14500/foo.c
new file mode 100644
index 0000000000000..25098ac479d06
--- /dev/null
+++ b/src/test/run-make/issue-14500/foo.c
@@ -0,0 +1,16 @@
+// 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 void foo();
+
+int main() {
+ foo();
+ return 0;
+}
diff --git a/src/test/run-make/issue-14500/foo.rs b/src/test/run-make/issue-14500/foo.rs
new file mode 100644
index 0000000000000..ceca907403f91
--- /dev/null
+++ b/src/test/run-make/issue-14500/foo.rs
@@ -0,0 +1,12 @@
+// 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.
+
+#[no_mangle]
+pub extern fn foo() {}
diff --git a/src/test/run-make/lto-smoke-c/Makefile b/src/test/run-make/lto-smoke-c/Makefile
index 49a04ce42a0ae..9b44c3e582a71 100644
--- a/src/test/run-make/lto-smoke-c/Makefile
+++ b/src/test/run-make/lto-smoke-c/Makefile
@@ -1,23 +1,10 @@
-include ../tools.mk
-ifdef IS_WINDOWS
- EXTRAFLAGS :=
-else
-ifeq ($(shell uname),Darwin)
-else
-ifeq ($(shell uname),FreeBSD)
- EXTRAFLAGS := -lm -lpthread -lgcc_s
-else
- EXTRAFLAGS := -lm -lrt -ldl -lpthread
-endif
-endif
-endif
-
# Apparently older versions of GCC segfault if -g is passed...
CC := $(CC:-g=)
all:
$(RUSTC) foo.rs -Z lto
ln -s $(call STATICLIB,foo-*) $(call STATICLIB,foo)
- $(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) $(EXTRAFLAGS) -lstdc++
+ $(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) $(EXTRACFLAGS) -lstdc++
$(call RUN,bar)
diff --git a/src/test/run-make/tools.mk b/src/test/run-make/tools.mk
index dedd739052ca0..c9c4c455e4f80 100644
--- a/src/test/run-make/tools.mk
+++ b/src/test/run-make/tools.mk
@@ -53,6 +53,20 @@ RPATH_LINK_SEARCH = -Wl,-rpath-link=$(1)
endif
endif
+# Extra flags needed to compile a working executable with the standard library
+ifdef IS_WINDOWS
+ EXTRACFLAGS :=
+else
+ifeq ($(shell uname),Darwin)
+else
+ifeq ($(shell uname),FreeBSD)
+ EXTRACFLAGS := -lm -lpthread -lgcc_s
+else
+ EXTRACFLAGS := -lm -lrt -ldl -lpthread
+endif
+endif
+endif
+
REMOVE_DYLIBS = rm $(TMPDIR)/$(call DYLIB_GLOB,$(1))
REMOVE_RLIBS = rm $(TMPDIR)/$(call RLIB_GLOB,$(1))
From 59157631061744947df9a7751ac55fe2304e67ad Mon Sep 17 00:00:00 2001
From: Axel Viala
Date: Sat, 7 Jun 2014 00:43:45 +0200
Subject: [PATCH 13/16] Removing unused wrapper to libc::close.
---
src/libstd/os.rs | 6 ------
1 file changed, 6 deletions(-)
diff --git a/src/libstd/os.rs b/src/libstd/os.rs
index 1f75754f4d53e..381ebc0820064 100644
--- a/src/libstd/os.rs
+++ b/src/libstd/os.rs
@@ -56,12 +56,6 @@ use libc::c_char;
#[cfg(windows)]
use str::OwnedStr;
-/// Delegates to the libc close() function, returning the same return value.
-pub fn close(fd: int) -> int {
- unsafe {
- libc::close(fd as c_int) as int
- }
-}
pub static TMPBUF_SZ : uint = 1000u;
static BUF_BYTES : uint = 2048u;
From cc63d4c61bb83fcbcef5ccfffcd9b26b1bf2d20a Mon Sep 17 00:00:00 2001
From: Alex Crichton
Date: Thu, 5 Jun 2014 23:01:01 -0700
Subject: [PATCH 14/16] doc: Turn off special features for rustdoc tests
These were only used for the markdown tests, and there's no reason they should
be distinct from the other tests.
---
src/doc/guide-macros.md | 35 ++++++++++++++++++++++++++---------
src/doc/guide-unsafe.md | 1 +
src/doc/rust.md | 3 +++
src/doc/tutorial.md | 3 +++
src/librustdoc/markdown.rs | 2 +-
src/librustdoc/test.rs | 23 +++++------------------
6 files changed, 39 insertions(+), 28 deletions(-)
diff --git a/src/doc/guide-macros.md b/src/doc/guide-macros.md
index b86a6aa1b619c..45745c7b7bc7a 100644
--- a/src/doc/guide-macros.md
+++ b/src/doc/guide-macros.md
@@ -11,7 +11,7 @@ which both pattern-match on their input and both return early in one case,
doing nothing otherwise:
~~~~
-# enum T { SpecialA(uint), SpecialB(uint) };
+# enum T { SpecialA(uint), SpecialB(uint) }
# fn f() -> uint {
# let input_1 = SpecialA(0);
# let input_2 = SpecialA(0);
@@ -37,7 +37,8 @@ lightweight custom syntax extensions, themselves defined using the
the pattern in the above code:
~~~~
-# enum T { SpecialA(uint), SpecialB(uint) };
+# #![feature(macro_rules)]
+# enum T { SpecialA(uint), SpecialB(uint) }
# fn f() -> uint {
# let input_1 = SpecialA(0);
# let input_2 = SpecialA(0);
@@ -55,6 +56,7 @@ early_return!(input_1 SpecialA);
early_return!(input_2 SpecialB);
# return 0;
# }
+# fn main() {}
~~~~
Macros are defined in pattern-matching style: in the above example, the text
@@ -155,7 +157,8 @@ separator token (a comma-separated list could be written `$(...),*`), and `+`
instead of `*` to mean "at least one".
~~~~
-# enum T { SpecialA(uint),SpecialB(uint),SpecialC(uint),SpecialD(uint)};
+# #![feature(macro_rules)]
+# enum T { SpecialA(uint),SpecialB(uint),SpecialC(uint),SpecialD(uint)}
# fn f() -> uint {
# let input_1 = SpecialA(0);
# let input_2 = SpecialA(0);
@@ -175,6 +178,7 @@ early_return!(input_1, [SpecialA|SpecialC|SpecialD]);
early_return!(input_2, [SpecialB]);
# return 0;
# }
+# fn main() {}
~~~~
### Transcription
@@ -215,9 +219,10 @@ solves the problem.
Now consider code like the following:
~~~~
-# enum T1 { Good1(T2, uint), Bad1};
+# #![feature(macro_rules)]
+# enum T1 { Good1(T2, uint), Bad1}
# struct T2 { body: T3 }
-# enum T3 { Good2(uint), Bad2};
+# enum T3 { Good2(uint), Bad2}
# fn f(x: T1) -> uint {
match x {
Good1(g1, val) => {
@@ -232,6 +237,7 @@ match x {
_ => return 0 // default value
}
# }
+# fn main() {}
~~~~
All the complicated stuff is deeply indented, and the error-handling code is
@@ -240,6 +246,7 @@ a match, but with a syntax that suits the problem better. The following macro
can solve the problem:
~~~~
+# #![feature(macro_rules)]
macro_rules! biased_match (
// special case: `let (x) = ...` is illegal, so use `let x = ...` instead
( ($e:expr) ~ ($p:pat) else $err:stmt ;
@@ -261,9 +268,9 @@ macro_rules! biased_match (
)
)
-# enum T1 { Good1(T2, uint), Bad1};
+# enum T1 { Good1(T2, uint), Bad1}
# struct T2 { body: T3 }
-# enum T3 { Good2(uint), Bad2};
+# enum T3 { Good2(uint), Bad2}
# fn f(x: T1) -> uint {
biased_match!((x) ~ (Good1(g1, val)) else { return 0 };
binds g1, val )
@@ -273,6 +280,7 @@ biased_match!((g1.body) ~ (Good2(result) )
// complicated stuff goes here
return result + val;
# }
+# fn main() {}
~~~~
This solves the indentation problem. But if we have a lot of chained matches
@@ -280,6 +288,8 @@ like this, we might prefer to write a single macro invocation. The input
pattern we want is clear:
~~~~
+# #![feature(macro_rules)]
+# fn main() {}
# macro_rules! b(
( $( ($e:expr) ~ ($p:pat) else $err:stmt ; )*
binds $( $bind_res:ident ),*
@@ -301,14 +311,18 @@ process the semicolon-terminated lines, one-by-one. So, we want the following
input patterns:
~~~~
+# #![feature(macro_rules)]
# macro_rules! b(
( binds $( $bind_res:ident ),* )
# => (0))
+# fn main() {}
~~~~
...and:
~~~~
+# #![feature(macro_rules)]
+# fn main() {}
# macro_rules! b(
( ($e :expr) ~ ($p :pat) else $err :stmt ;
$( ($e_rest:expr) ~ ($p_rest:pat) else $err_rest:stmt ; )*
@@ -322,6 +336,8 @@ The resulting macro looks like this. Note that the separation into
piece of syntax (the `let`) which we only want to transcribe once.
~~~~
+# #![feature(macro_rules)]
+# fn main() {
macro_rules! biased_match_rec (
// Handle the first layer
@@ -365,9 +381,9 @@ macro_rules! biased_match (
)
-# enum T1 { Good1(T2, uint), Bad1};
+# enum T1 { Good1(T2, uint), Bad1}
# struct T2 { body: T3 }
-# enum T3 { Good2(uint), Bad2};
+# enum T3 { Good2(uint), Bad2}
# fn f(x: T1) -> uint {
biased_match!(
(x) ~ (Good1(g1, val)) else { return 0 };
@@ -376,6 +392,7 @@ biased_match!(
// complicated stuff goes here
return result + val;
# }
+# }
~~~~
This technique applies to many cases where transcribing a result all at once is not possible.
diff --git a/src/doc/guide-unsafe.md b/src/doc/guide-unsafe.md
index e0a48682963b4..1431c8a5c9ae4 100644
--- a/src/doc/guide-unsafe.md
+++ b/src/doc/guide-unsafe.md
@@ -523,6 +523,7 @@ vectors provided from C, using idiomatic Rust practices.
```
#![no_std]
+#![feature(globs)]
# extern crate libc;
extern crate core;
diff --git a/src/doc/rust.md b/src/doc/rust.md
index 06c9da2fe0e5a..619e24af36063 100644
--- a/src/doc/rust.md
+++ b/src/doc/rust.md
@@ -1260,6 +1260,8 @@ a = Cat;
Enumeration constructors can have either named or unnamed fields:
~~~~
+# #![feature(struct_variant)]
+# fn main() {
enum Animal {
Dog (String, f64),
Cat { name: String, weight: f64 }
@@ -1267,6 +1269,7 @@ enum Animal {
let mut a: Animal = Dog("Cocoa".to_string(), 37.2);
a = Cat { name: "Spotty".to_string(), weight: 2.7 };
+# }
~~~~
In this example, `Cat` is a _struct-like enum variant_,
diff --git a/src/doc/tutorial.md b/src/doc/tutorial.md
index 917704a2faacd..3b4164ffbc618 100644
--- a/src/doc/tutorial.md
+++ b/src/doc/tutorial.md
@@ -774,6 +774,7 @@ fn point_from_direction(dir: Direction) -> Point {
Enum variants may also be structs. For example:
~~~~
+# #![feature(struct_variant)]
use std::f64;
# struct Point { x: f64, y: f64 }
# fn square(x: f64) -> f64 { x * x }
@@ -789,6 +790,7 @@ fn area(sh: Shape) -> f64 {
}
}
}
+# fn main() {}
~~~~
> *Note:* This feature of the compiler is currently gated behind the
@@ -3046,6 +3048,7 @@ use farm::{chicken, cow};
2. Import everything in a module with a wildcard:
~~~
+# #![feature(globs)]
use farm::*;
# mod farm {
# pub fn cow() { println!("Bat-chicken? What a stupid name!") }
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index 961c92940be81..500d17c9f9a57 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -173,7 +173,7 @@ pub fn render(input: &str, mut output: Path, matches: &getopts::Matches) -> int
pub fn test(input: &str, libs: HashSet, mut test_args: Vec) -> int {
let input_str = load_or_return!(input, 1, 2);
- let mut collector = Collector::new(input.to_string(), libs, true, true);
+ let mut collector = Collector::new(input.to_string(), libs, true);
find_testable_code(input_str.as_slice(), &mut collector);
test_args.unshift("rustdoctest".to_string());
testing::test_main(test_args.as_slice(), collector.tests);
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index ed53b2ac314a8..1434c3eb07d53 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -91,7 +91,6 @@ pub fn run(input: &str,
let mut collector = Collector::new(krate.name.to_string(),
libs,
- false,
false);
collector.fold_crate(krate);
@@ -103,8 +102,8 @@ pub fn run(input: &str,
}
fn runtest(test: &str, cratename: &str, libs: HashSet, should_fail: bool,
- no_run: bool, loose_feature_gating: bool) {
- let test = maketest(test, cratename, loose_feature_gating);
+ no_run: bool) {
+ let test = maketest(test, cratename);
let input = driver::StrInput(test.to_string());
let sessopts = config::Options {
@@ -201,18 +200,12 @@ fn runtest(test: &str, cratename: &str, libs: HashSet, should_fail: bool,
}
}
-fn maketest(s: &str, cratename: &str, loose_feature_gating: bool) -> String {
+pub fn maketest(s: &str, cratename: &str) -> String {
let mut prog = String::from_str(r"
#![deny(warnings)]
#![allow(unused_variable, dead_assignment, unused_mut, attribute_usage, dead_code)]
");
- if loose_feature_gating {
- // FIXME #12773: avoid inserting these when the tutorial & manual
- // etc. have been updated to not use them so prolifically.
- prog.push_str("#![feature(macro_rules, globs, struct_variant, managed_boxes) ]\n");
- }
-
if !s.contains("extern crate") {
if s.contains(cratename) {
prog.push_str(format!("extern crate {};\n",
@@ -238,13 +231,11 @@ pub struct Collector {
use_headers: bool,
current_header: Option,
cratename: String,
-
- loose_feature_gating: bool
}
impl Collector {
pub fn new(cratename: String, libs: HashSet,
- use_headers: bool, loose_feature_gating: bool) -> Collector {
+ use_headers: bool) -> Collector {
Collector {
tests: Vec::new(),
names: Vec::new(),
@@ -253,8 +244,6 @@ impl Collector {
use_headers: use_headers,
current_header: None,
cratename: cratename,
-
- loose_feature_gating: loose_feature_gating
}
}
@@ -268,7 +257,6 @@ impl Collector {
self.cnt += 1;
let libs = self.libs.clone();
let cratename = self.cratename.to_string();
- let loose_feature_gating = self.loose_feature_gating;
debug!("Creating test {}: {}", name, test);
self.tests.push(testing::TestDescAndFn {
desc: testing::TestDesc {
@@ -281,8 +269,7 @@ impl Collector {
cratename.as_slice(),
libs,
should_fail,
- no_run,
- loose_feature_gating);
+ no_run);
}),
});
}
From e5bbbca33e11d9e22dbbe32c975f908710d4155c Mon Sep 17 00:00:00 2001
From: Alex Crichton
Date: Fri, 6 Jun 2014 09:12:18 -0700
Subject: [PATCH 15/16] rustdoc: Submit examples to play.rust-lang.org
This grows a new option inside of rustdoc to add the ability to submit examples
to an external website. If the `--markdown-playground-url` command line option
or crate doc attribute `html_playground_url` is present, then examples will have
a button on hover to submit the code to the playground specified.
This commit enables submission of example code to play.rust-lang.org. The code
submitted is that which is tested by rustdoc, not necessarily the exact code
shown in the example.
Closes #14654
---
mk/docs.mk | 4 ++-
src/doc/footer.inc | 2 ++
src/doc/rust.css | 13 ++++++++++
src/libcollections/lib.rs | 3 ++-
src/libcore/lib.rs | 3 ++-
src/libgetopts/lib.rs | 3 ++-
src/libglob/lib.rs | 4 +--
src/libgreen/lib.rs | 3 ++-
src/liblog/lib.rs | 3 ++-
src/libnum/lib.rs | 3 ++-
src/librand/lib.rs | 3 ++-
src/libregex/lib.rs | 3 ++-
src/librustdoc/html/highlight.rs | 13 +++++++---
src/librustdoc/html/layout.rs | 13 ++++++++--
src/librustdoc/html/markdown.rs | 35 ++++++++++++++++++++++-----
src/librustdoc/html/render.rs | 15 ++++++++++--
src/librustdoc/html/static/main.css | 13 +++++++++-
src/librustdoc/html/static/main.js | 2 +-
src/librustdoc/html/static/playpen.js | 29 ++++++++++++++++++++++
src/librustdoc/lib.rs | 4 ++-
src/librustdoc/markdown.rs | 13 +++++++++-
src/librustdoc/test.rs | 24 ++++++++++++------
src/libserialize/lib.rs | 3 ++-
src/libstd/lib.rs | 3 ++-
src/libsync/lib.rs | 3 ++-
src/libterm/lib.rs | 3 ++-
src/libtime/lib.rs | 3 ++-
src/liburl/lib.rs | 3 ++-
src/libuuid/lib.rs | 3 ++-
29 files changed, 186 insertions(+), 43 deletions(-)
create mode 100644 src/librustdoc/html/static/playpen.js
diff --git a/mk/docs.mk b/mk/docs.mk
index 90f85079464bb..dab40cb165431 100644
--- a/mk/docs.mk
+++ b/mk/docs.mk
@@ -43,7 +43,9 @@ L10N_LANGS := ja
# The options are passed to the documentation generators.
RUSTDOC_HTML_OPTS_NO_CSS = --markdown-before-content=doc/version_info.html \
- --markdown-in-header=doc/favicon.inc --markdown-after-content=doc/footer.inc
+ --markdown-in-header=doc/favicon.inc \
+ --markdown-after-content=doc/footer.inc \
+ --markdown-playground-url='http://play.rust-lang.org/'
RUSTDOC_HTML_OPTS = $(RUSTDOC_HTML_OPTS_NO_CSS) --markdown-css rust.css
diff --git a/src/doc/footer.inc b/src/doc/footer.inc
index a103a4908f6bf..4e7d60586f23d 100644
--- a/src/doc/footer.inc
+++ b/src/doc/footer.inc
@@ -5,3 +5,5 @@ or the MIT license, at your opt
This file may not be copied, modified, or distributed except according to those terms.
+
+
diff --git a/src/doc/rust.css b/src/doc/rust.css
index d60dd54a67d14..3957231a195a5 100644
--- a/src/doc/rust.css
+++ b/src/doc/rust.css
@@ -313,6 +313,19 @@ table th {
padding: 5px;
}
+/* Code snippets */
+
+.rusttest { display: none; }
+pre.rust { position: relative; }
+pre.rust a { transform: scaleX(-1); }
+.test-arrow {
+ display: inline-block;
+ position: absolute;
+ top: 0;
+ right: 10px;
+ font-size: 150%;
+}
+
@media (min-width: 1170px) {
pre {
font-size: 15px;
diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs
index 2004285ecb91b..a65c06107ce34 100644
--- a/src/libcollections/lib.rs
+++ b/src/libcollections/lib.rs
@@ -17,7 +17,8 @@
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/",
+ html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, managed_boxes, default_type_params, phase, globs)]
#![no_std]
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 6aa07415e9cc7..2ccf431fc22e1 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -50,7 +50,8 @@
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/",
+ html_playground_url = "http://play.rust-lang.org/")]
#![no_std]
#![feature(globs, macro_rules, managed_boxes, phase, simd)]
diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs
index ddfe8380e09dd..10584223486c0 100644
--- a/src/libgetopts/lib.rs
+++ b/src/libgetopts/lib.rs
@@ -84,7 +84,8 @@
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/",
+ html_playground_url = "http://play.rust-lang.org/")]
#![feature(globs, phase)]
#![deny(missing_doc)]
#![deny(deprecated_owned_vector)]
diff --git a/src/libglob/lib.rs b/src/libglob/lib.rs
index 86753fbb811cb..f3e1da77ce5c7 100644
--- a/src/libglob/lib.rs
+++ b/src/libglob/lib.rs
@@ -29,8 +29,8 @@
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
-
+ html_root_url = "http://doc.rust-lang.org/",
+ html_playground_url = "http://play.rust-lang.org/")]
#![deny(deprecated_owned_vector)]
use std::cell::Cell;
diff --git a/src/libgreen/lib.rs b/src/libgreen/lib.rs
index 31fd8950c804c..c75d69480ce0d 100644
--- a/src/libgreen/lib.rs
+++ b/src/libgreen/lib.rs
@@ -203,7 +203,8 @@
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/",
+ html_playground_url = "http://play.rust-lang.org/")]
// NB this does *not* include globs, please keep it that way.
#![feature(macro_rules, phase)]
diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs
index ff5805599690d..daacf8b3c4761 100644
--- a/src/liblog/lib.rs
+++ b/src/liblog/lib.rs
@@ -111,7 +111,8 @@ if logging is disabled, none of the components of the log will be executed.
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/",
+ html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules)]
#![deny(missing_doc, deprecated_owned_vector)]
diff --git a/src/libnum/lib.rs b/src/libnum/lib.rs
index 29cf769ffc9d8..fae21e80f3072 100644
--- a/src/libnum/lib.rs
+++ b/src/libnum/lib.rs
@@ -50,7 +50,8 @@
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/",
+ html_playground_url = "http://play.rust-lang.org/")]
#![deny(deprecated_owned_vector)]
diff --git a/src/librand/lib.rs b/src/librand/lib.rs
index 3ed086e9b13cc..7a12dcf9f7f31 100644
--- a/src/librand/lib.rs
+++ b/src/librand/lib.rs
@@ -21,7 +21,8 @@
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/",
+ html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, phase, globs)]
#![no_std]
diff --git a/src/libregex/lib.rs b/src/libregex/lib.rs
index a48760913c161..44c206162ab25 100644
--- a/src/libregex/lib.rs
+++ b/src/libregex/lib.rs
@@ -360,7 +360,8 @@
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/",
+ html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, phase)]
#![deny(missing_doc, deprecated_owned_vector)]
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index f544e1e0973f3..3c9358b03a983 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -25,7 +25,7 @@ use html::escape::Escape;
use t = syntax::parse::token;
/// Highlights some source code, returning the HTML output.
-pub fn highlight(src: &str, class: Option<&str>) -> String {
+pub fn highlight(src: &str, class: Option<&str>, id: Option<&str>) -> String {
debug!("highlighting: ================\n{}\n==============", src);
let sess = parse::new_parse_sess();
let fm = parse::string_to_filemap(&sess,
@@ -36,6 +36,7 @@ pub fn highlight(src: &str, class: Option<&str>) -> String {
doit(&sess,
lexer::StringReader::new(&sess.span_diagnostic, fm),
class,
+ id,
&mut out).unwrap();
str::from_utf8_lossy(out.unwrap().as_slice()).to_string()
}
@@ -47,11 +48,17 @@ pub fn highlight(src: &str, class: Option<&str>) -> String {
/// it's used. All source code emission is done as slices from the source map,
/// not from the tokens themselves, in order to stay true to the original
/// source.
-fn doit(sess: &parse::ParseSess, mut lexer: lexer::StringReader, class: Option<&str>,
+fn doit(sess: &parse::ParseSess, mut lexer: lexer::StringReader,
+ class: Option<&str>, id: Option<&str>,
out: &mut Writer) -> io::IoResult<()> {
use syntax::parse::lexer::Reader;
- try!(write!(out, "\n", class.unwrap_or("")));
+ try!(write!(out, " try!(write!(out, "id='{}' ", id)),
+ None => {}
+ }
+ try!(write!(out, "class='rust {}'>\n", class.unwrap_or("")));
let mut last = BytePos(0);
let mut is_attribute = false;
let mut is_macro = false;
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 80653878247fa..e2fa57148c2c7 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -16,6 +16,7 @@ pub struct Layout {
pub logo: String,
pub favicon: String,
pub krate: String,
+ pub playground_url: String,
}
pub struct Page<'a> {
@@ -108,11 +109,13 @@ r##"
+ {play_js}