-.TH RUSTC "1" "March 2014" "rustc 0.11.0" "User Commands"
+.TH RUSTC "1" "March 2014" "rustc 0.12.0-pre" "User Commands"
.SH NAME
rustc \- The Rust compiler
.SH SYNOPSIS
.SH OPTIONS
+.TP
+\fB\-\-crate-name NAME\fR
+Specify the name of the crate being built
.TP
\fB\-\-crate-type=[bin|lib|dylib|rlib|staticlib]\fR
Configure the flavor of rust crate that is generated (default `bin`)
\fB\-\-pretty\fR [TYPE]
Pretty-print the input instead of compiling; valid types are: normal
(un-annotated source), expanded (crates expanded), typed (crates
-expanded, with type annotations), or identified (fully parenthesized,
-AST nodes and blocks with IDs)
+expanded, with type annotations), identified (fully parenthesized,
+AST nodes and blocks with IDs), or flowgraph=<nodeid> (graphviz
+formatted flowgraph for node)
.TP
\fB\-\-dep-info\fR [FILENAME]
Output dependency info to <filename> after compiling, in o format suitable
-.TH RUSTDOC "1" "March 2014" "rustdoc 0.11.0" "User Commands"
+.TH RUSTDOC "1" "March 2014" "rustdoc 0.12.0-pre" "User Commands"
.SH NAME
rustdoc \- generate documentation from Rust source code
.SH SYNOPSIS
MAYBE_DISABLE_VERIFY=
endif
-install: dist-install-dir-$(CFG_BUILD)-with-target-libs
- $(Q)sh tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" "$(MAYBE_DISABLE_VERIFY)"
+install: dist-install-dir-$(CFG_BUILD)-with-target-libs | tmp/empty_dir
+ $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" "$(MAYBE_DISABLE_VERIFY)"
# Remove tmp files while we can because they may have been created under sudo
$(Q)rm -R tmp/dist
-uninstall: dist-install-dir-$(CFG_BUILD)-with-target-libs
- $(Q)sh tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --uninstall --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)"
+uninstall: dist-install-dir-$(CFG_BUILD)-with-target-libs | tmp/empty_dir
+ $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --uninstall --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)"
# Remove tmp files while we can because they may have been created under sudo
$(Q)rm -R tmp/dist
+tmp/empty_dir:
+ mkdir -p $@
######################################################################
# Android remote installation
######################################################################
# The version number
-CFG_RELEASE_NUM=0.11.0
-CFG_RELEASE_LABEL=
+CFG_RELEASE_NUM=0.12.0
+CFG_RELEASE_LABEL=-pre
CFG_FILENAME_EXTRA=4e7c5e5c
You should see some output that looks something like this:
```{ignore}
-rustc 0.11.0-pre (443a1cd 2014-06-08 14:56:52 -0700)
+rustc 0.12.0-pre (443a1cd 2014-06-08 14:56:52 -0700)
```
If you did, Rust has been installed successfully! Congrats!
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-02-03 08:13+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-02-03 08:13+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-14 21:02+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
# The manifest lists all files to install
done < "${CFG_SRC_DIR}/${CFG_LIBDIR_RELATIVE}/rustlib/manifest.in"
+# Run ldconfig to make dynamic libraries available to the linker
+if [ "$CFG_OSTYPE" = "Linux" ]
+ then
+ ldconfig
+ if [ $? -ne 0 ]
+ then
+ warn "failed to run ldconfig."
+ warn "this may happen when not installing as root and may be fine"
+ fi
+fi
+
# Sanity check: can we run the installed binaries?
#
# As with the verification above, make sure the right LD_LIBRARY_PATH-equivalent
err "${ERR}"
else
echo
- echo " please ensure '${CFG_PREFIX}/lib' is added to ${CFG_LD_PATH_VAR}"
- echo
+ echo " Note: please ensure '${CFG_PREFIX}/lib' is added to ${CFG_LD_PATH_VAR}"
fi
fi
fi
-
echo
echo " Rust is ready to roll."
echo
<!ENTITY rustIdent "[a-zA-Z_][a-zA-Z_0-9]*">
<!ENTITY rustIntSuf "([iu](8|16|32|64)?)?">
]>
-<language name="Rust" version="0.11.0" kateversion="2.4" section="Sources" extensions="*.rs" mimetype="text/x-rust" priority="15">
+<language name="Rust" version="0.12.0-pre" kateversion="2.4" section="Sources" extensions="*.rs" mimetype="text/x-rust" priority="15">
<highlighting>
<list name="fn">
<item> fn </item>
-c'[Compile and assemble, but do not link]'
--cfg'[Configure the compilation environment]'
--crate-id'[Output the crate id and exit]'
- --crate-file-name'[Output the file(s) that would be written if compilation continued and exit]'
- --crate-name'[Output the crate name and exit]'
- --dep-info'[Output dependency info to <filename> after compiling]'
+ --crate-file-name'[deprecated in favor of --print-file-name]'
+ --crate-name'[Specify the name of the crate being built]'
--crate-type'[Specify the type of crate to crate]'
+ --debuginfo'[Emit DWARF debug info to the objects created: 0 = no debug info, 1 = line-tables only (for stacktraces and breakpoints), 2 = full debug info with variable and type information (same as -g)]'
+ --dep-info'[Output dependency info to <filename> after compiling]'
+ -g'[Equivalent to --debuginfo=2]'
{-h,--help}'[Display this message]'
-L'[Add a directory to the library search path]'
--linker'[Program to use for linking instead of the default.]'
--parse-only'[Parse only; do not compile, assemble, or link]'
--passes'[Comma or space separated list of pass names to use]'
--pretty'[Pretty-print the input instead of compiling]'
+ --print-crate-name'[Output the crate name and exit]'
+ --print-file-name'[Output the file(s) that would be written if compilation continued and exit]'
--save-temps'[Write intermediate files (.bc, .opt.bc, .o) in addition to normal output]'
--sysroot'[Override the system root]'
--test'[Build a test harness]'
#![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/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(unsafe_destructor)]
#![allow(missing_doc)]
mod tests {
use test::Bencher;
use std::prelude::*;
- use std::num::ToStrRadix;
+ use std::fmt;
use str::Str;
use string::String;
fn to_hex_str(r: &[u8, ..8]) -> String {
let mut s = String::new();
for b in r.iter() {
- s.push_str((*b as uint).to_str_radix(16u).as_slice());
+ s.push_str(format!("{}", fmt::radix(*b, 16)).as_slice());
}
s
}
let r = result_bytes(h);
let mut s = String::new();
for b in r.iter() {
- s.push_str((*b as uint).to_str_radix(16u).as_slice());
+ s.push_str(format!("{}", fmt::radix(*b, 16)).as_slice());
}
s
}
#![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/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, managed_boxes, default_type_params, phase, globs)]
use core::iter;
use core::mem::{replace, swap};
use core::ptr;
+use std::hash::{Writer, Hash};
use {Collection, Mutable, Set, MutableSet, MutableMap, Map};
use vec::Vec;
}
}
+impl<S: Writer, K: Ord + Hash<S>, V: Hash<S>> Hash<S> for TreeMap<K, V> {
+ fn hash(&self, state: &mut S) {
+ for elt in self.iter() {
+ elt.hash(state);
+ }
+ }
+}
+
impl<T: Ord> FromIterator<T> for TreeSet<T> {
fn from_iter<Iter: Iterator<T>>(iter: Iter) -> TreeSet<T> {
let mut set = TreeSet::new();
}
}
+impl<S: Writer, T: Ord + Hash<S>> Hash<S> for TreeSet<T> {
+ fn hash(&self, state: &mut S) {
+ for elt in self.iter() {
+ elt.hash(state);
+ }
+ }
+}
+
#[cfg(test)]
mod test_treemap {
use std::prelude::*;
#[cfg(test)]
mod test_set {
use std::prelude::*;
+ use std::hash;
use {Set, MutableSet, Mutable, MutableMap};
use super::{TreeMap, TreeSet};
assert!(m.clone() == m);
}
+ #[test]
+ fn test_hash() {
+ let mut x = TreeSet::new();
+ let mut y = TreeSet::new();
+
+ x.insert(1i);
+ x.insert(2);
+ x.insert(3);
+
+ y.insert(3i);
+ y.insert(2);
+ y.insert(1);
+
+ assert!(hash::hash(&x) == hash::hash(&y));
+ }
+
fn check(a: &[int],
b: &[int],
expected: &[int],
///
/// fn with_lock(spinlock: &Arc<AtomicBool>, f: || -> ()) {
/// // CAS loop until we are able to replace `false` with `true`
- /// while spinlock.compare_and_swap(false, true, SeqCst) == false {
+ /// while spinlock.compare_and_swap(false, true, SeqCst) != false {
/// // Since tasks may not be preemptive (if they are green threads)
/// // yield to the scheduler to let the other task run. Low level
/// // concurrent code needs to take into account Rust's two threading
*/
+use clone::Clone;
use cmp;
+use cmp::{PartialEq, PartialOrd, Ord};
+use mem;
use num::{Zero, One, CheckedAdd, CheckedSub, Saturating, ToPrimitive, Int};
-use option::{Option, Some, None};
use ops::{Add, Mul, Sub};
-use cmp::{PartialEq, PartialOrd, Ord};
-use clone::Clone;
+use option::{Option, Some, None};
use uint;
-use mem;
/// Conversion from an `Iterator`
pub trait FromIterator<A> {
fn idx(&mut self, _: uint) -> Option<A> { Some(self.element.clone()) }
}
+type IterateState<'a, T> = (|T|: 'a -> T, Option<T>, bool);
+
+/// An iterator that repeatedly applies a given function, starting
+/// from a given seed value.
+pub type Iterate<'a, T> = Unfold<'a, T, IterateState<'a, T>>;
+
+/// Creates a new iterator that produces an infinite sequence of
+/// repeated applications of the given function `f`.
+#[allow(visible_private_types)]
+pub fn iterate<'a, T: Clone>(f: |T|: 'a -> T, seed: T) -> Iterate<'a, T> {
+ Unfold::new((f, Some(seed), true), |st| {
+ let &(ref mut f, ref mut val, ref mut first) = st;
+ if *first {
+ *first = false;
+ } else {
+ val.mutate(|x| (*f)(x));
+ }
+ val.clone()
+ })
+}
+
/// Functions for lexicographical ordering of sequences.
///
/// Lexicographical ordering through `<`, `<=`, `>=`, `>` requires
#![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/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![no_std]
let r = MinMax(1i,2);
assert_eq!(r.into_option(), Some((1,2)));
}
+
+#[test]
+fn test_iterate() {
+ let mut it = iterate(|x| x * 2, 1u);
+ assert_eq!(it.next(), Some(1u));
+ assert_eq!(it.next(), Some(2u));
+ assert_eq!(it.next(), Some(4u));
+ assert_eq!(it.next(), Some(8u));
+}
#![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/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![experimental]
#![feature(managed_boxes, macro_rules)]
#![allow(experimental)]
#![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/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(phase)]
#[cfg(test)] #[phase(plugin, link)] extern crate log;
#![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/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(plugin_registrar, managed_boxes)]
#![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/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(globs, phase)]
#![deny(missing_doc)]
#![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/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
use std::cell::Cell;
#![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/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
use std::io;
use std::str;
//! possibly pinned to a particular scheduler thread:
//!
//! ```rust
+//! extern crate green;
+//! extern crate rustuv;
+//!
+//! # fn main() {
//! use std::task::TaskBuilder;
//! use green::{SchedPool, PoolConfig, GreenTaskBuilder};
//!
-//! let config = PoolConfig::new();
+//! let mut config = PoolConfig::new();
+//!
+//! // Optional: Set the event loop to be rustuv's to allow I/O to work
+//! config.event_loop_factory = rustuv::event_loop;
+//!
//! let mut pool = SchedPool::new(config);
//!
//! // Spawn tasks into the pool of schedulers
//! // Required to shut down this scheduler pool.
//! // The task will fail if `shutdown` is not called.
//! pool.shutdown();
+//! # }
//! ```
#![crate_name = "green"]
#![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/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
// NB this does *not* include globs, please keep it that way.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use std::ptr;
use std::sync::atomics;
use std::os::{errno, page_size, MemoryMap, MapReadable, MapWritable,
- MapNonStandardFlags, MapVirtual, getenv};
+ MapNonStandardFlags, getenv};
use libc;
/// A task's stack. The name "Stack" is a vestige of segmented stacks.
pub struct Stack {
- buf: MemoryMap,
+ buf: Option<MemoryMap>,
min_size: uint,
valgrind_id: libc::c_uint,
}
// guaranteed to be aligned properly.
if !protect_last_page(&stack) {
fail!("Could not memory-protect guard page. stack={}, errno={}",
- stack.data, errno());
+ stack.data(), errno());
}
let mut stk = Stack {
- buf: stack,
+ buf: Some(stack),
min_size: size,
valgrind_id: 0
};
/// Create a 0-length stack which starts (and ends) at 0.
pub unsafe fn dummy_stack() -> Stack {
Stack {
- buf: MemoryMap { data: 0 as *mut u8, len: 0, kind: MapVirtual },
+ buf: None,
min_size: 0,
valgrind_id: 0
}
/// Point to the low end of the allocated stack
pub fn start(&self) -> *const uint {
- self.buf.data as *const uint
+ self.buf.as_ref().map(|m| m.data() as *const uint)
+ .unwrap_or(ptr::null())
}
/// Point one uint beyond the high end of the allocated stack
pub fn end(&self) -> *const uint {
- unsafe {
- self.buf.data.offset(self.buf.len as int) as *const uint
- }
+ self.buf.as_ref().map(|buf| unsafe {
+ buf.data().offset(buf.len() as int) as *const uint
+ }).unwrap_or(ptr::null())
}
}
// This may seem backwards: the start of the segment is the last page?
// Yes! The stack grows from higher addresses (the end of the allocated
// block) to lower addresses (the start of the allocated block).
- let last_page = stack.data as *mut libc::c_void;
+ let last_page = stack.data() as *mut libc::c_void;
libc::mprotect(last_page, page_size() as libc::size_t,
libc::PROT_NONE) != -1
}
fn protect_last_page(stack: &MemoryMap) -> bool {
unsafe {
// see above
- let last_page = stack.data as *mut libc::c_void;
+ let last_page = stack.data() as *mut libc::c_void;
let mut old_prot: libc::DWORD = 0;
libc::VirtualProtect(last_page, page_size() as libc::SIZE_T,
libc::PAGE_NOACCESS,
#![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/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(plugin_registrar, managed_boxes)]
extern crate syntax;
#![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/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
/*!
pub mod posix88 {
use types::os::arch::c95::c_int;
use types::common::c95::c_void;
+ use types::os::arch::posix88::mode_t;
pub static O_RDONLY : c_int = 0;
pub static O_WRONLY : c_int = 1;
pub static O_CREAT : c_int = 64;
pub static O_EXCL : c_int = 128;
pub static O_TRUNC : c_int = 512;
- pub static S_IFIFO : c_int = 4096;
- pub static S_IFCHR : c_int = 8192;
- pub static S_IFBLK : c_int = 24576;
- pub static S_IFDIR : c_int = 16384;
- pub static S_IFREG : c_int = 32768;
- pub static S_IFLNK : c_int = 40960;
- pub static S_IFMT : c_int = 61440;
- pub static S_IEXEC : c_int = 64;
- pub static S_IWRITE : c_int = 128;
- pub static S_IREAD : c_int = 256;
- pub static S_IRWXU : c_int = 448;
- pub static S_IXUSR : c_int = 64;
- pub static S_IWUSR : c_int = 128;
- pub static S_IRUSR : c_int = 256;
+ pub static S_IFIFO : mode_t = 4096;
+ pub static S_IFCHR : mode_t = 8192;
+ pub static S_IFBLK : mode_t = 24576;
+ pub static S_IFDIR : mode_t = 16384;
+ pub static S_IFREG : mode_t = 32768;
+ pub static S_IFLNK : mode_t = 40960;
+ pub static S_IFMT : mode_t = 61440;
+ pub static S_IEXEC : mode_t = 64;
+ pub static S_IWRITE : mode_t = 128;
+ pub static S_IREAD : mode_t = 256;
+ pub static S_IRWXU : mode_t = 448;
+ pub static S_IXUSR : mode_t = 64;
+ pub static S_IWUSR : mode_t = 128;
+ pub static S_IRUSR : mode_t = 256;
pub static F_OK : c_int = 0;
pub static R_OK : c_int = 4;
pub static W_OK : c_int = 2;
pub mod posix88 {
use types::os::arch::c95::c_int;
use types::common::c95::c_void;
+ use types::os::arch::posix88::mode_t;
pub static O_RDONLY : c_int = 0;
pub static O_WRONLY : c_int = 1;
pub static O_CREAT : c_int = 256;
pub static O_EXCL : c_int = 1024;
pub static O_TRUNC : c_int = 512;
- pub static S_IFIFO : c_int = 4096;
- pub static S_IFCHR : c_int = 8192;
- pub static S_IFBLK : c_int = 24576;
- pub static S_IFDIR : c_int = 16384;
- pub static S_IFREG : c_int = 32768;
- pub static S_IFLNK : c_int = 40960;
- pub static S_IFMT : c_int = 61440;
- pub static S_IEXEC : c_int = 64;
- pub static S_IWRITE : c_int = 128;
- pub static S_IREAD : c_int = 256;
- pub static S_IRWXU : c_int = 448;
- pub static S_IXUSR : c_int = 64;
- pub static S_IWUSR : c_int = 128;
- pub static S_IRUSR : c_int = 256;
+ pub static S_IFIFO : mode_t = 4096;
+ pub static S_IFCHR : mode_t = 8192;
+ pub static S_IFBLK : mode_t = 24576;
+ pub static S_IFDIR : mode_t = 16384;
+ pub static S_IFREG : mode_t = 32768;
+ pub static S_IFLNK : mode_t = 40960;
+ pub static S_IFMT : mode_t = 61440;
+ pub static S_IEXEC : mode_t = 64;
+ pub static S_IWRITE : mode_t = 128;
+ pub static S_IREAD : mode_t = 256;
+ pub static S_IRWXU : mode_t = 448;
+ pub static S_IXUSR : mode_t = 64;
+ pub static S_IWUSR : mode_t = 128;
+ pub static S_IRUSR : mode_t = 256;
pub static F_OK : c_int = 0;
pub static R_OK : c_int = 4;
pub static W_OK : c_int = 2;
pub mod posix88 {
use types::common::c95::c_void;
use types::os::arch::c95::c_int;
+ use types::os::arch::posix88::mode_t;
pub static O_RDONLY : c_int = 0;
pub static O_WRONLY : c_int = 1;
pub static O_CREAT : c_int = 512;
pub static O_EXCL : c_int = 2048;
pub static O_TRUNC : c_int = 1024;
- pub static S_IFIFO : c_int = 4096;
- pub static S_IFCHR : c_int = 8192;
- pub static S_IFBLK : c_int = 24576;
- pub static S_IFDIR : c_int = 16384;
- pub static S_IFREG : c_int = 32768;
- pub static S_IFLNK : c_int = 40960;
- pub static S_IFMT : c_int = 61440;
- pub static S_IEXEC : c_int = 64;
- pub static S_IWRITE : c_int = 128;
- pub static S_IREAD : c_int = 256;
- pub static S_IRWXU : c_int = 448;
- pub static S_IXUSR : c_int = 64;
- pub static S_IWUSR : c_int = 128;
- pub static S_IRUSR : c_int = 256;
+ pub static S_IFIFO : mode_t = 4096;
+ pub static S_IFCHR : mode_t = 8192;
+ pub static S_IFBLK : mode_t = 24576;
+ pub static S_IFDIR : mode_t = 16384;
+ pub static S_IFREG : mode_t = 32768;
+ pub static S_IFLNK : mode_t = 40960;
+ pub static S_IFMT : mode_t = 61440;
+ pub static S_IEXEC : mode_t = 64;
+ pub static S_IWRITE : mode_t = 128;
+ pub static S_IREAD : mode_t = 256;
+ pub static S_IRWXU : mode_t = 448;
+ pub static S_IXUSR : mode_t = 64;
+ pub static S_IWUSR : mode_t = 128;
+ pub static S_IRUSR : mode_t = 256;
pub static F_OK : c_int = 0;
pub static R_OK : c_int = 4;
pub static W_OK : c_int = 2;
pub mod posix88 {
use types::common::c95::c_void;
use types::os::arch::c95::c_int;
+ use types::os::arch::posix88::mode_t;
pub static O_RDONLY : c_int = 0;
pub static O_WRONLY : c_int = 1;
pub static O_CREAT : c_int = 512;
pub static O_EXCL : c_int = 2048;
pub static O_TRUNC : c_int = 1024;
- pub static S_IFIFO : c_int = 4096;
- pub static S_IFCHR : c_int = 8192;
- pub static S_IFBLK : c_int = 24576;
- pub static S_IFDIR : c_int = 16384;
- pub static S_IFREG : c_int = 32768;
- pub static S_IFLNK : c_int = 40960;
- pub static S_IFMT : c_int = 61440;
- pub static S_IEXEC : c_int = 64;
- pub static S_IWRITE : c_int = 128;
- pub static S_IREAD : c_int = 256;
- pub static S_IRWXU : c_int = 448;
- pub static S_IXUSR : c_int = 64;
- pub static S_IWUSR : c_int = 128;
- pub static S_IRUSR : c_int = 256;
+ pub static S_IFIFO : mode_t = 4096;
+ pub static S_IFCHR : mode_t = 8192;
+ pub static S_IFBLK : mode_t = 24576;
+ pub static S_IFDIR : mode_t = 16384;
+ pub static S_IFREG : mode_t = 32768;
+ pub static S_IFLNK : mode_t = 40960;
+ pub static S_IFMT : mode_t = 61440;
+ pub static S_IEXEC : mode_t = 64;
+ pub static S_IWRITE : mode_t = 128;
+ pub static S_IREAD : mode_t = 256;
+ pub static S_IRWXU : mode_t = 448;
+ pub static S_IXUSR : mode_t = 64;
+ pub static S_IWUSR : mode_t = 128;
+ pub static S_IRUSR : mode_t = 256;
pub static F_OK : c_int = 0;
pub static R_OK : c_int = 4;
pub static W_OK : c_int = 2;
use types::os::arch::posix88::mode_t;
extern {
- pub fn open(path: *const c_char, oflag: c_int, mode: c_int)
+ pub fn open(path: *const c_char, oflag: c_int, mode: mode_t)
-> c_int;
pub fn creat(path: *const c_char, mode: mode_t) -> c_int;
pub fn fcntl(fd: c_int, cmd: c_int, ...) -> c_int;
#![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/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules)]
#![deny(missing_doc)]
#![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/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![deny(unused_result, unused_must_use)]
#![allow(non_camel_case_types, deprecated)]
#![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/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![allow(deprecated)] // from_str_radix
#![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/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, phase, globs)]
#![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/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, phase)]
#![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/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(plugin_registrar, managed_boxes, quote)]
#![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/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(intrinsics)]
#![no_std]
s
};
+ // Look in attributes 100% of the time to make sure the attribute is marked
+ // as used. After doing this, however, favor crate names from the command
+ // line.
+ let attr_crate_name = attrs.iter().find(|at| at.check_name("crate_name"))
+ .and_then(|at| at.value_str().map(|s| (at, s)));
+
match sess {
Some(sess) => {
match sess.opts.crate_name {
None => {}
}
- let crate_name = attrs.iter().find(|at| at.check_name("crate_name"))
- .and_then(|at| at.value_str().map(|s| (at, s)));
- match crate_name {
+ match attr_crate_name {
Some((attr, s)) => return validate(s.get().to_string(), Some(attr.span)),
None => {}
}
}
);
+ // JBC: make CFG processing part of expansion to avoid this problem:
+
// strip again, in case expansion added anything with a #[cfg].
krate = time(time_passes, "configuration 2", krate, |krate|
front::config::strip_unconfigured_items(krate));
krate.encode(&mut json).unwrap();
}
+ time(time_passes, "checking that all macro invocations are gone", &krate, |krate|
+ syntax::ext::expand::check_for_macros(&sess.parse_sess, krate));
+
Some((krate, map))
}
pub name: String,
}
+
/// Run the resolution, typechecking, region checking and other
/// miscellaneous analysis passes on the crate. Return various
/// structures carrying the results of the analysis.
krate: &ast::Crate,
ast_map: syntax::ast_map::Map,
name: String) -> CrateAnalysis {
-
let time_passes = sess.time_passes();
time(time_passes, "external crate/lib resolution", (), |_|
use std::os;
use std::cell::{Cell, RefCell};
-
+// Represents the data associated with a compilation
+// session for a single crate.
pub struct Session {
pub targ_cfg: config::Config,
pub opts: config::Options,
use std::gc::{Gc, GC};
+/// A folder that strips out items that do not belong in the current
+/// configuration.
struct Context<'a> {
in_cfg: |attrs: &[ast::Attribute]|: 'a -> bool,
}
fn fold_expr(&mut self, expr: Gc<ast::Expr>) -> Gc<ast::Expr> {
fold_expr(self, expr)
}
+ fn fold_mac(&mut self, mac: &ast::Mac) -> ast::Mac {
+ fold::fold_mac(mac, self)
+ }
}
pub fn strip_items(krate: ast::Crate,
#![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/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![allow(deprecated)]
#![feature(macro_rules, globs, struct_variant, managed_boxes, quote)]
}
}
+ let has_extern_repr = it.attrs.iter().fold(attr::ReprAny, |acc, attr| {
+ attr::find_repr_attr(cx.tcx.sess.diagnostic(), attr, acc)
+ }) == attr::ReprExtern;
+ if has_extern_repr { return }
+
match it.node {
ast::ItemTy(..) | ast::ItemStruct(..) => {
check_case(cx, "type", it.ident, it.span)
should_match_name: true,
};
let library = match load_ctxt.maybe_load_library_crate() {
- Some (l) => l,
+ Some(l) => l,
None if is_cross => {
// try loading from target crates (only valid if there are
// no syntax extensions)
let registrar = decoder::get_plugin_registrar_fn(library.metadata.as_slice()).map(|id| {
decoder::get_symbol(library.metadata.as_slice(), id)
});
+ if library.dylib.is_none() && registrar.is_some() {
+ let message = format!("plugin crate `{}` only found in rlib format, \
+ but must be available in dylib format",
+ info.ident);
+ self.env.sess.span_err(krate.span, message.as_slice());
+ // No need to abort because the loading code will just ignore this
+ // empty dylib.
+ }
let pc = PluginMetadata {
lib: library.dylib.clone(),
macros: macros,
encode_name(ebml_w, nm);
encode_type(ecx, ebml_w, node_id_to_type(tcx, id));
encode_def_id(ebml_w, local_def(id));
+
+ let stab = stability::lookup(ecx.tcx, field.id);
+ encode_stability(ebml_w, stab);
+
ebml_w.end_tag();
}
index
} else {
encode_symbol(ecx, ebml_w, m.def_id.node);
}
- encode_method_argument_names(ebml_w, &*ast_method.decl);
+ encode_method_argument_names(ebml_w, method_fn_decl(&*ast_method));
}
ebml_w.end_tag();
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);
+ encode_method_argument_names(ebml_w, method_fn_decl(m));
}
}
}
}
-struct MacroDefVisitor<'a, 'b, 'c> {
- ecx: &'a EncodeContext<'b>,
- ebml_w: &'a mut Encoder<'c>
-}
-
-impl<'a, 'b, 'c> Visitor<()> for MacroDefVisitor<'a, 'b, 'c> {
- fn visit_item(&mut self, item: &Item, _: ()) {
- match item.node {
- ItemMac(..) => {
- let def = self.ecx.tcx.sess.codemap().span_to_snippet(item.span)
- .expect("Unable to find source for macro");
- self.ebml_w.start_tag(tag_macro_def);
- self.ebml_w.wr_str(def.as_slice());
- self.ebml_w.end_tag();
- }
- _ => {}
- }
- visit::walk_item(self, item, ());
- }
+/// Given a span, write the text of that span into the output stream
+/// as an exported macro
+fn encode_macro_def(ecx: &EncodeContext,
+ ebml_w: &mut Encoder,
+ span: &syntax::codemap::Span) {
+ let def = ecx.tcx.sess.codemap().span_to_snippet(*span)
+ .expect("Unable to find source for macro");
+ ebml_w.start_tag(tag_macro_def);
+ ebml_w.wr_str(def.as_slice());
+ ebml_w.end_tag();
}
-fn encode_macro_defs<'a>(ecx: &'a EncodeContext,
- krate: &Crate,
- ebml_w: &'a mut Encoder) {
+/// Serialize the text of the exported macros
+fn encode_macro_defs(ecx: &EncodeContext,
+ krate: &Crate,
+ ebml_w: &mut Encoder) {
ebml_w.start_tag(tag_exported_macros);
- {
- let mut visitor = MacroDefVisitor {
- ecx: ecx,
- ebml_w: ebml_w,
- };
- visit::walk_crate(&mut visitor, krate, ());
+ for span in krate.exported_macros.iter() {
+ encode_macro_def(ecx, ebml_w, span);
}
ebml_w.end_tag();
}
let ident = match ii {
ast::IIItem(i) => i.ident,
ast::IIForeign(i) => i.ident,
- ast::IIMethod(_, _, m) => m.ident,
+ ast::IIMethod(_, _, m) => ast_util::method_ident(&*m),
};
debug!("Fn named: {}", token::get_ident(ident));
debug!("< Decoded inlined fn: {}::{}",
// HACK we're not dropping items.
e::IIItemRef(i) => ast::IIItem(fold::noop_fold_item(i, &mut fld)
.expect_one("expected one item")),
- e::IIMethodRef(d, p, m) => ast::IIMethod(d, p, fold::noop_fold_method(m, &mut fld)),
+ e::IIMethodRef(d, p, m) => ast::IIMethod(d, p, fold::noop_fold_method(m, &mut fld)
+ .expect_one(
+ "noop_fold_method must produce exactly one method")),
e::IIForeignRef(i) => ast::IIForeign(fold::noop_fold_foreign_item(i, &mut fld))
}
}
ast::IIItem(fld.fold_item(i).expect_one("expected one item"))
}
ast::IIMethod(d, is_provided, m) => {
- ast::IIMethod(xcx.tr_def_id(d), is_provided, fld.fold_method(m))
+ ast::IIMethod(xcx.tr_def_id(d), is_provided, fld.fold_method(m)
+ .expect_one("expected one method"))
}
ast::IIForeign(i) => ast::IIForeign(fld.fold_foreign_item(i))
}
use std::collections::HashSet;
use syntax::ast;
use syntax::ast_map;
+use syntax::ast_util;
use syntax::ast_util::{local_def, is_local};
use syntax::attr::AttrMetaMethods;
use syntax::attr;
visit::walk_trait_method(self, &*trait_method, ctxt);
}
ast_map::NodeMethod(method) => {
- visit::walk_block(self, &*method.body, ctxt);
+ visit::walk_block(self, ast_util::method_body(&*method), ctxt);
}
ast_map::NodeForeignItem(foreign_item) => {
visit::walk_foreign_item(self, &*foreign_item, ctxt);
// Overwrite so that we don't warn the trait method itself.
fn visit_trait_method(&mut self, trait_method: &ast::TraitMethod, _: ()) {
match *trait_method {
- ast::Provided(ref method) => visit::walk_block(self, &*method.body, ()),
+ ast::Provided(ref method) => visit::walk_block(self,
+ ast_util::method_body(&**method), ()),
ast::Required(_) => ()
}
}
use util::ppaux;
use syntax::ast;
+use syntax::ast_util;
use syntax::codemap::Span;
use syntax::visit;
use syntax::visit::Visitor;
visit::FkItemFn(_, _, fn_style, _) =>
(true, fn_style == ast::UnsafeFn),
visit::FkMethod(_, _, method) =>
- (true, method.fn_style == ast::UnsafeFn),
+ (true, ast_util::method_fn_style(method) == ast::UnsafeFn),
_ => (false, false),
};
use syntax::ast;
use syntax::ast_map;
+use syntax::ast_util;
use syntax::ast_util::{is_local, local_def};
use syntax::attr;
use syntax::codemap::Span;
if public_ty || public_trait {
for method in methods.iter() {
- let meth_public = match method.explicit_self.node {
+ let meth_public = match ast_util::method_explicit_self(&**method).node {
ast::SelfStatic => public_ty,
_ => true,
- } && method.vis == ast::Public;
+ } && ast_util::method_vis(&**method) == ast::Public;
if meth_public || tr.is_some() {
self.exported_items.insert(method.id);
}
let imp = self.tcx.map.get_parent_did(closest_private_id);
match ty::impl_trait_ref(self.tcx, imp) {
Some(..) => return Allowable,
- _ if m.vis == ast::Public => return Allowable,
- _ => m.vis
+ _ if ast_util::method_vis(&**m) == ast::Public => return Allowable,
+ _ => ast_util::method_vis(&**m)
}
}
Some(ast_map::NodeTraitMethod(_)) => {
"visibility qualifiers have no effect on trait \
impls");
for m in methods.iter() {
- check_inherited(m.span, m.vis, "");
+ check_inherited(m.span, ast_util::method_vis(&**m), "");
}
}
for m in methods.iter() {
match *m {
ast::Provided(ref m) => {
- check_inherited(m.span, m.vis,
+ check_inherited(m.span, ast_util::method_vis(&**m),
"unnecessary visibility");
}
ast::Required(ref m) => {
match item.node {
ast::ItemImpl(_, _, _, ref methods) => {
for m in methods.iter() {
- check_inherited(tcx, m.span, m.vis);
+ check_inherited(tcx, m.span, ast_util::method_vis(&**m));
}
}
ast::ItemForeignMod(ref fm) => {
match *m {
ast::Required(..) => {}
ast::Provided(ref m) => check_inherited(tcx, m.span,
- m.vis),
+ ast_util::method_vis(&**m)),
}
}
}
// methods will be visible as `Public::foo`.
let mut found_pub_static = false;
for method in methods.iter() {
- if method.explicit_self.node == ast::SelfStatic &&
+ if ast_util::method_explicit_self(&**method).node == ast::SelfStatic &&
self.exported_items.contains(&method.id) {
found_pub_static = true;
visit::walk_method_helper(self, &**method, ());
fn method_might_be_inlined(tcx: &ty::ctxt, method: &ast::Method,
impl_src: ast::DefId) -> bool {
if attributes_specify_inlining(method.attrs.as_slice()) ||
- generics_require_inlining(&method.generics) {
+ generics_require_inlining(ast_util::method_generics(&*method)) {
return true
}
if is_local(impl_src) {
}
}
Some(ast_map::NodeMethod(method)) => {
- if generics_require_inlining(&method.generics) ||
+ if generics_require_inlining(ast_util::method_generics(&*method)) ||
attributes_specify_inlining(method.attrs.as_slice()) {
true
} else {
// Keep going, nothing to get exported
}
ast::Provided(ref method) => {
- visit::walk_block(self, &*method.body, ())
+ visit::walk_block(self, ast_util::method_body(&**method), ())
}
}
}
ast_map::NodeMethod(method) => {
let did = self.tcx.map.get_parent_did(search_item);
if method_might_be_inlined(self.tcx, &*method, did) {
- visit::walk_block(self, &*method.body, ())
+ visit::walk_block(self, ast_util::method_body(&*method), ())
}
}
// Nothing to recurse on for these
use syntax::ast::*;
use syntax::ast;
+use syntax::ast_util;
use syntax::ast_util::{local_def};
use syntax::ast_util::{walk_pat, trait_method_to_ty_method};
use syntax::ext::mtwt;
// For each method...
for method in methods.iter() {
// Add the method to the module.
- let ident = method.ident;
+ let ident = ast_util::method_ident(&**method);
let method_name_bindings =
self.add_child(ident,
new_parent.clone(),
ForbidDuplicateValues,
method.span);
- let def = match method.explicit_self.node {
+ let def = match ast_util::method_explicit_self(&**method).node {
SelfStatic => {
// Static methods become
// `def_static_method`s.
DefStaticMethod(local_def(method.id),
FromImpl(local_def(
item.id)),
- method.fn_style)
+ ast_util::method_fn_style(&**method))
}
_ => {
// Non-static methods become
}
};
- let is_public = method.vis == ast::Public;
+ let is_public = ast_util::method_vis(&**method) == ast::Public;
method_name_bindings.define_value(def,
method.span,
is_public);
fn resolve_method(&mut self,
rib_kind: RibKind,
method: &Method) {
- let method_generics = &method.generics;
+ let method_generics = ast_util::method_generics(method);
let type_parameters = HasTypeParameters(method_generics,
FnSpace,
method.id,
rib_kind);
- self.resolve_function(rib_kind, Some(method.decl), type_parameters, method.body);
+ self.resolve_function(rib_kind, Some(ast_util::method_fn_decl(method)),
+ type_parameters,
+ ast_util::method_body(method));
}
fn with_current_self_type<T>(&mut self, self_type: &Ty, f: |&mut Resolver| -> T) -> T {
fn check_trait_method(&self, method: &Method) {
// If there is a TraitRef in scope for an impl, then the method must be in the trait.
for &(did, ref trait_ref) in self.current_trait_ref.iter() {
- let method_name = method.ident.name;
+ let method_name = ast_util::method_ident(method).name;
if self.method_map.borrow().find(&(method_name, did)).is_none() {
let path_str = self.path_idents_to_string(&trait_ref.path);
},
};
- qualname.push_str(get_ident(method.ident).get());
+ qualname.push_str(get_ident(ast_util::method_ident(&*method)).get());
let qualname = qualname.as_slice();
// record the decl for this def (if it has one)
decl_id,
scope_id);
- self.process_formals(&method.decl.inputs, qualname, e);
+ let m_decl = ast_util::method_fn_decl(&*method);
+ self.process_formals(&m_decl.inputs, qualname, e);
// walk arg and return types
- for arg in method.decl.inputs.iter() {
+ for arg in m_decl.inputs.iter() {
self.visit_ty(&*arg.ty, e);
}
- self.visit_ty(&*method.decl.output, e);
+ self.visit_ty(m_decl.output, e);
// walk the fn body
- self.visit_block(&*method.body, DxrVisitorEnv::new_nested(method.id));
+ self.visit_block(ast_util::method_body(&*method), DxrVisitorEnv::new_nested(method.id));
- self.process_generic_params(&method.generics,
+ self.process_generic_params(ast_util::method_generics(&*method),
method.span,
qualname,
method.id,
use util::nodemap::{NodeMap, DefIdMap};
use syntax::codemap::Span;
use syntax::{attr, visit};
+use syntax::ast;
use syntax::ast::{Attribute, Block, Crate, DefId, FnDecl, NodeId, Variant};
use syntax::ast::{Item, Required, Provided, TraitMethod, TypeMethod, Method};
-use syntax::ast::{Generics, StructDef, Ident};
+use syntax::ast::{Generics, StructDef, StructField, Ident};
use syntax::ast_util::is_local;
use syntax::attr::Stability;
use syntax::visit::{FnKind, FkMethod, Visitor};
s.ctor_id.map(|id| self.annotate(id, &[], parent.clone()));
visit::walk_struct_def(self, s, parent)
}
+
+ fn visit_struct_field(&mut self, s: &StructField, parent: Option<Stability>) {
+ let stab = self.annotate(s.node.id, s.node.attrs.as_slice(), parent);
+ visit::walk_struct_field(self, s, stab)
+ }
}
impl Index {
extern_cache: DefIdMap::new()
}
};
- visit::walk_crate(&mut annotator, krate,
- attr::find_stability(krate.attrs.as_slice()));
+ let stab = annotator.annotate(ast::CRATE_NODE_ID, krate.attrs.as_slice(), None);
+ visit::walk_crate(&mut annotator, krate, stab);
annotator.index
}
}
}
}
ast_map::NodeMethod(ref method) => {
- (method.ident,
- method.decl,
- &method.generics,
- method.body,
+ (ast_util::method_ident(&**method),
+ ast_util::method_fn_decl(&**method),
+ ast_util::method_generics(&**method),
+ ast_util::method_body(&**method),
method.span,
true)
}
ast_map::NodeTraitMethod(ref trait_method) => {
match **trait_method {
ast::Provided(ref method) => {
- (method.ident,
- method.decl,
- &method.generics,
- method.body,
+ (ast_util::method_ident(&**method),
+ ast_util::method_fn_decl(&**method),
+ ast_util::method_generics(&**method),
+ ast_util::method_body(&**method),
method.span,
true)
}
let impl_tpt = ty::lookup_item_type(ccx.tcx(), impl_did);
let unparameterized =
impl_tpt.generics.types.is_empty() &&
- mth.generics.ty_params.is_empty();
+ ast_util::method_generics(&*mth).ty_params.is_empty();
if unparameterized {
let llfn = get_item_val(ccx, mth.id);
- trans_fn(ccx, &*mth.decl, &*mth.body, llfn,
+ trans_fn(ccx, ast_util::method_fn_decl(&*mth),
+ ast_util::method_body(&*mth), llfn,
¶m_substs::empty(), mth.id, []);
}
local_def(mth.id)
use std::gc::Gc;
use syntax::abi::Rust;
use syntax::parse::token;
-use syntax::{ast, ast_map, visit};
+use syntax::{ast, ast_map, visit, ast_util};
/**
The main "translation" pass for methods. Generates code
return;
}
for method in methods.iter() {
- if method.generics.ty_params.len() == 0u {
+ if ast_util::method_generics(&**method).ty_params.len() == 0u {
let llfn = get_item_val(ccx, method.id);
- trans_fn(ccx, &*method.decl, &*method.body,
+ trans_fn(ccx, ast_util::method_fn_decl(&**method),
+ ast_util::method_body(&**method),
llfn, ¶m_substs::empty(), method.id, []);
} else {
let mut v = TransItemVisitor{ ccx: ccx };
ast_map::NodeTraitMethod(method) => {
let ident = match *method {
ast::Required(ref m) => m.ident,
- ast::Provided(ref m) => m.ident
+ ast::Provided(ref m) => ast_util::method_ident(&**m)
};
ident.name
}
use syntax::abi;
use syntax::ast;
use syntax::ast_map;
+use syntax::ast_util;
use syntax::ast_util::local_def;
use std::hash::{sip, Hash};
ast_map::NodeMethod(mth) => {
let d = mk_lldecl();
set_llvm_fn_attrs(mth.attrs.as_slice(), d);
- trans_fn(ccx, &*mth.decl, &*mth.body, d, &psubsts, mth.id, []);
+ trans_fn(ccx, ast_util::method_fn_decl(&*mth),
+ ast_util::method_body(&*mth), d, &psubsts, mth.id, []);
d
}
ast_map::NodeTraitMethod(method) => {
ast::Provided(mth) => {
let d = mk_lldecl();
set_llvm_fn_attrs(mth.attrs.as_slice(), d);
- trans_fn(ccx, &*mth.decl, &*mth.body, d, &psubsts, mth.id, []);
+ trans_fn(ccx, ast_util::method_fn_decl(&*mth),
+ ast_util::method_body(&*mth), d, &psubsts, mth.id, []);
d
}
_ => {
let method_def_id = local_def(method.id);
let method_ty = ty::method(ccx.tcx, method_def_id);
let method_generics = &method_ty.generics;
+ let m_body = ast_util::method_body(&*method);
let param_env = ty::construct_parameter_environment(ccx.tcx,
method_generics,
- method.body.id);
+ m_body.id);
let fty = ty::node_id_to_type(ccx.tcx, method.id);
- check_bare_fn(ccx, &*method.decl, &*method.body, method.id, fty, param_env);
+ check_bare_fn(ccx, ast_util::method_fn_decl(&*method),
+ m_body, method.id, fty, param_env);
}
fn check_impl_methods_against_trait(ccx: &CrateCtxt,
compare_impl_method(ccx.tcx,
&*impl_method_ty,
impl_method.span,
- impl_method.body.id,
+ ast_util::method_body(&**impl_method).id,
&**trait_method_ty,
&impl_trait_ref.substs);
}
for trait_method in trait_methods.iter() {
let is_implemented =
impl_methods.iter().any(
- |m| m.ident.name == trait_method.ident.name);
+ |m| ast_util::method_ident(&**m).name == trait_method.ident.name);
let is_provided =
provided_methods.iter().any(
|m| m.ident.name == trait_method.ident.name);
use syntax::ast::{TraitTyParamBound, UnboxedFnTyParamBound};
use syntax::ast;
use syntax::ast_map;
-use syntax::ast_util::{local_def, split_trait_methods};
+use syntax::ast_util;
+use syntax::ast_util::{local_def, method_ident, split_trait_methods};
use syntax::codemap::Span;
use syntax::codemap;
use syntax::owned_slice::OwnedSlice;
&ast::Provided(ref m) => {
ty_method_of_trait_method(
ccx, trait_id, &trait_def.generics,
- &m.id, &m.ident, &m.explicit_self,
- &m.generics, &m.fn_style, &*m.decl)
+ &m.id, &ast_util::method_ident(&**m),
+ ast_util::method_explicit_self(&**m),
+ ast_util::method_generics(&**m),
+ &ast_util::method_fn_style(&**m),
+ ast_util::method_fn_decl(&**m))
}
});
let tcx = ccx.tcx;
let mut seen_methods = HashSet::new();
for m in ms.iter() {
- if !seen_methods.insert(m.ident.repr(ccx.tcx)) {
+ if !seen_methods.insert(ast_util::method_ident(&**m).repr(tcx)) {
tcx.sess.span_err(m.span, "duplicate method in trait impl");
}
rcvr_visibility));
let fty = ty::mk_bare_fn(tcx, mty.fty.clone());
debug!("method {} (id {}) has type {}",
- m.ident.repr(ccx.tcx),
+ method_ident(&**m).repr(tcx),
m.id,
- fty.repr(ccx.tcx));
+ fty.repr(tcx));
tcx.tcache.borrow_mut().insert(
local_def(m.id),
Polytype {
rcvr_visibility: ast::Visibility)
-> ty::Method
{
- let fty = astconv::ty_of_method(ccx, m.id, m.fn_style,
+ let fty = astconv::ty_of_method(ccx, m.id, ast_util::method_fn_style(&*m),
untransformed_rcvr_ty,
- m.explicit_self, &*m.decl);
+ *ast_util::method_explicit_self(&*m),
+ ast_util::method_fn_decl(&*m));
// if the method specifies a visibility, use that, otherwise
// inherit the visibility from the impl (so `foo` in `pub impl
// { fn foo(); }` is public, but private in `priv impl { fn
// foo(); }`).
- let method_vis = m.vis.inherit_from(rcvr_visibility);
+ let method_vis = ast_util::method_vis(&*m).inherit_from(rcvr_visibility);
let m_ty_generics =
- ty_generics_for_fn_or_method(ccx, &m.generics,
+ ty_generics_for_fn_or_method(ccx, ast_util::method_generics(&*m),
(*rcvr_ty_generics).clone());
- ty::Method::new(m.ident,
+ ty::Method::new(ast_util::method_ident(&*m),
m_ty_generics,
fty,
- m.explicit_self.node,
+ ast_util::method_explicit_self(&*m).node,
method_vis,
local_def(m.id),
container,
Some(ref node) => match *node {
ast_map::NodeItem(ref item) => {
match item.node {
- ast::ItemFn(ref fn_decl, ref pur, _, ref gen, _) => {
+ ast::ItemFn(fn_decl, ref pur, _, ref gen, _) => {
Some((fn_decl, gen, *pur, item.ident, None, item.span))
},
_ => None
}
}
ast_map::NodeMethod(ref m) => {
- Some((&m.decl, &m.generics, m.fn_style,
- m.ident, Some(m.explicit_self.node), m.span))
+ Some((ast_util::method_fn_decl(&**m),
+ ast_util::method_generics(&**m),
+ ast_util::method_fn_style(&**m),
+ ast_util::method_ident(&**m),
+ Some(ast_util::method_explicit_self(&**m).node), m.span))
},
_ => None
},
= node_inner.expect("expect item fn");
let taken = lifetimes_in_scope(self.tcx, scope_id);
let life_giver = LifeGiver::with_taken(taken.as_slice());
- let rebuilder = Rebuilder::new(self.tcx, *fn_decl, expl_self,
+ let rebuilder = Rebuilder::new(self.tcx, fn_decl, expl_self,
generics, same_regions, &life_giver);
let (fn_decl, expl_self, generics) = rebuilder.rebuild();
self.give_expl_lifetime_param(&fn_decl, fn_style, ident,
_ => None
},
ast_map::NodeMethod(m) => {
- taken.push_all(m.generics.lifetimes.as_slice());
+ taken.push_all(ast_util::method_generics(&*m).lifetimes.as_slice());
Some(m.id)
},
_ => None
loader.plugins
}
+// note that macros aren't expanded yet, and therefore macros can't add plugins.
impl<'a> Visitor<()> for PluginLoader<'a> {
fn visit_view_item(&mut self, vi: &ast::ViewItem, _: ()) {
match vi.node {
_ => (),
}
}
+ fn visit_mac(&mut self, _: &ast::Mac, _:()) {
+ // bummer... can't see plugins inside macros.
+ // do nothing.
+ }
}
impl<'a> PluginLoader<'a> {
impl Clean<Item> for ast::Method {
fn clean(&self) -> Item {
- let inputs = match self.explicit_self.node {
- ast::SelfStatic => self.decl.inputs.as_slice(),
- _ => self.decl.inputs.slice_from(1)
+ let fn_decl = ast_util::method_fn_decl(self);
+ let inputs = match ast_util::method_explicit_self(self).node {
+ ast::SelfStatic => fn_decl.inputs.as_slice(),
+ _ => fn_decl.inputs.slice_from(1)
};
let decl = FnDecl {
inputs: Arguments {
values: inputs.iter().map(|x| x.clean()).collect(),
},
- output: (self.decl.output.clean()),
- cf: self.decl.cf.clean(),
+ output: (fn_decl.output.clean()),
+ cf: fn_decl.cf.clean(),
attrs: Vec::new()
};
Item {
- name: Some(self.ident.clean()),
+ name: Some(ast_util::method_ident(self).clean()),
attrs: self.attrs.clean().move_iter().collect(),
source: self.span.clean(),
def_id: ast_util::local_def(self.id),
- visibility: self.vis.clean(),
+ visibility: ast_util::method_vis(self).clean(),
stability: get_stability(ast_util::local_def(self.id)),
inner: MethodItem(Method {
- generics: self.generics.clean(),
- self_: self.explicit_self.node.clean(),
- fn_style: self.fn_style.clone(),
+ generics: ast_util::method_generics(self).clean(),
+ self_: ast_util::method_explicit_self(self).node.clean(),
+ fn_style: ast_util::method_fn_style(self).clone(),
decl: decl,
}),
}
name: Some(name.clean()),
attrs: Vec::new(),
visibility: Some(ast::Public),
- stability: get_stability(self.id),
// FIXME: this is not accurate, we need an id for
// the specific field but we're using the id
- // for the whole variant. Nothing currently
- // uses this so we should be good for now.
+ // for the whole variant. Thus we read the
+ // stability from the whole variant as well.
+ // Struct variants are experimental and need
+ // more infrastructure work before we can get
+ // at the needed information here.
def_id: self.id,
+ stability: get_stability(self.id),
inner: StructFieldItem(
TypedStructField(ty.clean())
)
visibility: Some(ast::Public),
def_id: self.id,
inner: VariantItem(Variant { kind: kind }),
- stability: None,
+ stability: get_stability(self.id),
}
}
}
source: self.span.clean(),
def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(),
- stability: None,
+ stability: get_stability(ast_util::local_def(self.id)),
inner: inner,
}
}
PatWildMulti => "..".to_string(),
PatIdent(_, ref p, _) => token::get_ident(p.node).get().to_string(),
PatEnum(ref p, _) => path_to_string(p),
- PatStruct(..) => fail!("tried to get argument name from pat_struct, \
- which is not allowed in function arguments"),
- PatTup(..) => "(tuple arg NYI)".to_string(),
+ PatStruct(ref name, ref fields, etc) => {
+ format!("{} {{ {}{} }}", path_to_string(name),
+ fields.iter().map(|fp|
+ format!("{}: {}", fp.ident.as_str(), name_from_pat(&*fp.pat)))
+ .collect::<Vec<String>>().connect(", "),
+ if etc { ", ..." } else { "" }
+ )
+ },
+ PatTup(ref elts) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
+ .collect::<Vec<String>>().connect(", ")),
PatBox(p) => name_from_pat(&*p),
PatRegion(p) => name_from_pat(&*p),
PatLit(..) => {
use syntax::ast_util;
use clean;
+use stability_summary::ModuleSummary;
use html::item_type;
use html::item_type::ItemType;
use html::render;
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);
+/// Similar to VisSpace, but used for mutability
+pub struct RawMutableSpace(pub clean::Mutability);
/// Wrapper struct for properly emitting the stability level.
pub struct Stability<'a>(pub &'a Option<clean::Stability>);
/// Wrapper struct for emitting the stability level concisely.
}
clean::Tuple(ref typs) => {
primitive_link(f, clean::PrimitiveTuple,
- format!("({:#})", typs).as_slice())
+ match typs.as_slice() {
+ [ref one] => format!("({},)", one),
+ many => format!("({:#})", many)
+ }.as_slice())
}
clean::Vector(ref t) => {
primitive_link(f, clean::Slice, format!("[{}]", **t).as_slice())
clean::Unique(ref t) => write!(f, "Box<{}>", **t),
clean::Managed(ref t) => write!(f, "Gc<{}>", **t),
clean::RawPointer(m, ref t) => {
- write!(f, "*{}{}", MutableSpace(m), **t)
+ write!(f, "*{}{}", RawMutableSpace(m), **t)
}
clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
let lt = match *l {
}
}
+impl fmt::Show for RawMutableSpace {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ RawMutableSpace(clean::Immutable) => write!(f, "const "),
+ RawMutableSpace(clean::Mutable) => write!(f, "mut "),
+ }
+ }
+}
+
impl<'a> fmt::Show for Stability<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let Stability(stab) = *self;
}
}
}
+
+impl fmt::Show for ModuleSummary {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fn fmt_inner<'a>(f: &mut fmt::Formatter,
+ context: &mut Vec<&'a str>,
+ m: &'a ModuleSummary)
+ -> fmt::Result {
+ let cnt = m.counts;
+ let tot = cnt.total();
+ if tot == 0 { return Ok(()) }
+
+ context.push(m.name.as_slice());
+ let path = context.connect("::");
+
+ // the total width of each row's stability summary, in pixels
+ let width = 500;
+
+ try!(write!(f, "<tr>"));
+ try!(write!(f, "<td class='summary'>\
+ <a class='summary' href='{}'>{}</a></td>",
+ Vec::from_slice(context.slice_from(1))
+ .append_one("index.html").connect("/"),
+ path));
+ try!(write!(f, "<td>"));
+ try!(write!(f, "<span class='summary Stable' \
+ style='width: {}px; display: inline-block'> </span>",
+ (width * cnt.stable)/tot));
+ try!(write!(f, "<span class='summary Unstable' \
+ style='width: {}px; display: inline-block'> </span>",
+ (width * cnt.unstable)/tot));
+ try!(write!(f, "<span class='summary Experimental' \
+ style='width: {}px; display: inline-block'> </span>",
+ (width * cnt.experimental)/tot));
+ try!(write!(f, "<span class='summary Deprecated' \
+ style='width: {}px; display: inline-block'> </span>",
+ (width * cnt.deprecated)/tot));
+ try!(write!(f, "<span class='summary Unmarked' \
+ style='width: {}px; display: inline-block'> </span>",
+ (width * cnt.unmarked)/tot));
+ try!(write!(f, "</td></tr>"));
+
+ for submodule in m.submodules.iter() {
+ try!(fmt_inner(f, context, submodule));
+ }
+ context.pop();
+ Ok(())
+ }
+
+ let mut context = Vec::new();
+
+ try!(write!(f,
+r"<h1 class='fqn'>Stability dashboard: crate <a class='mod' href='index.html'>{}</a></h1>
+This dashboard summarizes the stability levels for all of the public modules of
+the crate, according to the total number of items at each level in the module and its children:
+<blockquote>
+<a class='stability Stable'></a> stable,<br/>
+<a class='stability Unstable'></a> unstable,<br/>
+<a class='stability Experimental'></a> experimental,<br/>
+<a class='stability Deprecated'></a> deprecated,<br/>
+<a class='stability Unmarked'></a> unmarked
+</blockquote>
+The counts do not include methods or trait
+implementations that are visible only through a re-exported type.",
+self.name));
+ try!(write!(f, "<table>"))
+ try!(fmt_inner(f, &mut context, self));
+ write!(f, "</table>")
+ }
+}
use externalfiles::ExternalHtml;
+use serialize::json;
+use serialize::Encodable;
use serialize::json::ToJson;
use syntax::ast;
use syntax::ast_util;
use html::layout;
use html::markdown::Markdown;
use html::markdown;
+use stability_summary;
/// Major driving force in all rustdoc rendering. This contains information
/// about where in the tree-like hierarchy rendering is occurring and controls
try!(mkdir(&cx.dst));
+ // Crawl the crate, building a summary of the stability levels. NOTE: this
+ // summary *must* be computed with the original `krate`; the folding below
+ // removes the impls from their modules.
+ let summary = stability_summary::build(&krate);
+
// Crawl the crate attributes looking for attributes which control how we're
// going to emit HTML
match krate.module.as_ref().map(|m| m.doc_list().unwrap_or(&[])) {
let krate = try!(render_sources(&mut cx, krate));
// And finally render the whole crate's documentation
- cx.krate(krate)
+ cx.krate(krate, summary)
}
fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::IoResult<String> {
include_bin!("static/FiraSans-Regular.woff")));
try!(write(cx.dst.join("FiraSans-Medium.woff"),
include_bin!("static/FiraSans-Medium.woff")));
- try!(write(cx.dst.join("SourceSerifPro-Bold.woff"),
- include_bin!("static/SourceSerifPro-Bold.woff")));
try!(write(cx.dst.join("Heuristica-Italic.woff"),
include_bin!("static/Heuristica-Italic.woff")));
+ try!(write(cx.dst.join("SourceSerifPro-Regular.woff"),
+ include_bin!("static/SourceSerifPro-Regular.woff")));
try!(write(cx.dst.join("SourceSerifPro-Bold.woff"),
include_bin!("static/SourceSerifPro-Bold.woff")));
try!(write(cx.dst.join("SourceCodePro-Regular.woff"),
///
/// This currently isn't parallelized, but it'd be pretty easy to add
/// parallelization to this function.
- fn krate(self, mut krate: clean::Crate) -> io::IoResult<()> {
+ fn krate(mut self, mut krate: clean::Crate,
+ stability: stability_summary::ModuleSummary) -> io::IoResult<()> {
let mut item = match krate.module.take() {
Some(i) => i,
None => return Ok(())
};
item.name = Some(krate.name);
+ // render stability dashboard
+ try!(self.recurse(stability.name.clone(), |this| {
+ let json_dst = &this.dst.join("stability.json");
+ let mut json_out = BufferedWriter::new(try!(File::create(json_dst)));
+ try!(stability.encode(&mut json::Encoder::new(&mut json_out)));
+
+ let title = stability.name.clone().append(" - Stability dashboard");
+ let page = layout::Page {
+ ty: "mod",
+ root_path: this.root_path.as_slice(),
+ title: title.as_slice(),
+ };
+ let html_dst = &this.dst.join("stability.html");
+ let mut html_out = BufferedWriter::new(try!(File::create(html_dst)));
+ layout::render(&mut html_out, &this.layout, &page,
+ &Sidebar{ cx: this, item: &item },
+ &stability)
+ }));
+
+ // render the crate documentation
let mut work = vec!((self, item));
loop {
match work.pop() {
None => break,
}
}
+
Ok(())
}
}
}
+
+
impl<'a> fmt::Show for Item<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
// Write the breadcrumb trail header for the top
// Write stability level
try!(write!(fmt, "{}", Stability(&self.item.stability)));
+ // Links to out-of-band information, i.e. src and stability dashboard
+ try!(write!(fmt, "<span class='out-of-band'>"));
+
+ // Write stability dashboard link
+ match self.item.inner {
+ clean::ModuleItem(ref m) if m.is_crate => {
+ try!(write!(fmt, "<a href='stability.html'>[stability dashboard]</a> "));
+ }
+ _ => {}
+ };
+
// Write `src` tag
//
// When this item is part of a `pub use` in a downstream crate, the
if self.cx.include_sources && !is_primitive {
match self.href() {
Some(l) => {
- try!(write!(fmt,
- "<a class='source' id='src-{}' \
- href='{}'>[src]</a>",
+ try!(write!(fmt, "<a id='src-{}' href='{}'>[src]</a>",
self.item.def_id.node, l));
}
None => {}
}
}
+
+ try!(write!(fmt, "</span>"));
+
try!(write!(fmt, "</h1>\n"));
match self.item.inner {
fn item_module(w: &mut fmt::Formatter, cx: &Context,
item: &clean::Item, items: &[clean::Item]) -> fmt::Result {
try!(document(w, item));
+
let mut indices = range(0, items.len()).filter(|i| {
!ignore_private_item(&items[*i])
}).collect::<Vec<uint>>();
}
}
}
+
write!(w, "</table>")
}
.docblock h2 { font-size: 1.15em; }
.docblock h3, .docblock h4, .docblock h5 { font-size: 1em; }
-.content .source {
+.content .out-of-band {
float: right;
font-size: 23px;
}
.stability.Locked { border-color: #0084B6; color: #00668c; }
.stability.Unmarked { border-color: #FFFFFF; }
+.summary {
+ padding-right: 0px;
+}
+.summary.Deprecated { background-color: #A071A8; }
+.summary.Experimental { background-color: #D46D6A; }
+.summary.Unstable { background-color: #D4B16A; }
+.summary.Stable { background-color: #54A759; }
+.summary.Unmarked { background-color: #FFFFFF; }
+
:target { background: #FDFFD3; }
/* Code highlighting */
pub mod markdown;
pub mod passes;
pub mod plugins;
+pub mod stability_summary;
pub mod visit_ast;
pub mod test;
mod flock;
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This module crawls a `clean::Crate` and produces a summarization of the
+//! stability levels within the crate. The summary contains the module
+//! hierarchy, with item counts for every stability level per module. A parent
+//! module's count includes its childrens's.
+
+use std::ops::Add;
+use std::num::Zero;
+use std::iter::AdditiveIterator;
+
+use syntax::attr::{Deprecated, Experimental, Unstable, Stable, Frozen, Locked};
+use syntax::ast::Public;
+
+use clean::{Crate, Item, ModuleItem, Module, StructItem, Struct, EnumItem, Enum};
+use clean::{ImplItem, Impl, TraitItem, Trait, TraitMethod, Provided, Required};
+use clean::{ViewItemItem, PrimitiveItem};
+
+#[deriving(Zero, Encodable, Decodable, PartialEq, Eq)]
+/// The counts for each stability level.
+pub struct Counts {
+ pub deprecated: uint,
+ pub experimental: uint,
+ pub unstable: uint,
+ pub stable: uint,
+ pub frozen: uint,
+ pub locked: uint,
+
+ /// No stability level, inherited or otherwise.
+ pub unmarked: uint,
+}
+
+impl Add<Counts, Counts> for Counts {
+ fn add(&self, other: &Counts) -> Counts {
+ Counts {
+ deprecated: self.deprecated + other.deprecated,
+ experimental: self.experimental + other.experimental,
+ unstable: self.unstable + other.unstable,
+ stable: self.stable + other.stable,
+ frozen: self.frozen + other.frozen,
+ locked: self.locked + other.locked,
+ unmarked: self.unmarked + other.unmarked,
+ }
+ }
+}
+
+impl Counts {
+ pub fn total(&self) -> uint {
+ self.deprecated + self.experimental + self.unstable + self.stable +
+ self.frozen + self.locked + self.unmarked
+ }
+}
+
+#[deriving(Encodable, Decodable, PartialEq, Eq)]
+/// A summarized module, which includes total counts and summarized chilcren
+/// modules.
+pub struct ModuleSummary {
+ pub name: String,
+ pub counts: Counts,
+ pub submodules: Vec<ModuleSummary>,
+}
+
+impl PartialOrd for ModuleSummary {
+ fn partial_cmp(&self, other: &ModuleSummary) -> Option<Ordering> {
+ self.name.partial_cmp(&other.name)
+ }
+}
+
+impl Ord for ModuleSummary {
+ fn cmp(&self, other: &ModuleSummary) -> Ordering {
+ self.name.cmp(&other.name)
+ }
+}
+
+// is the item considered publically visible?
+fn visible(item: &Item) -> bool {
+ match item.inner {
+ ImplItem(_) => true,
+ _ => item.visibility == Some(Public)
+ }
+}
+
+// Produce the summary for an arbitrary item. If the item is a module, include a
+// module summary. The counts for items with nested items (e.g. modules, traits,
+// impls) include all children counts.
+fn summarize_item(item: &Item) -> (Counts, Option<ModuleSummary>) {
+ // count this item
+ let item_counts = match item.stability {
+ None => Counts { unmarked: 1, .. Zero::zero() },
+ Some(ref stab) => match stab.level {
+ Deprecated => Counts { deprecated: 1, .. Zero::zero() },
+ Experimental => Counts { experimental: 1, .. Zero::zero() },
+ Unstable => Counts { unstable: 1, .. Zero::zero() },
+ Stable => Counts { stable: 1, .. Zero::zero() },
+ Frozen => Counts { frozen: 1, .. Zero::zero() },
+ Locked => Counts { locked: 1, .. Zero::zero() },
+ }
+ };
+
+ // Count this item's children, if any. Note that a trait impl is
+ // considered to have no children.
+ match item.inner {
+ // Require explicit `pub` to be visible
+ StructItem(Struct { fields: ref subitems, .. }) |
+ ImplItem(Impl { methods: ref subitems, trait_: None, .. }) => {
+ let subcounts = subitems.iter().filter(|i| visible(*i))
+ .map(summarize_item)
+ .map(|s| s.val0())
+ .sum();
+ (item_counts + subcounts, None)
+ }
+ // `pub` automatically
+ EnumItem(Enum { variants: ref subitems, .. }) => {
+ let subcounts = subitems.iter().map(summarize_item)
+ .map(|s| s.val0())
+ .sum();
+ (item_counts + subcounts, None)
+ }
+ TraitItem(Trait { methods: ref methods, .. }) => {
+ fn extract_item<'a>(meth: &'a TraitMethod) -> &'a Item {
+ match *meth {
+ Provided(ref item) | Required(ref item) => item
+ }
+ }
+ let subcounts = methods.iter().map(extract_item)
+ .map(summarize_item)
+ .map(|s| s.val0())
+ .sum();
+ (item_counts + subcounts, None)
+ }
+ ModuleItem(Module { items: ref items, .. }) => {
+ let mut counts = item_counts;
+ let mut submodules = Vec::new();
+
+ for (subcounts, submodule) in items.iter().filter(|i| visible(*i))
+ .map(summarize_item) {
+ counts = counts + subcounts;
+ submodule.map(|m| submodules.push(m));
+ }
+ submodules.sort();
+
+ (counts, Some(ModuleSummary {
+ name: item.name.as_ref().map_or("".to_string(), |n| n.clone()),
+ counts: counts,
+ submodules: submodules,
+ }))
+ }
+ // no stability information for the following items:
+ ViewItemItem(_) | PrimitiveItem(_) => (Zero::zero(), None),
+ _ => (item_counts, None)
+ }
+}
+
+/// Summarizes the stability levels in a crate.
+pub fn build(krate: &Crate) -> ModuleSummary {
+ match krate.module {
+ None => ModuleSummary {
+ name: krate.name.clone(),
+ counts: Zero::zero(),
+ submodules: Vec::new(),
+ },
+ Some(ref item) => ModuleSummary {
+ name: krate.name.clone(), .. summarize_item(item).val1().unwrap()
+ }
+ }
+}
#![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/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(macro_rules, phase, globs, thread_local, managed_boxes, asm)]
#![feature(linkage, lang_items, unsafe_destructor, default_type_params)]
let path = &"./tmp/mk_rm_dir".to_c_str();
let mode = S_IWUSR | S_IRUSR;
- let result = FsRequest::mkdir(l(), path, mode);
+ let result = FsRequest::mkdir(l(), path, mode as c_int);
assert!(result.is_ok());
let result = FsRequest::rmdir(l(), path);
#![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/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, unsafe_destructor)]
#![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/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(default_type_params)]
use std::char;
#![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/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, managed_boxes, default_type_params, phase)]
* ```
*/
+#![experimental]
+
pub use core_collections::hash::{Hash, Hasher, Writer, hash, sip};
use default::Default;
}
fn from_rtio(s: rtio::FileStat) -> FileStat {
+ #[cfg(windows)]
+ type Mode = libc::c_int;
+ #[cfg(unix)]
+ type Mode = libc::mode_t;
+
let rtio::FileStat {
size, kind, perm, created, modified,
accessed, device, inode, rdev,
FileStat {
size: size,
- kind: match (kind as libc::c_int) & libc::S_IFMT {
+ kind: match (kind as Mode) & libc::S_IFMT {
libc::S_IFREG => io::TypeFile,
libc::S_IFDIR => io::TypeDirectory,
libc::S_IFIFO => io::TypeNamedPipe,
#[inline]
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
// return an error if the entire write does not fit in the buffer
- let max_size = self.buf.len();
- if self.pos >= max_size || (self.pos + buf.len()) > max_size {
+ let cap = if self.pos >= self.buf.len() { 0 } else { self.buf.len() - self.pos };
+ if buf.len() > cap {
return Err(IoError {
kind: io::OtherIoError,
desc: "Trying to write past end of buffer",
writer.write([1, 2, 3]).unwrap();
writer.write([4, 5, 6, 7]).unwrap();
assert_eq!(writer.tell(), Ok(8));
+ writer.write([]).unwrap();
+ assert_eq!(writer.tell(), Ok(8));
}
assert_eq!(buf.as_slice(), &[0, 1, 2, 3, 4, 5, 6, 7]);
}
//! passing. [`sync`](sync/index.html) contains further, primitive, shared
//! memory types, including [`atomics`](sync/atomics/index.html).
//!
-//! Common types of I/O, including files, TCP, UPD, pipes, Unix domain sockets,
+//! Common types of I/O, including files, TCP, UDP, pipes, Unix domain sockets,
//! timers, and process spawning, are defined in the [`io`](io/index.html) module.
//!
//! Rust's I/O and concurrency depends on a small runtime interface
#![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/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, globs, managed_boxes, linkage)]
// The test runner requires std::slice::Vector, so re-export std::slice just for it.
#[cfg(test)] pub use slice;
}
-
-#[deprecated]
-#[allow(missing_doc)]
-#[doc(hiden)]
-pub mod unstable {
- #[deprecated = "use std::dynamic_lib"]
- pub use dynamic_lib;
-}
/// The memory map is released (unmapped) when the destructor is run, so don't
/// let it leave scope by accident if you want it to stick around.
pub struct MemoryMap {
- /// Pointer to the memory created or modified by this map.
- pub data: *mut u8,
- /// Number of bytes this map applies to
- pub len: uint,
- /// Type of mapping
- pub kind: MemoryMapKind,
+ data: *mut u8,
+ len: uint,
+ kind: MemoryMapKind,
}
/// Type of memory map
}
}
+impl MemoryMap {
+ /// Returns the pointer to the memory created or modified by this map.
+ pub fn data(&self) -> *mut u8 { self.data }
+ /// Returns the number of bytes this map applies to.
+ pub fn len(&self) -> uint { self.len }
+ /// Returns the type of mapping this represents.
+ pub fn kind(&self) -> MemoryMapKind { self.kind }
+}
+
#[cfg(target_os = "linux")]
pub mod consts {
pub use os::arch_consts::ARCH;
#![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/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(phase, globs, macro_rules, unsafe_destructor)]
impl Show for Ident {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "\"{}\"#{}", token::get_ident(*self).get(), self.ctxt)
+ write!(f, "{}#{}", self.name, self.ctxt)
+ }
+}
+
+impl Show for Name {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let Name(nm) = *self;
+ write!(f, "\"{}\"({})", token::get_name(*self).get(), nm)
}
}
/// A name is a part of an identifier, representing a string or gensym. It's
/// the result of interning.
-#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Encodable, Decodable, Clone, Show)]
+#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Encodable, Decodable, Clone)]
pub struct Name(pub u32);
impl Name {
pub attrs: Vec<Attribute>,
pub config: CrateConfig,
pub span: Span,
+ pub exported_macros: Vec<Span>
}
pub type MetaItem = Spanned<MetaItem_>;
/// There's only one flavor, now, so this could presumably be simplified.
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)]
pub enum Mac_ {
+ // NB: the additional ident for a macro_rules-style macro is actually
+ // stored in the enclosing item. Oog.
MacInvocTT(Path, Vec<TokenTree> , SyntaxContext), // new macro-invocation
}
pub type ExplicitSelf = Spanned<ExplicitSelf_>;
-// Represents a method declaration
#[deriving(PartialEq, Eq, Encodable, Decodable, Hash)]
pub struct Method {
- pub ident: Ident,
pub attrs: Vec<Attribute>,
- pub generics: Generics,
- pub explicit_self: ExplicitSelf,
- pub fn_style: FnStyle,
- pub decl: P<FnDecl>,
- pub body: P<Block>,
pub id: NodeId,
pub span: Span,
- pub vis: Visibility,
+ pub node: Method_
+}
+
+#[deriving(PartialEq, Eq, Encodable, Decodable, Hash)]
+pub enum Method_ {
+ /// Represents a method declaration
+ MethDecl(Ident, Generics, ExplicitSelf, FnStyle, P<FnDecl>, P<Block>, Visibility),
+ /// Represents a macro in method position
+ MethMac(Mac),
}
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)]
hi: BytePos(20),
expn_info: None,
},
+ exported_macros: Vec::new(),
};
// doesn't matter which encoder we use....
let _f = &e as &serialize::Encodable<json::Encoder, io::IoError>;
NodeLifetime(Gc<Lifetime>),
}
+/// Represents an entry and its parent Node ID
/// The odd layout is to bring down the total size.
#[deriving(Clone)]
enum MapEntry {
}
}
+/// Represents a mapping from Node IDs to AST elements and their parent
+/// Node IDs
pub struct Map {
/// NodeIds are sequential integers from 0, so we can be
/// super-compact by storing them in a vector. Not everything with
}
}
+ /// returns the name associated with the given NodeId's AST
pub fn get_path_elem(&self, id: NodeId) -> PathElem {
- match self.get(id) {
+ let node = self.get(id);
+ match node {
NodeItem(item) => {
match item.node {
ItemMod(_) | ItemForeignMod(_) => {
}
}
NodeForeignItem(i) => PathName(i.ident.name),
- NodeMethod(m) => PathName(m.ident.name),
+ NodeMethod(m) => match m.node {
+ MethDecl(ident, _, _, _, _, _, _) => PathName(ident.name),
+ MethMac(_) => fail!("no path elem for {:?}", node)
+ },
NodeTraitMethod(tm) => match *tm {
Required(ref m) => PathName(m.ident.name),
- Provided(ref m) => PathName(m.ident.name)
+ Provided(m) => match m.node {
+ MethDecl(ident, _, _, _, _, _, _) => PathName(ident.name),
+ MethMac(_) => fail!("no path elem for {:?}", node),
+ }
},
NodeVariant(v) => PathName(v.node.name.name),
- node => fail!("no path elem for {:?}", node)
+ _ => fail!("no path elem for {:?}", node)
}
}
}
}
+ /// Given a node ID and a closure, apply the closure to the array
+ /// of attributes associated with the AST corresponding to the Node ID
pub fn with_attrs<T>(&self, id: NodeId, f: |Option<&[Attribute]>| -> T) -> T {
let node = self.get(id);
let attrs = match node {
}
}
+/// A Folder that walks over an AST and constructs a Node ID Map. Its
+/// fold_ops argument has the opportunity to replace Node IDs and spans.
pub struct Ctx<'a, F> {
map: &'a Map,
/// The node in which we are currently mapping (an item or a method).
m
}
- fn fold_method(&mut self, m: Gc<Method>) -> Gc<Method> {
+ fn fold_method(&mut self, m: Gc<Method>) -> SmallVector<Gc<Method>> {
let parent = self.parent;
self.parent = DUMMY_NODE_ID;
- let m = fold::noop_fold_method(&*m, self);
+ let m = fold::noop_fold_method(&*m, self).expect_one(
+ "noop_fold_method must produce exactly one method");
assert_eq!(self.parent, m.id);
self.parent = parent;
- m
+ SmallVector::one(m)
}
fn fold_fn_decl(&mut self, decl: &FnDecl) -> P<FnDecl> {
self.insert(lifetime.id, EntryLifetime(self.parent, box(GC) lifetime));
lifetime
}
+
+ fn fold_mac(&mut self, mac: &Mac) -> Mac {
+ fold::fold_mac(mac, self)
+ }
}
pub fn map_crate<F: FoldOps>(krate: Crate, fold_ops: F) -> (Crate, Map) {
let path_str = map.path_to_str_with_ident(id, item.ident);
format!("foreign item {} (id={})", path_str, id)
}
- Some(NodeMethod(m)) => {
- format!("method {} in {} (id={})",
- token::get_ident(m.ident),
- map.path_to_string(id), id)
- }
+ Some(NodeMethod(m)) => match m.node {
+ MethDecl(ident, _, _, _, _, _, _) =>
+ format!("method {} in {} (id={})",
+ token::get_ident(ident),
+ map.path_to_string(id), id),
+ MethMac(ref mac) =>
+ format!("method macro {} (id={})",
+ pprust::mac_to_string(mac), id)
+ },
Some(NodeTraitMethod(ref tm)) => {
let m = ast_util::trait_method_to_ty_method(&**tm);
format!("method {} in {} (id={})",
token::gensym_ident(pretty.as_slice())
}
-pub fn public_methods(ms: Vec<Gc<Method>> ) -> Vec<Gc<Method>> {
- ms.move_iter().filter(|m| {
- match m.vis {
- Public => true,
- _ => false
- }
- }).collect()
-}
-
/// extract a TypeMethod from a TraitMethod. if the TraitMethod is
/// a default, pull out the useful fields to make a TypeMethod
+//
+// NB: to be used only after expansion is complete, and macros are gone.
pub fn trait_method_to_ty_method(method: &TraitMethod) -> TypeMethod {
match *method {
Required(ref m) => (*m).clone(),
- Provided(ref m) => {
- TypeMethod {
- ident: m.ident,
- attrs: m.attrs.clone(),
- fn_style: m.fn_style,
- decl: m.decl,
- generics: m.generics.clone(),
- explicit_self: m.explicit_self,
- id: m.id,
- span: m.span,
- vis: m.vis,
+ Provided(m) => {
+ match m.node {
+ MethDecl(ident, ref generics, explicit_self, fn_style, decl, _, vis) => {
+ TypeMethod {
+ ident: ident,
+ attrs: m.attrs.clone(),
+ fn_style: fn_style,
+ decl: decl,
+ generics: generics.clone(),
+ explicit_self: explicit_self,
+ id: m.id,
+ span: m.span,
+ vis: vis,
+ }
+ },
+ MethMac(_) => fail!("expected non-macro method declaration")
}
+
}
}
}
fn visit_id(&self, node_id: NodeId);
}
+/// A visitor that applies its operation to all of the node IDs
+/// in a visitable thing.
+
pub struct IdVisitor<'a, O> {
pub operation: &'a O,
pub pass_through_items: bool,
inline == InlineNever || inline == InlineNone
}
+
+/// Macro invocations are guaranteed not to occur after expansion is complete.
+/// extracting fields of a method requires a dynamic check to make sure that it's
+/// not a macro invocation, though this check is guaranteed to succeed, assuming
+/// that the invocations are indeed gone.
+macro_rules! method_field_extractor {
+ ($fn_name:ident, $field_ty:ty, $field_pat:pat, $result:ident) => {
+ /// Returns the ident of a Method. To be used after expansion is complete
+ pub fn $fn_name<'a>(method: &'a ast::Method) -> $field_ty {
+ match method.node {
+ $field_pat => $result,
+ MethMac(_) => {
+ fail!("expected an AST without macro invocations");
+ }
+ }
+ }
+ }
+}
+
+// Note: this is unhygienic in the lifetime 'a. In order to fix this, we'd have to
+// add :lifetime as a macro argument type, so that the 'a could be supplied by the macro
+// invocation.
+pub method_field_extractor!(method_ident,ast::Ident,MethDecl(ident,_,_,_,_,_,_),ident)
+pub method_field_extractor!(method_generics,&'a ast::Generics,
+ MethDecl(_,ref generics,_,_,_,_,_),generics)
+pub method_field_extractor!(method_explicit_self,&'a ast::ExplicitSelf,
+ MethDecl(_,_,ref explicit_self,_,_,_,_),explicit_self)
+pub method_field_extractor!(method_fn_style,ast::FnStyle,MethDecl(_,_,_,fn_style,_,_,_),fn_style)
+pub method_field_extractor!(method_fn_decl,P<ast::FnDecl>,MethDecl(_,_,_,_,decl,_,_),decl)
+pub method_field_extractor!(method_body,P<ast::Block>,MethDecl(_,_,_,_,_,body,_),body)
+pub method_field_extractor!(method_vis,ast::Visibility,MethDecl(_,_,_,_,_,_,vis),vis)
+
#[cfg(test)]
mod test {
use ast::*;
.iter().map(ident_to_segment).collect::<Vec<PathSegment>>().as_slice()));
}
}
+
pub span: Option<Span>
}
-pub trait MacroExpander {
+/// Represents a thing that maps token trees to Macro Results
+pub trait TTMacroExpander {
fn expand(&self,
ecx: &mut ExtCtxt,
span: Span,
fn(ecx: &mut ExtCtxt, span: codemap::Span, token_tree: &[ast::TokenTree])
-> Box<MacResult>;
-impl MacroExpander for BasicMacroExpander {
+impl TTMacroExpander for BasicMacroExpander {
fn expand(&self,
ecx: &mut ExtCtxt,
span: Span,
/// just into the compiler's internal macro table, for `make_def`).
pub trait MacResult {
/// Define a new macro.
+ // this should go away; the idea that a macro might expand into
+ // either a macro definition or an expression, depending on what
+ // the context wants, is kind of silly.
fn make_def(&self) -> Option<MacroDef> {
None
}
fn make_items(&self) -> Option<SmallVector<Gc<ast::Item>>> {
None
}
+
+ /// Create zero or more methods.
+ fn make_methods(&self) -> Option<SmallVector<Gc<ast::Method>>> {
+ None
+ }
+
/// Create a pattern.
fn make_pat(&self) -> Option<Gc<ast::Pat>> {
None
span: sp,
}
}
+
}
impl MacResult for DummyResult {
Some(DummyResult::raw_pat(self.span))
}
fn make_items(&self) -> Option<SmallVector<Gc<ast::Item>>> {
+ // this code needs a comment... why not always just return the Some() ?
+ if self.expr_only {
+ None
+ } else {
+ Some(SmallVector::zero())
+ }
+ }
+ fn make_methods(&self) -> Option<SmallVector<Gc<ast::Method>>> {
if self.expr_only {
None
} else {
/// A normal, function-like syntax extension.
///
/// `bytes!` is a `NormalTT`.
- NormalTT(Box<MacroExpander + 'static>, Option<Span>),
+ NormalTT(Box<TTMacroExpander + 'static>, Option<Span>),
/// A function-like syntax extension that has an extra ident before
/// the block.
pub mod_path: Vec<ast::Ident> ,
pub trace_mac: bool,
+ pub exported_macros: Vec<codemap::Span>
}
impl<'a> ExtCtxt<'a> {
backtrace: None,
mod_path: Vec::new(),
ecfg: ecfg,
- trace_mac: false
+ trace_mac: false,
+ exported_macros: Vec::new(),
}
}
pub fn name_of(&self, st: &str) -> ast::Name {
token::intern(st)
}
+ pub fn push_exported_macro(&mut self, span: codemap::Span) {
+ self.exported_macros.push(span);
+ }
}
/// Extract a string literal from the macro expanded version of `expr`,
args: Vec::new(),
ret_ty: Self,
attributes: attrs,
- const_nonmatching: false,
combine_substructure: combine_substructure(|c, s, sub| {
cs_clone("Clone", c, s, sub)
}),
ctor_ident = variant.node.name;
all_fields = af;
},
- EnumNonMatching(..) => {
+ EnumNonMatchingCollapsed (..) => {
cx.span_bug(trait_span,
format!("non-matching enum variants in \
`deriving({})`",
args: vec!(borrowed_self()),
ret_ty: Literal(Path::new(vec!("bool"))),
attributes: attrs,
- const_nonmatching: true,
combine_substructure: combine_substructure(|a, b, c| {
$f(a, b, c)
})
args: vec!(borrowed_self()),
ret_ty: Literal(Path::new(vec!("bool"))),
attributes: attrs,
- const_nonmatching: false,
combine_substructure: combine_substructure(|cx, span, substr| {
cs_op($op, $equal, cx, span, substr)
})
args: vec![borrowed_self()],
ret_ty: ret_ty,
attributes: attrs,
- const_nonmatching: false,
combine_substructure: combine_substructure(|cx, span, substr| {
cs_partial_cmp(cx, span, substr)
})
trait_def.expand(cx, mitem, item, push)
}
-pub fn some_ordering_const(cx: &mut ExtCtxt, span: Span, cnst: Ordering) -> Gc<ast::Expr> {
- let cnst = match cnst {
- Less => "Less",
- Equal => "Equal",
- Greater => "Greater"
+pub enum OrderingOp {
+ PartialCmpOp, LtOp, LeOp, GtOp, GeOp,
+}
+
+pub fn some_ordering_collapsed(cx: &mut ExtCtxt,
+ span: Span,
+ op: OrderingOp,
+ self_arg_tags: &[ast::Ident]) -> Gc<ast::Expr> {
+ let lft = cx.expr_ident(span, self_arg_tags[0]);
+ let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1]));
+ let op_str = match op {
+ PartialCmpOp => "partial_cmp",
+ LtOp => "lt", LeOp => "le",
+ GtOp => "gt", GeOp => "ge",
};
- let ordering = cx.path_global(span,
- vec!(cx.ident_of("std"),
- cx.ident_of("cmp"),
- cx.ident_of(cnst)));
- let ordering = cx.expr_path(ordering);
- cx.expr_some(span, ordering)
+ cx.expr_method_call(span, lft, cx.ident_of(op_str), vec![rgt])
}
pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span,
substr: &Substructure) -> Gc<Expr> {
let test_id = cx.ident_of("__test");
- let equals_expr = some_ordering_const(cx, span, Equal);
+ let ordering = cx.path_global(span,
+ vec!(cx.ident_of("std"),
+ cx.ident_of("cmp"),
+ cx.ident_of("Equal")));
+ let ordering = cx.expr_path(ordering);
+ let equals_expr = cx.expr_some(span, ordering);
/*
Builds:
cx.expr_block(cx.block(span, vec!(assign), Some(if_)))
},
equals_expr.clone(),
- |cx, span, list, _| {
- match list {
- // an earlier nonmatching variant is Less than a
- // later one.
- [(self_var, _, _), (other_var, _, _)] =>
- some_ordering_const(cx, span, self_var.cmp(&other_var)),
- _ => cx.span_bug(span, "not exactly 2 arguments in `deriving(Ord)`")
+ |cx, span, (self_args, tag_tuple), _non_self_args| {
+ if self_args.len() != 2 {
+ cx.span_bug(span, "not exactly 2 arguments in `deriving(Ord)`")
+ } else {
+ some_ordering_collapsed(cx, span, PartialCmpOp, tag_tuple)
}
},
cx, span, substr)
cx.expr_binary(span, ast::BiOr, cmp, and)
},
cx.expr_bool(span, equal),
- |cx, span, args, _| {
- // nonmatching enums, order by the order the variants are
- // written
- match args {
- [(self_var, _, _),
- (other_var, _, _)] =>
- cx.expr_bool(span,
- if less {
- self_var < other_var
- } else {
- self_var > other_var
- }),
- _ => cx.span_bug(span, "not exactly 2 arguments in `deriving(Ord)`")
+ |cx, span, (self_args, tag_tuple), _non_self_args| {
+ if self_args.len() != 2 {
+ cx.span_bug(span, "not exactly 2 arguments in `deriving(Ord)`")
+ } else {
+ let op = match (less, equal) {
+ (true, true) => LeOp, (true, false) => LtOp,
+ (false, true) => GeOp, (false, false) => GtOp,
+ };
+ some_ordering_collapsed(cx, span, op, tag_tuple)
}
},
cx, span, substr)
args: vec!(),
ret_ty: nil_ty(),
attributes: attrs,
- const_nonmatching: true,
combine_substructure: combine_substructure(|a, b, c| {
cs_total_eq_assert(a, b, c)
})
use ext::deriving::generic::ty::*;
use parse::token::InternedString;
-use std::cmp::{Ordering, Equal, Less, Greater};
use std::gc::Gc;
pub fn expand_deriving_totalord(cx: &mut ExtCtxt,
args: vec!(borrowed_self()),
ret_ty: Literal(Path::new(vec!("std", "cmp", "Ordering"))),
attributes: attrs,
- const_nonmatching: false,
combine_substructure: combine_substructure(|a, b, c| {
cs_cmp(a, b, c)
}),
}
-pub fn ordering_const(cx: &mut ExtCtxt, span: Span, cnst: Ordering) -> ast::Path {
- let cnst = match cnst {
- Less => "Less",
- Equal => "Equal",
- Greater => "Greater"
- };
- cx.path_global(span,
- vec!(cx.ident_of("std"),
- cx.ident_of("cmp"),
- cx.ident_of(cnst)))
+pub fn ordering_collapsed(cx: &mut ExtCtxt,
+ span: Span,
+ self_arg_tags: &[ast::Ident]) -> Gc<ast::Expr> {
+ let lft = cx.expr_ident(span, self_arg_tags[0]);
+ let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1]));
+ cx.expr_method_call(span, lft, cx.ident_of("cmp"), vec![rgt])
}
pub fn cs_cmp(cx: &mut ExtCtxt, span: Span,
substr: &Substructure) -> Gc<Expr> {
let test_id = cx.ident_of("__test");
- let equals_path = ordering_const(cx, span, Equal);
+ let equals_path = cx.path_global(span,
+ vec!(cx.ident_of("std"),
+ cx.ident_of("cmp"),
+ cx.ident_of("Equal")));
/*
Builds:
cx.expr_block(cx.block(span, vec!(assign), Some(if_)))
},
cx.expr_path(equals_path.clone()),
- |cx, span, list, _| {
- match list {
- // an earlier nonmatching variant is Less than a
- // later one.
- [(self_var, _, _),
- (other_var, _, _)] => {
- let order = ordering_const(cx, span, self_var.cmp(&other_var));
- cx.expr_path(order)
- }
- _ => cx.span_bug(span, "not exactly 2 arguments in `deriving(Ord)`")
+ |cx, span, (self_args, tag_tuple), _non_self_args| {
+ if self_args.len() != 2 {
+ cx.span_bug(span, "not exactly 2 arguments in `deriving(TotalOrd)`")
+ } else {
+ ordering_collapsed(cx, span, tag_tuple)
}
},
cx, span, substr)
vec!(box Self,
box Literal(Path::new_local("__E"))), true)),
attributes: Vec::new(),
- const_nonmatching: true,
combine_substructure: combine_substructure(|a, b, c| {
decodable_substructure(a, b, c)
}),
args: Vec::new(),
ret_ty: Self,
attributes: attrs,
- const_nonmatching: false,
combine_substructure: combine_substructure(|a, b, c| {
default_substructure(a, b, c)
})
box Literal(Path::new_local("__E"))),
true)),
attributes: Vec::new(),
- const_nonmatching: true,
combine_substructure: combine_substructure(|a, b, c| {
encodable_substructure(a, b, c)
}),
//! `struct T(int, char)`).
//! - `EnumMatching`, when `Self` is an enum and all the arguments are the
//! same variant of the enum (e.g. `Some(1)`, `Some(3)` and `Some(4)`)
-//! - `EnumNonMatching` when `Self` is an enum and the arguments are not
-//! the same variant (e.g. `None`, `Some(1)` and `None`). If
-//! `const_nonmatching` is true, this will contain an empty list.
+//! - `EnumNonMatchingCollapsed` when `Self` is an enum and the arguments
+//! are not the same variant (e.g. `None`, `Some(1)` and `None`).
//! - `StaticEnum` and `StaticStruct` for static methods, where the type
//! being derived upon is either an enum or struct respectively. (Any
//! argument with type Self is just grouped among the non-self
//! arguments.)
//!
//! In the first two cases, the values from the corresponding fields in
-//! all the arguments are grouped together. In the `EnumNonMatching` case
+//! all the arguments are grouped together. For `EnumNonMatchingCollapsed`
//! this isn't possible (different variants have different fields), so the
-//! fields are grouped by which argument they come from. There are no
+//! fields are inaccessible. (Previous versions of the deriving infrastructure
+//! had a way to expand into code that could access them, at the cost of
+//! generating exponential amounts of code; see issue #15375). There are no
//! fields with values in the static cases, so these are treated entirely
//! differently.
//!
//! For `C0(a)` and `C1 {x}` ,
//!
//! ~~~text
-//! EnumNonMatching(~[(0, <ast::Variant for B0>,
-//! ~[(<span of int>, None, <expr for &a>)]),
-//! (1, <ast::Variant for B1>,
-//! ~[(<span of x>, Some(<ident of x>),
-//! <expr for &other.x>)])])
+//! EnumNonMatchingCollapsed(
+//! ~[<ident of self>, <ident of __arg_1>],
+//! &[<ast::Variant for C0>, <ast::Variant for C1>],
+//! &[<ident for self index value>, <ident of __arg_1 index value>])
//! ~~~
//!
-//! (and vice versa, but with the order of the outermost list flipped.)
+//! It is the same for when the arguments are flipped to `C1 {x}` and
+//! `C0(a)`; the only difference is what the values of the identifiers
+//! <ident for self index value> and <ident of __arg_1 index value> will
+//! be in the generated code.
+//!
+//! `EnumNonMatchingCollapsed` deliberately provides far less information
+//! than is generally available for a given pair of variants; see #15375
+//! for discussion.
//!
//! ## Static
//!
pub attributes: Vec<ast::Attribute>,
- /// if the value of the nonmatching enums is independent of the
- /// actual enum variants, i.e. can use _ => .. match.
- pub const_nonmatching: bool,
-
pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
}
EnumMatching(uint, &'a ast::Variant, Vec<FieldInfo>),
/**
- non-matching variants of the enum, [(variant index, ast::Variant,
- [field span, field ident, fields])] \(i.e. all fields for self are in the
- first tuple, for other1 are in the second tuple, etc.)
+ non-matching variants of the enum, but with all state hidden from
+ the consequent code. The first component holds Idents for all of
+ the Self arguments; the second component is a slice of all of the
+ variants for the enum itself, and the third component is a list of
+ Idents bound to the variant index values for each of the actual
+ input Self arguments.
*/
- EnumNonMatching(&'a [(uint, P<ast::Variant>,
- Vec<(Span, Option<Ident>, Gc<Expr>)>)]),
+ EnumNonMatchingCollapsed(Vec<Ident>, &'a [Gc<ast::Variant>], &'a [Ident]),
/// A static method where Self is a struct.
StaticStruct(&'a ast::StructDef, StaticFields),
|&mut ExtCtxt, Span, &Substructure|: 'a -> Gc<Expr>;
/**
-Deal with non-matching enum variants, the arguments are a list
-representing each variant: (variant index, ast::Variant instance,
-[variant fields]), and a list of the nonself args of the type
+Deal with non-matching enum variants. The tuple is a list of
+identifiers (one for each Self argument, which could be any of the
+variants since they have been collapsed together) and the identifiers
+holding the variant index value for each of the Self arguments. The
+last argument is all the non-Self args of the method being derived.
*/
-pub type EnumNonMatchFunc<'a> =
+pub type EnumNonMatchCollapsedFunc<'a> =
|&mut ExtCtxt,
Span,
- &[(uint, P<ast::Variant>, Vec<(Span, Option<Ident>, Gc<Expr>)>)],
+ (&[Ident], &[Ident]),
&[Gc<Expr>]|: 'a
-> Gc<Expr>;
}
}
+fn variant_to_pat(cx: &mut ExtCtxt, sp: Span, variant: &ast::Variant)
+ -> Gc<ast::Pat> {
+ let ident = cx.path_ident(sp, variant.node.name);
+ cx.pat(sp, match variant.node.kind {
+ ast::TupleVariantKind(..) => ast::PatEnum(ident, None),
+ ast::StructVariantKind(..) => ast::PatStruct(ident, Vec::new(), true),
+ })
+}
+
impl<'a> MethodDef<'a> {
fn call_substructure_method(&self,
cx: &mut ExtCtxt,
// Create the method.
box(GC) ast::Method {
- ident: method_ident,
attrs: self.attributes.clone(),
- generics: fn_generics,
- explicit_self: explicit_self,
- fn_style: ast::NormalFn,
- decl: fn_decl,
- body: body_block,
id: ast::DUMMY_NODE_ID,
span: trait_.span,
- vis: ast::Inherited,
+ node: ast::MethDecl(method_ident,
+ fn_generics,
+ explicit_self,
+ ast::NormalFn,
+ fn_decl,
+ body_block,
+ ast::Inherited)
}
}
~~~
#[deriving(PartialEq)]
enum A {
- A1
+ A1,
A2(int)
}
- // is equivalent to (with const_nonmatching == false)
+ // is equivalent to
impl PartialEq for A {
- fn eq(&self, __arg_1: &A) {
- match *self {
- A1 => match *__arg_1 {
- A1 => true
- A2(ref __arg_1_1) => false
- },
- A2(self_1) => match *__arg_1 {
- A1 => false,
- A2(ref __arg_1_1) => self_1.eq(__arg_1_1)
+ fn eq(&self, __arg_1: &A) -> ::bool {
+ match (&*self, &*__arg_1) {
+ (&A1, &A1) => true,
+ (&A2(ref __self_0),
+ &A2(ref __arg_1_0)) => (*__self_0).eq(&(*__arg_1_0)),
+ _ => {
+ let __self_vi = match *self { A1(..) => 0u, A2(..) => 1u };
+ let __arg_1_vi = match *__arg_1 { A1(..) => 0u, A2(..) => 1u };
+ false
}
}
}
}
~~~
+
+ (Of course `__self_vi` and `__arg_1_vi` are unused for
+ `PartialEq`, and those subcomputations will hopefully be removed
+ as their results are unused. The point of `__self_vi` and
+ `__arg_1_vi` is for `PartialOrd`; see #15503.)
*/
fn expand_enum_method_body(&self,
cx: &mut ExtCtxt,
self_args: &[Gc<Expr>],
nonself_args: &[Gc<Expr>])
-> Gc<Expr> {
- let mut matches = Vec::new();
- self.build_enum_match(cx, trait_, enum_def, type_ident,
- self_args, nonself_args,
- None, &mut matches, 0)
+ self.build_enum_match_tuple(
+ cx, trait_, enum_def, type_ident, self_args, nonself_args)
}
/**
- Creates the nested matches for an enum definition recursively, i.e.
-
- ~~~text
- match self {
- Variant1 => match other { Variant1 => matching, Variant2 => nonmatching, ... },
- Variant2 => match other { Variant1 => nonmatching, Variant2 => matching, ... },
- ...
+ Creates a match for a tuple of all `self_args`, where either all
+ variants match, or it falls into a catch-all for when one variant
+ does not match.
+
+ There are N + 1 cases because is a case for each of the N
+ variants where all of the variants match, and one catch-all for
+ when one does not match.
+
+ The catch-all handler is provided access the variant index values
+ for each of the self-args, carried in precomputed variables. (Nota
+ bene: the variant index values are not necessarily the
+ discriminant values. See issue #15523.)
+
+ ~~~text
+ match (this, that, ...) {
+ (Variant1, Variant1, Variant1) => ... // delegate Matching on Variant1
+ (Variant2, Variant2, Variant2) => ... // delegate Matching on Variant2
+ ...
+ _ => {
+ let __this_vi = match this { Variant1 => 0u, Variant2 => 1u, ... };
+ let __that_vi = match that { Variant1 => 0u, Variant2 => 1u, ... };
+ ... // catch-all remainder can inspect above variant index values.
+ }
}
- ~~~
-
- It acts in the most naive way, so every branch (and subbranch,
- subsubbranch, etc) exists, not just the ones where all the variants in
- the tree are the same. Hopefully the optimisers get rid of any
- repetition, otherwise derived methods with many Self arguments will be
- exponentially large.
-
- `matching` is Some(n) if all branches in the tree above the
- current position are variant `n`, `None` otherwise (including on
- the first call).
+ ~~~
*/
- fn build_enum_match(&self,
- cx: &mut ExtCtxt,
- trait_: &TraitDef,
- enum_def: &EnumDef,
- type_ident: Ident,
- self_args: &[Gc<Expr>],
- nonself_args: &[Gc<Expr>],
- matching: Option<uint>,
- matches_so_far: &mut Vec<(uint, P<ast::Variant>,
- Vec<(Span, Option<Ident>, Gc<Expr>)>)> ,
- match_count: uint) -> Gc<Expr> {
- if match_count == self_args.len() {
- // we've matched against all arguments, so make the final
- // expression at the bottom of the match tree
- if matches_so_far.len() == 0 {
- cx.span_bug(trait_.span,
- "no self match on an enum in \
- generic `deriving`");
- }
-
- // `ref` inside let matches is buggy. Causes havoc with rusc.
- // let (variant_index, ref self_vec) = matches_so_far[0];
- let (variant, self_vec) = match matches_so_far.get(0) {
- &(_, v, ref s) => (v, s)
- };
-
- // we currently have a vec of vecs, where each
- // subvec is the fields of one of the arguments,
- // but if the variants all match, we want this as
- // vec of tuples, where each tuple represents a
- // field.
-
- // most arms don't have matching variants, so do a
- // quick check to see if they match (even though
- // this means iterating twice) instead of being
- // optimistic and doing a pile of allocations etc.
- let substructure = match matching {
- Some(variant_index) => {
- let mut enum_matching_fields = Vec::from_elem(self_vec.len(), Vec::new());
-
- for triple in matches_so_far.tail().iter() {
- match triple {
- &(_, _, ref other_fields) => {
- for (i, &(_, _, e)) in other_fields.iter().enumerate() {
- enum_matching_fields.get_mut(i).push(e);
- }
- }
- }
- }
- let field_tuples =
- self_vec.iter()
- .zip(enum_matching_fields.iter())
- .map(|(&(span, id, self_f), other)| {
- FieldInfo {
- span: span,
- name: id,
- self_: self_f,
- other: (*other).clone()
- }
- }).collect();
- EnumMatching(variant_index, &*variant, field_tuples)
- }
- None => {
- EnumNonMatching(matches_so_far.as_slice())
+ fn build_enum_match_tuple(
+ &self,
+ cx: &mut ExtCtxt,
+ trait_: &TraitDef,
+ enum_def: &EnumDef,
+ type_ident: Ident,
+ self_args: &[Gc<Expr>],
+ nonself_args: &[Gc<Expr>]) -> Gc<Expr> {
+
+ let sp = trait_.span;
+ let variants = &enum_def.variants;
+
+ let self_arg_names = self_args.iter().enumerate()
+ .map(|(arg_count, _self_arg)| {
+ if arg_count == 0 {
+ "__self".to_string()
+ } else {
+ format!("__arg_{}", arg_count)
}
- };
- self.call_substructure_method(cx, trait_, type_ident,
- self_args, nonself_args,
- &substructure)
+ })
+ .collect::<Vec<String>>();
+
+ let self_arg_idents = self_arg_names.iter()
+ .map(|name|cx.ident_of(name.as_slice()))
+ .collect::<Vec<ast::Ident>>();
+
+ // The `vi_idents` will be bound, solely in the catch-all, to
+ // a series of let statements mapping each self_arg to a uint
+ // corresponding to its variant index.
+ let vi_idents : Vec<ast::Ident> = self_arg_names.iter()
+ .map(|name| { let vi_suffix = format!("{:s}_vi", name.as_slice());
+ cx.ident_of(vi_suffix.as_slice()) })
+ .collect::<Vec<ast::Ident>>();
+
+ // Builds, via callback to call_substructure_method, the
+ // delegated expression that handles the catch-all case,
+ // using `__variants_tuple` to drive logic if necessary.
+ let catch_all_substructure = EnumNonMatchingCollapsed(
+ self_arg_idents, variants.as_slice(), vi_idents.as_slice());
+
+ // These arms are of the form:
+ // (Variant1, Variant1, ...) => Body1
+ // (Variant2, Variant2, ...) => Body2
+ // ...
+ // where each tuple has length = self_args.len()
+ let mut match_arms : Vec<ast::Arm> = variants.iter().enumerate()
+ .map(|(index, &variant)| {
+
+ // These self_pats have form Variant1, Variant2, ...
+ let self_pats : Vec<(Gc<ast::Pat>,
+ Vec<(Span, Option<Ident>, Gc<Expr>)>)>;
+ self_pats = self_arg_names.iter()
+ .map(|self_arg_name|
+ trait_.create_enum_variant_pattern(
+ cx, &*variant, self_arg_name.as_slice(),
+ ast::MutImmutable))
+ .collect();
+
+ // A single arm has form (&VariantK, &VariantK, ...) => BodyK
+ // (see "Final wrinkle" note below for why.)
+ let subpats = self_pats.iter()
+ .map(|&(p, ref _idents)| cx.pat(sp, ast::PatRegion(p)))
+ .collect::<Vec<Gc<ast::Pat>>>();
+
+ // Here is the pat = `(&VariantK, &VariantK, ...)`
+ let single_pat = cx.pat(sp, ast::PatTup(subpats));
+
+ // For the BodyK, we need to delegate to our caller,
+ // passing it an EnumMatching to indicate which case
+ // we are in.
+
+ // All of the Self args have the same variant in these
+ // cases. So we transpose the info in self_pats to
+ // gather the getter expressions together, in the form
+ // that EnumMatching expects.
+
+ // The transposition is driven by walking across the
+ // arg fields of the variant for the first self pat.
+ let &(_, ref self_arg_fields) = self_pats.get(0);
+
+ let field_tuples : Vec<FieldInfo>;
+
+ field_tuples = self_arg_fields.iter().enumerate()
+ // For each arg field of self, pull out its getter expr ...
+ .map(|(field_index, &(sp, opt_ident, self_getter_expr))| {
+ // ... but FieldInfo also wants getter expr
+ // for matching other arguments of Self type;
+ // so walk across the *other* self_pats and
+ // pull out getter for same field in each of
+ // them (using `field_index` tracked above).
+ // That is the heart of the transposition.
+ let others = self_pats.tail().iter()
+ .map(|&(_pat, ref fields)| {
+
+ let &(_, _opt_ident, other_getter_expr) =
+ fields.get(field_index);
+
+ // All Self args have same variant, so
+ // opt_idents are the same. (Assert
+ // here to make it self-evident that
+ // it is okay to ignore `_opt_ident`.)
+ assert!(opt_ident == _opt_ident);
+
+ other_getter_expr
+ }).collect::<Vec<Gc<Expr>>>();
+
+ FieldInfo { span: sp,
+ name: opt_ident,
+ self_: self_getter_expr,
+ other: others,
+ }
+ }).collect::<Vec<FieldInfo>>();
+
+ // Now, for some given VariantK, we have built up
+ // expressions for referencing every field of every
+ // Self arg, assuming all are instances of VariantK.
+ // Build up code associated with such a case.
+ let substructure = EnumMatching(index, variant, field_tuples);
+ let arm_expr = self.call_substructure_method(
+ cx, trait_, type_ident, self_args, nonself_args,
+ &substructure);
+
+ cx.arm(sp, vec![single_pat], arm_expr)
+ }).collect();
- } else { // there are still matches to create
- let current_match_str = if match_count == 0 {
- "__self".to_string()
- } else {
- format!("__arg_{}", match_count)
- };
+ // We will usually need the catch-all after matching the
+ // tuples `(VariantK, VariantK, ...)` for each VariantK of the
+ // enum. But:
+ //
+ // * when there is only one Self arg, the arms above suffice
+ // (and the deriving we call back into may not be prepared to
+ // handle EnumNonMatchCollapsed), and,
+ //
+ // * when the enum has only one variant, the single arm that
+ // is already present always suffices.
+ //
+ // * In either of the two cases above, if we *did* add a
+ // catch-all `_` match, it would trigger the
+ // unreachable-pattern error.
+ //
+ if variants.len() > 1 && self_args.len() > 1 {
+ let arms : Vec<ast::Arm> = variants.iter().enumerate()
+ .map(|(index, &variant)| {
+ let pat = variant_to_pat(cx, sp, &*variant);
+ let lit = ast::LitUint(index as u64, ast::TyU);
+ cx.arm(sp, vec![pat], cx.expr_lit(sp, lit))
+ }).collect();
- let mut arms = Vec::new();
-
- // the code for nonmatching variants only matters when
- // we've seen at least one other variant already
- if self.const_nonmatching && match_count > 0 {
- // make a matching-variant match, and a _ match.
- let index = match matching {
- Some(i) => i,
- None => cx.span_bug(trait_.span,
- "non-matching variants when required to \
- be matching in generic `deriving`")
- };
-
- // matching-variant match
- let variant = *enum_def.variants.get(index);
- let (pattern, idents) = trait_.create_enum_variant_pattern(
- cx,
- &*variant,
- current_match_str.as_slice(),
- ast::MutImmutable);
-
- matches_so_far.push((index, variant, idents));
- let arm_expr = self.build_enum_match(cx,
- trait_,
- enum_def,
- type_ident,
- self_args, nonself_args,
- matching,
- matches_so_far,
- match_count + 1);
- matches_so_far.pop().unwrap();
- arms.push(cx.arm(trait_.span, vec!( pattern ), arm_expr));
-
- if enum_def.variants.len() > 1 {
- let e = &EnumNonMatching(&[]);
- let wild_expr = self.call_substructure_method(cx, trait_, type_ident,
- self_args, nonself_args,
- e);
- let wild_arm = cx.arm(
- trait_.span,
- vec!( cx.pat_wild(trait_.span) ),
- wild_expr);
- arms.push(wild_arm);
- }
- } else {
- // create an arm matching on each variant
- for (index, &variant) in enum_def.variants.iter().enumerate() {
- let (pattern, idents) =
- trait_.create_enum_variant_pattern(
- cx,
- &*variant,
- current_match_str.as_slice(),
- ast::MutImmutable);
-
- matches_so_far.push((index, variant, idents));
- let new_matching =
- match matching {
- _ if match_count == 0 => Some(index),
- Some(i) if index == i => Some(i),
- _ => None
- };
- let arm_expr = self.build_enum_match(cx,
- trait_,
- enum_def,
- type_ident,
- self_args, nonself_args,
- new_matching,
- matches_so_far,
- match_count + 1);
- matches_so_far.pop().unwrap();
-
- let arm = cx.arm(trait_.span, vec!( pattern ), arm_expr);
- arms.push(arm);
- }
+ // Build a series of let statements mapping each self_arg
+ // to a uint corresponding to its variant index.
+ // i.e. for `enum E<T> { A, B(1), C(T, T) }`, and a deriving
+ // with three Self args, builds three statements:
+ //
+ // ```
+ // let __self0_vi = match self {
+ // A => 0u, B(..) => 1u, C(..) => 2u
+ // };
+ // let __self1_vi = match __arg1 {
+ // A => 0u, B(..) => 1u, C(..) => 2u
+ // };
+ // let __self2_vi = match __arg2 {
+ // A => 0u, B(..) => 1u, C(..) => 2u
+ // };
+ // ```
+ let mut index_let_stmts : Vec<Gc<ast::Stmt>> = Vec::new();
+ for (&ident, &self_arg) in vi_idents.iter().zip(self_args.iter()) {
+ let variant_idx = cx.expr_match(sp, self_arg, arms.clone());
+ let let_stmt = cx.stmt_let(sp, false, ident, variant_idx);
+ index_let_stmts.push(let_stmt);
}
- // match foo { arm, arm, arm, ... }
- cx.expr_match(trait_.span, self_args[match_count], arms)
+ let arm_expr = self.call_substructure_method(
+ cx, trait_, type_ident, self_args, nonself_args,
+ &catch_all_substructure);
+
+ // Builds the expression:
+ // {
+ // let __self0_vi = ...;
+ // let __self1_vi = ...;
+ // ...
+ // <delegated expression referring to __self0_vi, et al.>
+ // }
+ let arm_expr = cx.expr_block(
+ cx.block_all(sp, Vec::new(), index_let_stmts, Some(arm_expr)));
+
+ // Builds arm:
+ // _ => { let __self0_vi = ...;
+ // let __self1_vi = ...;
+ // ...
+ // <delegated expression as above> }
+ let catch_all_match_arm =
+ cx.arm(sp, vec![cx.pat_wild(sp)], arm_expr);
+
+ match_arms.push(catch_all_match_arm);
+
+ } else if variants.len() == 0 {
+ // As an additional wrinkle, For a zero-variant enum A,
+ // currently the compiler
+ // will accept `fn (a: &Self) { match *a { } }`
+ // but rejects `fn (a: &Self) { match (&*a,) { } }`
+ // as well as `fn (a: &Self) { match ( *a,) { } }`
+ //
+ // This means that the strategy of building up a tuple of
+ // all Self arguments fails when Self is a zero variant
+ // enum: rustc rejects the expanded program, even though
+ // the actual code tends to be impossible to execute (at
+ // least safely), according to the type system.
+ //
+ // The most expedient fix for this is to just let the
+ // code fall through to the catch-all. But even this is
+ // error-prone, since the catch-all as defined above would
+ // generate code like this:
+ //
+ // _ => { let __self0 = match *self { };
+ // let __self1 = match *__arg_0 { };
+ // <catch-all-expr> }
+ //
+ // Which is yields bindings for variables which type
+ // inference cannot resolve to unique types.
+ //
+ // One option to the above might be to add explicit type
+ // annotations. But the *only* reason to go down that path
+ // would be to try to make the expanded output consistent
+ // with the case when the number of enum variants >= 1.
+ //
+ // That just isn't worth it. In fact, trying to generate
+ // sensible code for *any* deriving on a zero-variant enum
+ // does not make sense. But at the same time, for now, we
+ // do not want to cause a compile failure just because the
+ // user happened to attach a deriving to their
+ // zero-variant enum.
+ //
+ // Instead, just generate a failing expression for the
+ // zero variant case, skipping matches and also skipping
+ // delegating back to the end user code entirely.
+ //
+ // (See also #4499 and #12609; note that some of the
+ // discussions there influence what choice we make here;
+ // e.g. if we feature-gate `match x { ... }` when x refers
+ // to an uninhabited type (e.g. a zero-variant enum or a
+ // type holding such an enum), but do not feature-gate
+ // zero-variant enums themselves, then attempting to
+ // derive Show on such a type could here generate code
+ // that needs the feature gate enabled.)
+
+ return cx.expr_unreachable(sp);
}
+
+ // Final wrinkle: the self_args are expressions that deref
+ // down to desired l-values, but we cannot actually deref
+ // them when they are fed as r-values into a tuple
+ // expression; here add a layer of borrowing, turning
+ // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
+ let borrowed_self_args = self_args.iter()
+ .map(|&self_arg| cx.expr_addr_of(sp, self_arg))
+ .collect::<Vec<Gc<ast::Expr>>>();
+ let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args));
+ cx.expr_match(sp, match_arg, match_arms)
}
fn expand_static_enum_method_body(&self,
pub fn cs_fold(use_foldl: bool,
f: |&mut ExtCtxt, Span, Gc<Expr>, Gc<Expr>, &[Gc<Expr>]| -> Gc<Expr>,
base: Gc<Expr>,
- enum_nonmatch_f: EnumNonMatchFunc,
+ enum_nonmatch_f: EnumNonMatchCollapsedFunc,
cx: &mut ExtCtxt,
trait_span: Span,
substructure: &Substructure)
})
}
},
- EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span,
- *all_enums,
- substructure.nonself_args),
+ EnumNonMatchingCollapsed(ref all_args, _, tuple) =>
+ enum_nonmatch_f(cx, trait_span, (all_args.as_slice(), tuple),
+ substructure.nonself_args),
StaticEnum(..) | StaticStruct(..) => {
cx.span_bug(trait_span, "static function in `deriving`")
}
*/
#[inline]
pub fn cs_same_method(f: |&mut ExtCtxt, Span, Vec<Gc<Expr>>| -> Gc<Expr>,
- enum_nonmatch_f: EnumNonMatchFunc,
+ enum_nonmatch_f: EnumNonMatchCollapsedFunc,
cx: &mut ExtCtxt,
trait_span: Span,
substructure: &Substructure)
f(cx, trait_span, called)
},
- EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span,
- *all_enums,
- substructure.nonself_args),
+ EnumNonMatchingCollapsed(ref all_self_args, _, tuple) =>
+ enum_nonmatch_f(cx, trait_span, (all_self_args.as_slice(), tuple),
+ substructure.nonself_args),
StaticEnum(..) | StaticStruct(..) => {
cx.span_bug(trait_span, "static function in `deriving`")
}
pub fn cs_same_method_fold(use_foldl: bool,
f: |&mut ExtCtxt, Span, Gc<Expr>, Gc<Expr>| -> Gc<Expr>,
base: Gc<Expr>,
- enum_nonmatch_f: EnumNonMatchFunc,
+ enum_nonmatch_f: EnumNonMatchCollapsedFunc,
cx: &mut ExtCtxt,
trait_span: Span,
substructure: &Substructure)
*/
#[inline]
pub fn cs_binop(binop: ast::BinOp, base: Gc<Expr>,
- enum_nonmatch_f: EnumNonMatchFunc,
+ enum_nonmatch_f: EnumNonMatchCollapsedFunc,
cx: &mut ExtCtxt, trait_span: Span,
substructure: &Substructure) -> Gc<Expr> {
cs_same_method_fold(
/// cs_binop with binop == or
#[inline]
-pub fn cs_or(enum_nonmatch_f: EnumNonMatchFunc,
+pub fn cs_or(enum_nonmatch_f: EnumNonMatchCollapsedFunc,
cx: &mut ExtCtxt, span: Span,
substructure: &Substructure) -> Gc<Expr> {
cs_binop(ast::BiOr, cx.expr_bool(span, false),
/// cs_binop with binop == and
#[inline]
-pub fn cs_and(enum_nonmatch_f: EnumNonMatchFunc,
+pub fn cs_and(enum_nonmatch_f: EnumNonMatchCollapsedFunc,
cx: &mut ExtCtxt, span: Span,
substructure: &Substructure) -> Gc<Expr> {
cs_binop(ast::BiAnd, cx.expr_bool(span, true),
args: vec!(Ptr(box Literal(args), Borrowed(None, MutMutable))),
ret_ty: nil_ty(),
attributes: attrs,
- const_nonmatching: false,
combine_substructure: combine_substructure(|a, b, c| {
hash_substructure(a, b, c)
})
true)),
// #[inline] liable to cause code-bloat
attributes: attrs.clone(),
- const_nonmatching: false,
combine_substructure: combine_substructure(|c, s, sub| {
cs_from("i64", c, s, sub)
}),
true)),
// #[inline] liable to cause code-bloat
attributes: attrs,
- const_nonmatching: false,
combine_substructure: combine_substructure(|c, s, sub| {
cs_from("u64", c, s, sub)
}),
),
ret_ty: Self,
attributes: Vec::new(),
- const_nonmatching: false,
combine_substructure: combine_substructure(|a, b, c| {
rand_substructure(a, b, c)
})
args: vec!(fmtr),
ret_ty: Literal(Path::new(vec!("std", "fmt", "Result"))),
attributes: Vec::new(),
- const_nonmatching: false,
combine_substructure: combine_substructure(|a, b, c| {
show_substructure(a, b, c)
})
let name = match *substr.fields {
Struct(_) => substr.type_ident,
EnumMatching(_, v, _) => v.node.name,
-
- EnumNonMatching(..) | StaticStruct(..) | StaticEnum(..) => {
+ EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => {
cx.span_bug(span, "nonsensical .fields in `#[deriving(Show)]`")
}
};
args: Vec::new(),
ret_ty: Self,
attributes: attrs.clone(),
- const_nonmatching: false,
combine_substructure: combine_substructure(|a, b, c| {
zero_substructure(a, b, c)
})
args: Vec::new(),
ret_ty: Literal(Path::new(vec!("bool"))),
attributes: attrs,
- const_nonmatching: false,
combine_substructure: combine_substructure(|cx, span, substr| {
cs_and(|cx, span, _, _| cx.span_bug(span,
"Non-matching enum \
// expr_mac should really be expr_ext or something; it's the
// entry-point for all syntax extensions.
ExprMac(ref mac) => {
- match (*mac).node {
- // it would almost certainly be cleaner to pass the whole
- // macro invocation in, rather than pulling it apart and
- // marking the tts and the ctxt separately. This also goes
- // for the other three macro invocation chunks of code
- // in this file.
- // Token-tree macros:
- MacInvocTT(ref pth, ref tts, _) => {
- if pth.segments.len() > 1u {
- fld.cx.span_err(pth.span,
- "expected macro name without module \
- separators");
- // let compilation continue
- return DummyResult::raw_expr(e.span);
- }
- let extname = pth.segments.get(0).identifier;
- let extnamestr = token::get_ident(extname);
- let marked_after = match fld.extsbox.find(&extname.name) {
- None => {
- fld.cx.span_err(
- pth.span,
- format!("macro undefined: '{}!'",
- extnamestr.get()).as_slice());
-
- // let compilation continue
- return DummyResult::raw_expr(e.span);
- }
- Some(&NormalTT(ref expandfun, exp_span)) => {
- fld.cx.bt_push(ExpnInfo {
- call_site: e.span,
- callee: NameAndSpan {
- name: extnamestr.get().to_string(),
- format: MacroBang,
- span: exp_span,
- },
- });
- let fm = fresh_mark();
- // mark before:
- let marked_before = mark_tts(tts.as_slice(), fm);
-
- // The span that we pass to the expanders we want to
- // be the root of the call stack. That's the most
- // relevant span and it's the actual invocation of
- // the macro.
- let mac_span = original_span(fld.cx);
-
- let expanded = match expandfun.expand(fld.cx,
- mac_span.call_site,
- marked_before.as_slice()).make_expr() {
- Some(e) => e,
- None => {
- fld.cx.span_err(
- pth.span,
- format!("non-expression macro in expression position: {}",
- extnamestr.get().as_slice()
- ).as_slice());
- return DummyResult::raw_expr(e.span);
- }
- };
+ let expanded_expr = match expand_mac_invoc(mac,&e.span,
+ |r|{r.make_expr()},
+ |expr,fm|{mark_expr(expr,fm)},
+ fld) {
+ Some(expr) => expr,
+ None => {
+ return DummyResult::raw_expr(e.span);
+ }
+ };
- // mark after:
- mark_expr(expanded,fm)
- }
- _ => {
- fld.cx.span_err(
- pth.span,
- format!("'{}' is not a tt-style macro",
- extnamestr.get()).as_slice());
- return DummyResult::raw_expr(e.span);
- }
- };
+ // Keep going, outside-in.
+ //
+ // FIXME(pcwalton): Is it necessary to clone the
+ // node here?
+ let fully_expanded =
+ fld.fold_expr(expanded_expr).node.clone();
+ fld.cx.bt_pop();
- // Keep going, outside-in.
- //
- // FIXME(pcwalton): Is it necessary to clone the
- // node here?
- let fully_expanded =
- fld.fold_expr(marked_after).node.clone();
- fld.cx.bt_pop();
-
- box(GC) ast::Expr {
- id: ast::DUMMY_NODE_ID,
- node: fully_expanded,
- span: e.span,
- }
- }
+ box(GC) ast::Expr {
+ id: ast::DUMMY_NODE_ID,
+ node: fully_expanded,
+ span: e.span,
}
}
}
}
+/// Expand a (not-ident-style) macro invocation. Returns the result
+/// of expansion and the mark which must be applied to the result.
+/// Our current interface doesn't allow us to apply the mark to the
+/// result until after calling make_expr, make_items, etc.
+fn expand_mac_invoc<T>(mac: &ast::Mac, span: &codemap::Span,
+ parse_thunk: |Box<MacResult>|->Option<T>,
+ mark_thunk: |T,Mrk|->T,
+ fld: &mut MacroExpander)
+ -> Option<T> {
+ match (*mac).node {
+ // it would almost certainly be cleaner to pass the whole
+ // macro invocation in, rather than pulling it apart and
+ // marking the tts and the ctxt separately. This also goes
+ // for the other three macro invocation chunks of code
+ // in this file.
+ // Token-tree macros:
+ MacInvocTT(ref pth, ref tts, _) => {
+ if pth.segments.len() > 1u {
+ fld.cx.span_err(pth.span,
+ "expected macro name without module \
+ separators");
+ // let compilation continue
+ return None;
+ }
+ let extname = pth.segments.get(0).identifier;
+ let extnamestr = token::get_ident(extname);
+ match fld.extsbox.find(&extname.name) {
+ None => {
+ fld.cx.span_err(
+ pth.span,
+ format!("macro undefined: '{}!'",
+ extnamestr.get()).as_slice());
+
+ // let compilation continue
+ None
+ }
+ Some(&NormalTT(ref expandfun, exp_span)) => {
+ fld.cx.bt_push(ExpnInfo {
+ call_site: *span,
+ callee: NameAndSpan {
+ name: extnamestr.get().to_string(),
+ format: MacroBang,
+ span: exp_span,
+ },
+ });
+ let fm = fresh_mark();
+ let marked_before = mark_tts(tts.as_slice(), fm);
+
+ // The span that we pass to the expanders we want to
+ // be the root of the call stack. That's the most
+ // relevant span and it's the actual invocation of
+ // the macro.
+ let mac_span = original_span(fld.cx);
+
+ let expanded = expandfun.expand(fld.cx,
+ mac_span.call_site,
+ marked_before.as_slice());
+ let parsed = match parse_thunk(expanded) {
+ Some(e) => e,
+ None => {
+ fld.cx.span_err(
+ pth.span,
+ format!("non-expression macro in expression position: {}",
+ extnamestr.get().as_slice()
+ ).as_slice());
+ return None;
+ }
+ };
+ Some(mark_thunk(parsed,fm))
+ }
+ _ => {
+ fld.cx.span_err(
+ pth.span,
+ format!("'{}' is not a tt-style macro",
+ extnamestr.get()).as_slice());
+ None
+ }
+ }
+ }
+ }
+}
+
/// Rename loop label and expand its loop body
///
/// The renaming procedure for loop is different in the sense that the loop
// create issue to recommend refactoring here?
fld.extsbox.insert(intern(name.as_slice()), ext);
if attr::contains_name(it.attrs.as_slice(), "macro_export") {
- SmallVector::one(it)
- } else {
- SmallVector::zero()
+ fld.cx.push_exported_macro(it.span);
}
+ SmallVector::zero()
}
None => {
match expanded.make_items() {
Some(items) => {
items.move_iter()
- .flat_map(|i| mark_item(i, fm).move_iter())
+ .map(|i| mark_item(i, fm))
.flat_map(|i| fld.fold_item(i).move_iter())
.collect()
}
return items;
}
-// expand a stmt
+/// Expand a stmt
+//
+// I don't understand why this returns a vector... it looks like we're
+// half done adding machinery to allow macros to expand into multiple statements.
fn expand_stmt(s: &Stmt, fld: &mut MacroExpander) -> SmallVector<Gc<Stmt>> {
- // why the copying here and not in expand_expr?
- // looks like classic changed-in-only-one-place
- let (pth, tts, semi) = match s.node {
- StmtMac(ref mac, semi) => {
- match mac.node {
- MacInvocTT(ref pth, ref tts, _) => {
- (pth, (*tts).clone(), semi)
- }
- }
- }
+ let (mac, semi) = match s.node {
+ StmtMac(ref mac, semi) => (mac, semi),
_ => return expand_non_macro_stmt(s, fld)
};
- if pth.segments.len() > 1u {
- fld.cx.span_err(pth.span, "expected macro name without module separators");
- return SmallVector::zero();
- }
- let extname = pth.segments.get(0).identifier;
- let extnamestr = token::get_ident(extname);
- let marked_after = match fld.extsbox.find(&extname.name) {
+ let expanded_stmt = match expand_mac_invoc(mac,&s.span,
+ |r|{r.make_stmt()},
+ |sts,mrk|{mark_stmt(sts,mrk)},
+ fld) {
+ Some(stmt) => stmt,
None => {
- fld.cx.span_err(pth.span,
- format!("macro undefined: '{}!'",
- extnamestr).as_slice());
- return SmallVector::zero();
- }
-
- Some(&NormalTT(ref expandfun, exp_span)) => {
- fld.cx.bt_push(ExpnInfo {
- call_site: s.span,
- callee: NameAndSpan {
- name: extnamestr.get().to_string(),
- format: MacroBang,
- span: exp_span,
- }
- });
- let fm = fresh_mark();
- // mark before expansion:
- let marked_tts = mark_tts(tts.as_slice(), fm);
-
- // See the comment in expand_expr for why we want the original span,
- // not the current mac.span.
- let mac_span = original_span(fld.cx);
-
- let expanded = match expandfun.expand(fld.cx,
- mac_span.call_site,
- marked_tts.as_slice()).make_stmt() {
- Some(stmt) => stmt,
- None => {
- fld.cx.span_err(pth.span,
- format!("non-statement macro in statement position: {}",
- extnamestr).as_slice());
- return SmallVector::zero();
- }
- };
-
- mark_stmt(&*expanded,fm)
- }
-
- _ => {
- fld.cx.span_err(pth.span, format!("'{}' is not a tt-style macro",
- extnamestr).as_slice());
return SmallVector::zero();
}
};
// Keep going, outside-in.
- let fully_expanded = fld.fold_stmt(&*marked_after);
- if fully_expanded.is_empty() {
- fld.cx.span_err(pth.span, "macro didn't expand to a statement");
- return SmallVector::zero();
- }
+ let fully_expanded = fld.fold_stmt(&*expanded_stmt);
fld.cx.bt_pop();
let fully_expanded: SmallVector<Gc<Stmt>> = fully_expanded.move_iter()
.map(|s| box(GC) Spanned { span: s.span, node: s.node.clone() })
_ => visit::walk_pat(self, pattern, ())
}
}
-
}
/// find the PatIdent paths in a pattern
ctxt: mtwt::apply_renames(self.renames, id.ctxt),
}
}
+ fn fold_mac(&mut self, macro: &ast::Mac) -> ast::Mac {
+ fold::fold_mac(macro, self)
+ }
}
/// A tree-folder that applies every rename in its list to
_ => noop_fold_pat(pat, self)
}
}
+ fn fold_mac(&mut self, macro: &ast::Mac) -> ast::Mac {
+ fold::fold_mac(macro, self)
+ }
}
// expand a method
-fn expand_method(m: &ast::Method, fld: &mut MacroExpander) -> Gc<ast::Method> {
+fn expand_method(m: &ast::Method, fld: &mut MacroExpander) -> SmallVector<Gc<ast::Method>> {
let id = fld.new_id(m.id);
- let (rewritten_fn_decl, rewritten_body)
- = expand_and_rename_fn_decl_and_block(m.decl,m.body,fld);
-
- // all of the other standard stuff:
- box(GC) ast::Method {
- id: id,
- ident: fld.fold_ident(m.ident),
- attrs: m.attrs.iter().map(|a| fld.fold_attribute(*a)).collect(),
- generics: fold_generics(&m.generics, fld),
- explicit_self: fld.fold_explicit_self(&m.explicit_self),
- fn_style: m.fn_style,
- decl: rewritten_fn_decl,
- body: rewritten_body,
- span: fld.new_span(m.span),
- vis: m.vis
+ match m.node {
+ ast::MethDecl(ident, ref generics, ref explicit_self, fn_style, decl, body, vis) => {
+ let (rewritten_fn_decl, rewritten_body)
+ = expand_and_rename_fn_decl_and_block(decl,body,fld);
+ SmallVector::one(box(GC) ast::Method {
+ attrs: m.attrs.iter().map(|a| fld.fold_attribute(*a)).collect(),
+ id: id,
+ span: fld.new_span(m.span),
+ node: ast::MethDecl(fld.fold_ident(ident),
+ fold_generics(generics, fld),
+ fld.fold_explicit_self(explicit_self),
+ fn_style,
+ rewritten_fn_decl,
+ rewritten_body,
+ vis)
+ })
+ },
+ ast::MethMac(ref mac) => {
+ let maybe_new_methods =
+ expand_mac_invoc(mac, &m.span,
+ |r|{r.make_methods()},
+ |meths,mark|{
+ meths.move_iter().map(|m|{mark_method(m,mark)})
+ .collect()},
+ fld);
+
+ let new_methods = match maybe_new_methods {
+ Some(methods) => methods,
+ None => SmallVector::zero()
+ };
+
+ // expand again if necessary
+ new_methods.move_iter().flat_map(|m| fld.fold_method(m).move_iter()).collect()
+ }
}
}
expand_arm(arm, self)
}
- fn fold_method(&mut self, method: Gc<ast::Method>) -> Gc<ast::Method> {
+ fn fold_method(&mut self, method: Gc<ast::Method>) -> SmallVector<Gc<ast::Method>> {
expand_method(method, self)
}
pub fn expand_crate(parse_sess: &parse::ParseSess,
cfg: ExpansionConfig,
+ // these are the macros being imported to this crate:
macros: Vec<ExportedMacros>,
user_exts: Vec<NamedSyntaxExtension>,
c: Crate) -> Crate {
expander.extsbox.insert(name, extension);
}
- let ret = expander.fold_crate(c);
+ let mut ret = expander.fold_crate(c);
+ ret.exported_macros = expander.cx.exported_macros.clone();
parse_sess.span_diagnostic.handler().abort_if_errors();
return ret;
}
// apply a given mark to the given stmt. Used following the expansion of a macro.
fn mark_stmt(expr: &ast::Stmt, m: Mrk) -> Gc<ast::Stmt> {
Marker{mark:m}.fold_stmt(expr)
- .expect_one("marking a stmt didn't return a stmt")
+ .expect_one("marking a stmt didn't return exactly one stmt")
}
// apply a given mark to the given item. Used following the expansion of a macro.
-fn mark_item(expr: Gc<ast::Item>, m: Mrk) -> SmallVector<Gc<ast::Item>> {
+fn mark_item(expr: Gc<ast::Item>, m: Mrk) -> Gc<ast::Item> {
Marker{mark:m}.fold_item(expr)
+ .expect_one("marking an item didn't return exactly one item")
+}
+
+// apply a given mark to the given item. Used following the expansion of a macro.
+fn mark_method(expr: Gc<ast::Method>, m: Mrk) -> Gc<ast::Method> {
+ Marker{mark:m}.fold_method(expr)
+ .expect_one("marking an item didn't return exactly one method")
}
fn original_span(cx: &ExtCtxt) -> Gc<codemap::ExpnInfo> {
return einfo;
}
+/// Check that there are no macro invocations left in the AST:
+pub fn check_for_macros(sess: &parse::ParseSess, krate: &ast::Crate) {
+ visit::walk_crate(&mut MacroExterminator{sess:sess}, krate, ());
+}
+
+/// A visitor that ensures that no macro invocations remain in an AST.
+struct MacroExterminator<'a>{
+ sess: &'a parse::ParseSess
+}
+
+impl<'a> visit::Visitor<()> for MacroExterminator<'a> {
+ fn visit_mac(&mut self, macro: &ast::Mac, _:()) {
+ self.sess.span_diagnostic.span_bug(macro.span,
+ "macro exterminator: expected AST \
+ with no macro invocations");
+ }
+}
+
+
#[cfg(test)]
mod test {
use super::{pattern_bindings, expand_crate, contains_macro_escape};
}
// macro_rules in method position. Sadly, unimplemented.
- #[ignore] #[test] fn macro_in_method_posn(){
+ #[test] fn macro_in_method_posn(){
expand_crate_str(
- "macro_rules! my_method (() => fn thirteen(&self) -> int {13})
+ "macro_rules! my_method (() => (fn thirteen(&self) -> int {13}))
struct A;
impl A{ my_method!()}
fn f(){A.thirteen;}".to_string());
use ast;
use codemap::{Span, Spanned, DUMMY_SP};
use ext::base::{ExtCtxt, MacResult, MacroDef};
-use ext::base::{NormalTT, MacroExpander};
+use ext::base::{NormalTT, TTMacroExpander};
use ext::base;
use ext::tt::macro_parser::{Success, Error, Failure};
use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
impl<'a> ParserAnyMacro<'a> {
/// Make sure we don't have any tokens left to parse, so we don't
/// silently drop anything. `allow_semi` is so that "optional"
- /// semilons at the end of normal expressions aren't complained
+ /// semicolons at the end of normal expressions aren't complained
/// about e.g. the semicolon in `macro_rules! kapow( () => {
/// fail!(); } )` doesn't get picked up by .parse_expr(), but it's
/// allowed to be there.
let mut ret = SmallVector::zero();
loop {
let mut parser = self.parser.borrow_mut();
+ // so... do outer attributes attached to the macro invocation
+ // just disappear? This question applies to make_methods, as
+ // well.
match parser.parse_item_with_outer_attributes() {
Some(item) => ret.push(item),
None => break
self.ensure_complete_parse(false);
Some(ret)
}
+
+ fn make_methods(&self) -> Option<SmallVector<Gc<ast::Method>>> {
+ let mut ret = SmallVector::zero();
+ loop {
+ let mut parser = self.parser.borrow_mut();
+ match parser.token {
+ EOF => break,
+ _ => ret.push(parser.parse_method(None))
+ }
+ }
+ self.ensure_complete_parse(false);
+ Some(ret)
+ }
+
fn make_stmt(&self) -> Option<Gc<ast::Stmt>> {
let attrs = self.parser.borrow_mut().parse_outer_attributes();
let ret = self.parser.borrow_mut().parse_stmt(attrs);
rhses: Vec<Rc<NamedMatch>>,
}
-impl MacroExpander for MacroRulesMacroExpander {
+impl TTMacroExpander for MacroRulesMacroExpander {
fn expand(&self,
cx: &mut ExtCtxt,
sp: Span,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+//! A Folder represents an AST->AST fold; it accepts an AST piece,
+//! and returns a piece of the same type. So, for instance, macro
+//! expansion is a Folder that walks over an AST and produces another
+//! AST.
+//!
+//! Note: using a Folder (other than the MacroExpander Folder) on
+//! an AST before macro expansion is probably a bad idea. For instance,
+//! a folder renaming item names in a module will miss all of those
+//! that are created by the expansion of a macro.
+
use ast::*;
use ast;
use ast_util;
noop_fold_type_method(m, self)
}
- fn fold_method(&mut self, m: Gc<Method>) -> Gc<Method> {
+ fn fold_method(&mut self, m: Gc<Method>) -> SmallVector<Gc<Method>> {
noop_fold_method(&*m, self)
}
}
}
- fn fold_mac(&mut self, macro: &Mac) -> Mac {
- Spanned {
- node: match macro.node {
- MacInvocTT(ref p, ref tts, ctxt) => {
- MacInvocTT(self.fold_path(p),
- fold_tts(tts.as_slice(), self),
- ctxt)
- }
- },
- span: self.new_span(macro.span)
- }
+ fn fold_mac(&mut self, _macro: &Mac) -> Mac {
+ fail!("fold_mac disabled by default");
+ // NB: see note about macros above.
+ // if you really want a folder that
+ // works on macros, use this
+ // definition in your trait impl:
+ // fold::fold_mac(_macro, self)
}
fn map_exprs(&self, f: |Gc<Expr>| -> Gc<Expr>,
}
+
+pub fn fold_mac<T: Folder>(macro: &Mac, fld: &mut T) -> Mac {
+ Spanned {
+ node: match macro.node {
+ MacInvocTT(ref p, ref tts, ctxt) => {
+ MacInvocTT(fld.fold_path(p),
+ fold_tts(tts.as_slice(), fld),
+ ctxt)
+ }
+ },
+ span: fld.new_span(macro.span)
+ }
+}
+
/* some little folds that probably aren't useful to have in Folder itself*/
//used in noop_fold_item and noop_fold_crate and noop_fold_crate_directive
match *nt {
token::NtItem(item) =>
token::NtItem(fld.fold_item(item)
+ // this is probably okay, because the only folds likely
+ // to peek inside interpolated nodes will be renamings/markings,
+ // which map single items to single items
.expect_one("expected fold to produce exactly one item")),
token::NtBlock(block) => token::NtBlock(fld.fold_block(block)),
token::NtStmt(stmt) =>
token::NtStmt(fld.fold_stmt(stmt)
+ // this is probably okay, because the only folds likely
+ // to peek inside interpolated nodes will be renamings/markings,
+ // which map single items to single items
.expect_one("expected fold to produce exactly one statement")),
token::NtPat(pat) => token::NtPat(fld.fold_pat(pat)),
token::NtExpr(expr) => token::NtExpr(fld.fold_expr(expr)),
ItemImpl(fold_generics(generics, folder),
ifce.as_ref().map(|p| fold_trait_ref(p, folder)),
folder.fold_ty(ty),
- methods.iter().map(|x| folder.fold_method(*x)).collect()
+ methods.iter().flat_map(|x| folder.fold_method(*x).move_iter()).collect()
)
}
ItemTrait(ref generics, ref unbound, ref traits, ref methods) => {
- let methods = methods.iter().map(|method| {
- match *method {
- Required(ref m) => Required(folder.fold_type_method(m)),
- Provided(method) => Provided(folder.fold_method(method))
- }
+ let methods = methods.iter().flat_map(|method| {
+ let r = match *method {
+ Required(ref m) =>
+ SmallVector::one(Required(folder.fold_type_method(m))).move_iter(),
+ Provided(method) => {
+ // the awkward collect/iter idiom here is because
+ // even though an iter and a map satisfy the same trait bound,
+ // they're not actually the same type, so the method arms
+ // don't unify.
+ let methods : SmallVector<ast::TraitMethod> =
+ folder.fold_method(method).move_iter()
+ .map(|m| Provided(m)).collect();
+ methods.move_iter()
+ }
+ };
+ r
}).collect();
ItemTrait(fold_generics(generics, folder),
unbound.clone(),
attrs: c.attrs.iter().map(|x| folder.fold_attribute(*x)).collect(),
config: c.config.iter().map(|x| fold_meta_item_(*x, folder)).collect(),
span: folder.new_span(c.span),
+ exported_macros: c.exported_macros.iter().map(|sp| folder.new_span(*sp)).collect(),
}
}
}
}
-pub fn noop_fold_method<T: Folder>(m: &Method, folder: &mut T) -> Gc<Method> {
+// Default fold over a method.
+// Invariant: produces exactly one method.
+pub fn noop_fold_method<T: Folder>(m: &Method, folder: &mut T) -> SmallVector<Gc<Method>> {
let id = folder.new_id(m.id); // Needs to be first, for ast_map.
- box(GC) Method {
- id: id,
- ident: folder.fold_ident(m.ident),
+ SmallVector::one(box(GC) Method {
attrs: m.attrs.iter().map(|a| folder.fold_attribute(*a)).collect(),
- generics: fold_generics(&m.generics, folder),
- explicit_self: folder.fold_explicit_self(&m.explicit_self),
- fn_style: m.fn_style,
- decl: folder.fold_fn_decl(&*m.decl),
- body: folder.fold_block(m.body),
+ id: id,
span: folder.new_span(m.span),
- vis: m.vis
- }
+ node: match m.node {
+ MethDecl(ident, ref generics, ref explicit_self, fn_style, decl, body, vis) => {
+ MethDecl(folder.fold_ident(ident),
+ fold_generics(generics, folder),
+ folder.fold_explicit_self(explicit_self),
+ fn_style,
+ folder.fold_fn_decl(&*decl),
+ folder.fold_block(body),
+ vis)
+ },
+ MethMac(ref mac) => MethMac(folder.fold_mac(mac)),
+ }
+ })
}
pub fn noop_fold_pat<T: Folder>(p: Gc<Pat>, folder: &mut T) -> Gc<Pat> {
use util::parser_testing::{string_to_crate, matches_codepattern};
use parse::token;
use print::pprust;
+ use fold;
use super::*;
// this version doesn't care about getting comments or docstrings in.
fn fold_ident(&mut self, _: ast::Ident) -> ast::Ident {
token::str_to_ident("zz")
}
+ fn fold_mac(&mut self, macro: &ast::Mac) -> ast::Mac {
+ fold::fold_mac(macro, self)
+ }
}
// maybe add to expand.rs...
#![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/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(macro_rules, globs, managed_boxes, default_type_params, phase)]
#![feature(quote, unsafe_destructor)]
self.expect(&token::LBRACKET);
let meta_item = self.parse_meta_item();
+ let hi = self.span.hi;
self.expect(&token::RBRACKET);
- let hi = self.span.hi;
(mk_sp(lo, hi), meta_item, style)
}
_ => {
p.parse_inner_attrs_and_block();
let attrs = attrs.append(inner_attrs.as_slice());
Provided(box(GC) ast::Method {
- ident: ident,
attrs: attrs,
- generics: generics,
- explicit_self: explicit_self,
- fn_style: style,
- decl: d,
- body: body,
id: ast::DUMMY_NODE_ID,
span: mk_sp(lo, hi),
- vis: vis,
+ node: ast::MethDecl(ident, generics, explicit_self, style, d, body, vis)
})
}
} else if is_ident(&self.token)
&& !token::is_any_keyword(&self.token)
&& self.look_ahead(1, |t| *t == token::NOT) {
+ // it's a macro invocation:
check_expected_item(self, !item_attrs.is_empty());
}
/// Parse a method in a trait impl, starting with `attrs` attributes.
- fn parse_method(&mut self,
+ pub fn parse_method(&mut self,
already_parsed_attrs: Option<Vec<Attribute>>) -> Gc<Method> {
let next_attrs = self.parse_outer_attributes();
let attrs = match already_parsed_attrs {
let lo = self.span.lo;
- let visa = self.parse_visibility();
- let fn_style = self.parse_fn_style();
- let ident = self.parse_ident();
- let generics = self.parse_generics();
- let (explicit_self, decl) = self.parse_fn_decl_with_self(|p| {
- p.parse_arg()
- });
+ // code copied from parse_macro_use_or_failure... abstraction!
+ let (method_, hi, new_attrs) = {
+ if !token::is_any_keyword(&self.token)
+ && self.look_ahead(1, |t| *t == token::NOT)
+ && (self.look_ahead(2, |t| *t == token::LPAREN)
+ || self.look_ahead(2, |t| *t == token::LBRACE)) {
+ // method macro.
+ let pth = self.parse_path(NoTypesAllowed).path;
+ self.expect(&token::NOT);
- let (inner_attrs, body) = self.parse_inner_attrs_and_block();
- let hi = body.span.hi;
- let attrs = attrs.append(inner_attrs.as_slice());
+ // eat a matched-delimiter token tree:
+ let tts = match token::close_delimiter_for(&self.token) {
+ Some(ket) => {
+ self.bump();
+ self.parse_seq_to_end(&ket,
+ seq_sep_none(),
+ |p| p.parse_token_tree())
+ }
+ None => self.fatal("expected open delimiter")
+ };
+ let m_ = ast::MacInvocTT(pth, tts, EMPTY_CTXT);
+ let m: ast::Mac = codemap::Spanned { node: m_,
+ span: mk_sp(self.span.lo,
+ self.span.hi) };
+ (ast::MethMac(m), self.span.hi, attrs)
+ } else {
+ let visa = self.parse_visibility();
+ let fn_style = self.parse_fn_style();
+ let ident = self.parse_ident();
+ let generics = self.parse_generics();
+ let (explicit_self, decl) = self.parse_fn_decl_with_self(|p| {
+ p.parse_arg()
+ });
+ let (inner_attrs, body) = self.parse_inner_attrs_and_block();
+ let new_attrs = attrs.append(inner_attrs.as_slice());
+ (ast::MethDecl(ident, generics, explicit_self, fn_style, decl, body, visa),
+ body.span.hi, new_attrs)
+ }
+ };
box(GC) ast::Method {
- ident: ident,
- attrs: attrs,
- generics: generics,
- explicit_self: explicit_self,
- fn_style: fn_style,
- decl: decl,
- body: body,
+ attrs: new_attrs,
id: ast::DUMMY_NODE_ID,
span: mk_sp(lo, hi),
- vis: visa,
+ node: method_,
}
}
module: m,
attrs: inner,
config: self.cfg.clone(),
- span: mk_sp(lo, self.span.lo)
+ span: mk_sp(lo, self.span.lo),
+ exported_macros: Vec::new(),
}
}
to_string(|s| s.print_arg(arg))
}
+pub fn mac_to_string(arg: &ast::Mac) -> String {
+ to_string(|s| s.print_mac(arg))
+}
+
pub fn visibility_qualified(vis: ast::Visibility, s: &str) -> String {
match vis {
ast::Public => format!("pub {}", s),
match self.s.last_token() { pp::End => true, _ => false }
}
+ // is this the beginning of a line?
pub fn is_bol(&mut self) -> bool {
self.s.last_token().is_eof() || self.s.last_token().is_hardbreak_tok()
}
}
}
+ /// Pretty-print an item
pub fn print_item(&mut self, item: &ast::Item) -> IoResult<()> {
try!(self.hardbreak_if_not_bol());
try!(self.maybe_print_comment(item.span.lo));
try!(self.hardbreak_if_not_bol());
try!(self.maybe_print_comment(meth.span.lo));
try!(self.print_outer_attributes(meth.attrs.as_slice()));
- try!(self.print_fn(&*meth.decl, Some(meth.fn_style), abi::Rust,
- meth.ident, &meth.generics, Some(meth.explicit_self.node),
- meth.vis));
- try!(word(&mut self.s, " "));
- self.print_block_with_attrs(&*meth.body, meth.attrs.as_slice())
+ match meth.node {
+ ast::MethDecl(ident, ref generics, ref explicit_self, fn_style, decl, body, vis) => {
+ try!(self.print_fn(&*decl, Some(fn_style), abi::Rust,
+ ident, generics, Some(explicit_self.node),
+ vis));
+ try!(word(&mut self.s, " "));
+ self.print_block_with_attrs(&*body, meth.attrs.as_slice())
+ },
+ ast::MethMac(codemap::Spanned { node: ast::MacInvocTT(ref pth, ref tts, _),
+ ..}) => {
+ // code copied from ItemMac:
+ try!(self.print_path(pth, false));
+ try!(word(&mut self.s, "! "));
+ try!(self.cbox(indent_unit));
+ try!(self.popen());
+ try!(self.print_tts(tts.as_slice()));
+ try!(self.pclose());
+ self.end()
+ }
+ }
}
pub fn print_outer_attributes(&mut self,
//! execute before AST node B, then A is visited first. The borrow checker in
//! particular relies on this property.
//!
+//! Note: walking an AST before macro expansion is probably a bad idea. For
+//! instance, a walker looking for item names in a module will miss all of
+//! those that are created by the expansion of a macro.
+
use abi::Abi;
use ast::*;
use ast;
fn visit_explicit_self(&mut self, es: &ExplicitSelf, e: E) {
walk_explicit_self(self, es, e)
}
- fn visit_mac(&mut self, macro: &Mac, e: E) {
- walk_mac(self, macro, e)
+ fn visit_mac(&mut self, _macro: &Mac, _e: E) {
+ fail!("visit_mac disabled by default");
+ // NB: see note about macros above.
+ // if you really want a visitor that
+ // works on macros, use this
+ // definition in your trait impl:
+ // visit::walk_mac(self, _macro, _e)
}
fn visit_path(&mut self, path: &Path, _id: ast::NodeId, e: E) {
walk_path(self, path, e)
pub fn walk_method_helper<E: Clone, V: Visitor<E>>(visitor: &mut V,
method: &Method,
env: E) {
- visitor.visit_ident(method.span, method.ident, env.clone());
- visitor.visit_fn(&FkMethod(method.ident, &method.generics, method),
- &*method.decl,
- &*method.body,
- method.span,
- method.id,
- env.clone());
- for attr in method.attrs.iter() {
- visitor.visit_attribute(attr, env.clone());
+ match method.node {
+ MethDecl(ident, ref generics, _, _, decl, body, _) => {
+ visitor.visit_ident(method.span, ident, env.clone());
+ visitor.visit_fn(&FkMethod(ident, generics, method),
+ decl,
+ body,
+ method.span,
+ method.id,
+ env.clone());
+ for attr in method.attrs.iter() {
+ visitor.visit_attribute(attr, env.clone());
+ }
+
+ },
+ MethMac(ref mac) => visitor.visit_mac(mac, env.clone())
}
}
}
FkMethod(_, generics, method) => {
visitor.visit_generics(generics, env.clone());
-
- visitor.visit_explicit_self(&method.explicit_self, env.clone());
+ match method.node {
+ MethDecl(_, _, ref explicit_self, _, _, _, _) =>
+ visitor.visit_explicit_self(explicit_self, env.clone()),
+ MethMac(ref mac) =>
+ visitor.visit_mac(mac, env.clone())
+ }
}
FkFnBlock(..) => {}
}
#![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/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, phase)]
#![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/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(asm, macro_rules, phase)]
#![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/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(phase)]
//! provide for basic string-related manipulations. This crate does not
//! (yet) aim to provide a full set of Unicode tables.
-#![crate_id = "unicode#0.11.0"]
#![crate_name = "unicode"]
#![experimental]
#![license = "MIT/ASL2"]
#![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/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(default_type_params)]
#![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/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(default_type_params)]
--- /dev/null
+// Copyright 2013-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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+#![feature(plugin_registrar)]
+
+extern crate rustc;
+
+use rustc::plugin::Registry;
+
+#[plugin_registrar]
+pub fn plugin_registrar(_: &mut Registry) {}
--- /dev/null
+// Copyright 2013-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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:rlib_crate_test.rs
+// ignore-stage1
+// ignore-tidy-linelength
+// ignore-android
+
+#![feature(phase)]
+#[phase(plugin)] extern crate rlib_crate_test;
+//~^ ERROR: plugin crate `rlib_crate_test` only found in rlib format, but must be available in dylib format
+
+fn main() {}
trait foo6 { //~ ERROR trait `foo6` should have a camel case name such as `Foo6`
}
+#[repr(C)]
+struct foo7 {
+ bar: int,
+}
+
fn main() { }
/// *wow*
pub trait Doge { }
+
+ pub struct Foo { x: int, y: uint }
+
+ pub fn prawns((a, b): (int, uint), Foo { x, y }: Foo) { }
}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags:--crate-name crate-name-attr-used -F unused-attribute
+
+#![crate_name = "test"]
+
+fn main() {}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(macro_rules)]
+
+struct A;
+
+macro_rules! make_thirteen_method {() => (pub fn thirteen(&self)->int {13})}
+impl A { make_thirteen_method!() }
+
+fn main() {
+ assert_eq!(A.thirteen(),13);
+}
+
+
+