This is accomplished by rewriting static expressions into equivalent patterns.
This way, patterns referencing static variables can both participate
in exhaustiveness analysis as well as be compiled down into the appropriate
branch of the decision trees that match expressions are codegened to.
Fixes #6533.
Fixes #13626.
Fixes #13731.
Fixes #14576.
Fixes #15393.
guide-tasks guide-container guide-pointers guide-testing \
guide-runtime complement-bugreport \
complement-lang-faq complement-design-faq complement-project-faq rust \
- rustdoc guide-unsafe
+ rustdoc guide-unsafe guide-strings
PDF_DOCS := tutorial rust
% The Strings Guide
-# Strings
-
Strings are an important concept to master in any programming language. If you
come from a managed language background, you may be surprised at the complexity
of string handling in a systems programming language. Efficient access and
Rust has two main types of strings: `&str` and `String`.
-## &str
+# &str
The first kind is a `&str`. This is pronounced a 'string slice.' String literals
are of the type `&str`:
means that they're a 'view' into an already-allocated string, such as a
`&'static str` or a `String`.
-## String
+# String
A `String` is a heap-allocated string. This string is growable, and is also
guaranteed to be UTF-8.
let stack_str: &str = str::from_utf8(x).unwrap();
```
-## Best Practices
+# Best Practices
-### `String` vs. `&str`
+## `String` vs. `&str`
In general, you should prefer `String` when you need ownership, and `&str` when
you just need to borrow a string. This is very similar to using `Vec<T>` vs. `&[T]`,
either kind of string into `foo` by using `.as_slice()` on any `String` you
need to pass in, so the `&str` version is more flexible.
-### Comparisons
+## Comparisons
To compare a String to a constant string, prefer `as_slice()`...
Converting a `String` to a `&str` is cheap, but converting the `&str` to a
`String` involves an allocation.
-## Other Documentation
+# Other Documentation
* [the `&str` API documentation](/std/str/index.html)
* [the `String` API documentation](std/string/index.html)
# Guides
+* [Strings](guide-strings.html)
* [Pointers](guide-pointers.html)
* [References and Lifetimes](guide-lifetimes.html)
* [Containers and Iterators](guide-container.html)
/// Move the last element to the front of the list.
///
/// If the list is empty, do nothing.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use std::collections::{DList, Deque};
+ ///
+ /// let mut dl = DList::new();
+ /// dl.push_back(1i);
+ /// dl.push_back(2);
+ /// dl.push_back(3);
+ ///
+ /// dl.rotate_forward();
+ ///
+ /// for e in dl.iter() {
+ /// println!("{}", e); // prints 3, then 1, then 2
+ /// }
+ /// ```
#[inline]
pub fn rotate_forward(&mut self) {
self.pop_back_node().map(|tail| {
/// Move the first element to the back of the list.
///
/// If the list is empty, do nothing.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use std::collections::{DList, Deque};
+ ///
+ /// let mut dl = DList::new();
+ /// dl.push_back(1i);
+ /// dl.push_back(2);
+ /// dl.push_back(3);
+ ///
+ /// dl.rotate_backward();
+ ///
+ /// for e in dl.iter() {
+ /// println!("{}", e); // prints 2, then 3, then 1
+ /// }
+ /// ```
#[inline]
pub fn rotate_backward(&mut self) {
self.pop_front_node().map(|head| {
/// Add all elements from `other` to the end of the list
///
/// O(1)
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use std::collections::{DList, Deque};
+ ///
+ /// let mut a = DList::new();
+ /// let mut b = DList::new();
+ /// a.push_back(1i);
+ /// a.push_back(2);
+ /// b.push_back(3i);
+ /// b.push_back(4);
+ ///
+ /// a.append(b);
+ ///
+ /// for e in a.iter() {
+ /// println!("{}", e); // prints 1, then 2, then 3, then 4
+ /// }
+ /// ```
pub fn append(&mut self, mut other: DList<T>) {
match self.list_tail.resolve() {
None => *self = other,
/// Add all elements from `other` to the beginning of the list
///
/// O(1)
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use std::collections::{DList, Deque};
+ ///
+ /// let mut a = DList::new();
+ /// let mut b = DList::new();
+ /// a.push_back(1i);
+ /// a.push_back(2);
+ /// b.push_back(3i);
+ /// b.push_back(4);
+ ///
+ /// a.prepend(b);
+ ///
+ /// for e in a.iter() {
+ /// println!("{}", e); // prints 3, then 4, then 1, then 2
+ /// }
+ /// ```
#[inline]
pub fn prepend(&mut self, mut other: DList<T>) {
mem::swap(self, &mut other);
/// or at the end.
///
/// O(N)
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use std::collections::{DList, Deque};
+ ///
+ /// let mut a: DList<int> = DList::new();
+ /// a.push_back(2i);
+ /// a.push_back(4);
+ /// a.push_back(7);
+ /// a.push_back(8);
+ ///
+ /// // insert 11 before the first odd number in the list
+ /// a.insert_when(11, |&e, _| e % 2 == 1);
+ ///
+ /// for e in a.iter() {
+ /// println!("{}", e); // prints 2, then 4, then 11, then 7, then 8
+ /// }
+ /// ```
pub fn insert_when(&mut self, elt: T, f: |&T, &T| -> bool) {
{
let mut it = self.mut_iter();
#[cfg(test)]
mod tests {
use std::iter::AdditiveIterator;
+ use std::iter::range;
use std::default::Default;
use std::char::Char;
use std::clone::Clone;
assert_eq!(pos, v.len());
}
+ #[test]
+ fn test_chars_decoding() {
+ let mut bytes = [0u8, ..4];
+ for c in range(0u32, 0x110000).filter_map(|c| ::core::char::from_u32(c)) {
+ let len = c.encode_utf8(bytes);
+ let s = ::core::str::from_utf8(bytes.slice_to(len)).unwrap();
+ if Some(c) != s.chars().next() {
+ fail!("character {:x}={} does not decode correctly", c as u32, c);
+ }
+ }
+ }
+
+ #[test]
+ fn test_chars_rev_decoding() {
+ let mut bytes = [0u8, ..4];
+ for c in range(0u32, 0x110000).filter_map(|c| ::core::char::from_u32(c)) {
+ let len = c.encode_utf8(bytes);
+ let s = ::core::str::from_utf8(bytes.slice_to(len)).unwrap();
+ if Some(c) != s.chars().rev().next() {
+ fail!("character {:x}={} does not decode correctly", c as u32, c);
+ }
+ }
+ }
+
#[test]
fn test_iterator_clone() {
let s = "ศไทย中华Việt Nam";
#[cfg(test)]
mod bench {
use test::Bencher;
+ use test::black_box;
use super::*;
+ use std::option::{None, Some};
use std::iter::{Iterator, DoubleEndedIterator};
use std::collections::Collection;
#[bench]
fn char_iterator(b: &mut Bencher) {
let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
- let len = s.char_len();
- b.iter(|| assert_eq!(s.chars().count(), len));
+ b.iter(|| s.chars().count());
+ }
+
+ #[bench]
+ fn char_iterator_for(b: &mut Bencher) {
+ let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
+
+ b.iter(|| {
+ for ch in s.chars() { black_box(ch) }
+ });
}
#[bench]
Mary had a little lamb, Little lamb
Mary had a little lamb, Little lamb
Mary had a little lamb, Little lamb";
- let len = s.char_len();
- b.iter(|| assert_eq!(s.chars().count(), len));
+ b.iter(|| s.chars().count());
}
#[bench]
fn char_iterator_rev(b: &mut Bencher) {
let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
- let len = s.char_len();
- b.iter(|| assert_eq!(s.chars().rev().count(), len));
+ b.iter(|| s.chars().rev().count());
+ }
+
+ #[bench]
+ fn char_iterator_rev_for(b: &mut Bencher) {
+ let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
+
+ b.iter(|| {
+ for ch in s.chars().rev() { black_box(ch) }
+ });
}
#[bench]
Section: Iterators
*/
-/// External iterator for a string's characters.
-/// Use with the `std::iter` module.
+/// Iterator for the char (representing *Unicode Scalar Values*) of a string
+///
+/// Created with the method `.chars()`.
#[deriving(Clone)]
pub struct Chars<'a> {
- /// The slice remaining to be iterated
- string: &'a str,
+ iter: slice::Items<'a, u8>
+}
+
+// Return the initial codepoint accumulator for the first byte.
+// The first byte is special, only want bottom 5 bits for width 2, 4 bits
+// for width 3, and 3 bits for width 4
+macro_rules! utf8_first_byte(
+ ($byte:expr, $width:expr) => (($byte & (0x7F >> $width)) as u32)
+)
+
+// return the value of $ch updated with continuation byte $byte
+macro_rules! utf8_acc_cont_byte(
+ ($ch:expr, $byte:expr) => (($ch << 6) | ($byte & CONT_MASK) as u32)
+)
+
+macro_rules! utf8_is_cont_byte(
+ ($byte:expr) => (($byte & !CONT_MASK) == TAG_CONT_U8)
+)
+
+#[inline]
+fn unwrap_or_0(opt: Option<&u8>) -> u8 {
+ match opt {
+ Some(&byte) => byte,
+ None => 0,
+ }
}
impl<'a> Iterator<char> for Chars<'a> {
#[inline]
fn next(&mut self) -> Option<char> {
- // Decode the next codepoint, then update
- // the slice to be just the remaining part
- if self.string.len() != 0 {
- let CharRange {ch, next} = self.string.char_range_at(0);
- unsafe {
- self.string = raw::slice_unchecked(self.string, next, self.string.len());
+ // Decode UTF-8, using the valid UTF-8 invariant
+ let x = match self.iter.next() {
+ None => return None,
+ Some(&next_byte) if next_byte < 128 => return Some(next_byte as char),
+ Some(&next_byte) => next_byte,
+ };
+
+ // Multibyte case follows
+ // Decode from a byte combination out of: [[[x y] z] w]
+ // NOTE: Performance is sensitive to the exact formulation here
+ let init = utf8_first_byte!(x, 2);
+ let y = unwrap_or_0(self.iter.next());
+ let mut ch = utf8_acc_cont_byte!(init, y);
+ if x >= 0xE0 {
+ // [[x y z] w] case
+ // 5th bit in 0xE0 .. 0xEF is always clear, so `init` is still valid
+ let z = unwrap_or_0(self.iter.next());
+ let y_z = utf8_acc_cont_byte!((y & CONT_MASK) as u32, z);
+ ch = init << 12 | y_z;
+ if x >= 0xF0 {
+ // [x y z w] case
+ // use only the lower 3 bits of `init`
+ let w = unwrap_or_0(self.iter.next());
+ ch = (init & 7) << 18 | utf8_acc_cont_byte!(y_z, w);
}
- Some(ch)
- } else {
- None
+ }
+
+ // str invariant says `ch` is a valid Unicode Scalar Value
+ unsafe {
+ Some(mem::transmute(ch))
}
}
#[inline]
fn size_hint(&self) -> (uint, Option<uint>) {
- (self.string.len().saturating_add(3)/4, Some(self.string.len()))
+ let (len, _) = self.iter.size_hint();
+ (len.saturating_add(3) / 4, Some(len))
}
}
impl<'a> DoubleEndedIterator<char> for Chars<'a> {
#[inline]
fn next_back(&mut self) -> Option<char> {
- if self.string.len() != 0 {
- let CharRange {ch, next} = self.string.char_range_at_reverse(self.string.len());
- unsafe {
- self.string = raw::slice_unchecked(self.string, 0, next);
+ let w = match self.iter.next_back() {
+ None => return None,
+ Some(&back_byte) if back_byte < 128 => return Some(back_byte as char),
+ Some(&back_byte) => back_byte,
+ };
+
+ // Multibyte case follows
+ // Decode from a byte combination out of: [x [y [z w]]]
+ let mut ch;
+ let z = unwrap_or_0(self.iter.next_back());
+ ch = utf8_first_byte!(z, 2);
+ if utf8_is_cont_byte!(z) {
+ let y = unwrap_or_0(self.iter.next_back());
+ ch = utf8_first_byte!(y, 3);
+ if utf8_is_cont_byte!(y) {
+ let x = unwrap_or_0(self.iter.next_back());
+ ch = utf8_first_byte!(x, 4);
+ ch = utf8_acc_cont_byte!(ch, y);
}
- Some(ch)
- } else {
- None
+ ch = utf8_acc_cont_byte!(ch, z);
+ }
+ ch = utf8_acc_cont_byte!(ch, w);
+
+ // str invariant says `ch` is a valid Unicode Scalar Value
+ unsafe {
+ Some(mem::transmute(ch))
}
}
}
/// Use with the `std::iter` module.
#[deriving(Clone)]
pub struct CharOffsets<'a> {
- /// The original string to be iterated
- string: &'a str,
+ front_offset: uint,
iter: Chars<'a>,
}
impl<'a> Iterator<(uint, char)> for CharOffsets<'a> {
#[inline]
fn next(&mut self) -> Option<(uint, char)> {
- // Compute the byte offset by using the pointer offset between
- // the original string slice and the iterator's remaining part
- let offset = self.iter.string.as_ptr() as uint - self.string.as_ptr() as uint;
- self.iter.next().map(|ch| (offset, ch))
+ let (pre_len, _) = self.iter.iter.size_hint();
+ match self.iter.next() {
+ None => None,
+ Some(ch) => {
+ let index = self.front_offset;
+ let (len, _) = self.iter.iter.size_hint();
+ self.front_offset += pre_len - len;
+ Some((index, ch))
+ }
+ }
}
#[inline]
impl<'a> DoubleEndedIterator<(uint, char)> for CharOffsets<'a> {
#[inline]
fn next_back(&mut self) -> Option<(uint, char)> {
- self.iter.next_back().map(|ch| {
- let offset = self.iter.string.len() +
- self.iter.string.as_ptr() as uint - self.string.as_ptr() as uint;
- (offset, ch)
- })
+ match self.iter.next_back() {
+ None => None,
+ Some(ch) => {
+ let (len, _) = self.iter.iter.size_hint();
+ let index = self.front_offset + len;
+ Some((index, ch))
+ }
+ }
}
}
// UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
// %xF4 %x80-8F 2( UTF8-tail )
match w {
- 2 => if second & 192 != TAG_CONT_U8 {err!()},
+ 2 => if second & !CONT_MASK != TAG_CONT_U8 {err!()},
3 => {
- match (first, second, next!() & 192) {
+ match (first, second, next!() & !CONT_MASK) {
(0xE0 , 0xA0 .. 0xBF, TAG_CONT_U8) |
(0xE1 .. 0xEC, 0x80 .. 0xBF, TAG_CONT_U8) |
(0xED , 0x80 .. 0x9F, TAG_CONT_U8) |
}
}
4 => {
- match (first, second, next!() & 192, next!() & 192) {
+ match (first, second, next!() & !CONT_MASK, next!() & !CONT_MASK) {
(0xF0 , 0x90 .. 0xBF, TAG_CONT_U8, TAG_CONT_U8) |
(0xF1 .. 0xF3, 0x80 .. 0xBF, TAG_CONT_U8, TAG_CONT_U8) |
(0xF4 , 0x80 .. 0x8F, TAG_CONT_U8, TAG_CONT_U8) => {}
pub next: uint,
}
-// Return the initial codepoint accumulator for the first byte.
-// The first byte is special, only want bottom 5 bits for width 2, 4 bits
-// for width 3, and 3 bits for width 4
-macro_rules! utf8_first_byte(
- ($byte:expr, $width:expr) => (($byte & (0x7F >> $width)) as u32)
-)
-
-// return the value of $ch updated with continuation byte $byte
-macro_rules! utf8_acc_cont_byte(
- ($ch:expr, $byte:expr) => (($ch << 6) | ($byte & 63u8) as u32)
-)
-
-static TAG_CONT_U8: u8 = 128u8;
+/// Mask of the value bits of a continuation byte
+static CONT_MASK: u8 = 0b0011_1111u8;
+/// Value of the tag bits (tag mask is !CONT_MASK) of a continuation byte
+static TAG_CONT_U8: u8 = 0b1000_0000u8;
/// Unsafe operations
pub mod raw {
#[inline]
fn chars(&self) -> Chars<'a> {
- Chars{string: *self}
+ Chars{iter: self.as_bytes().iter()}
}
#[inline]
#[inline]
fn char_indices(&self) -> CharOffsets<'a> {
- CharOffsets{string: *self, iter: self.chars()}
+ CharOffsets{front_offset: 0, iter: self.chars()}
}
#[inline]
// Multibyte case is a fn to allow char_range_at_reverse to inline cleanly
fn multibyte_char_range_at_reverse(s: &str, mut i: uint) -> CharRange {
// while there is a previous byte == 10......
- while i > 0 && s.as_bytes()[i] & 192u8 == TAG_CONT_U8 {
+ while i > 0 && s.as_bytes()[i] & !CONT_MASK == TAG_CONT_U8 {
i -= 1u;
}
};
// 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.
+ // as used. After doing this, however, we still prioritize a crate name from
+ // the command line over one found in the #[crate_name] attribute. If we
+ // find both we ensure that they're the same later on as well.
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 {
- Some(ref s) => return validate(s.clone(), None),
+ Some(ref s) => {
+ match attr_crate_name {
+ Some((attr, ref name)) if s.as_slice() != name.get() => {
+ let msg = format!("--crate-name and #[crate_name] \
+ are required to match, but `{}` \
+ != `{}`", s, name);
+ sess.span_err(attr.span, msg.as_slice());
+ }
+ _ => {},
+ }
+ return validate(s.clone(), None);
+ }
None => {}
}
}
add_dynamic_crate(cmd, sess, src.dylib.unwrap())
}
cstore::RequireStatic => {
- add_static_crate(cmd, sess, tmpdir, cnum, src.rlib.unwrap())
+ add_static_crate(cmd, sess, tmpdir, src.rlib.unwrap())
}
}
// Adds the static "rlib" versions of all crates to the command line.
fn add_static_crate(cmd: &mut Command, sess: &Session, tmpdir: &Path,
- cnum: ast::CrateNum, cratepath: Path) {
+ cratepath: Path) {
// When performing LTO on an executable output, all of the
// bytecode from the upstream libraries has already been
// included in our object file output. We need to modify all of
// If we're not doing LTO, then our job is simply to just link
// against the archive.
if sess.lto() {
- let name = sess.cstore.get_crate_data(cnum).name.clone();
+ let name = cratepath.filename_str().unwrap();
+ let name = name.slice(3, name.len() - 5); // chop off lib/.rlib
time(sess.time_passes(),
format!("altering {}.rlib", name).as_slice(),
(), |()| {
};
let archive = ArchiveRO::open(&path).expect("wanted an rlib");
- debug!("reading {}", name);
+ let file = path.filename_str().unwrap();
+ let file = file.slice(3, file.len() - 5); // chop off lib/.rlib
+ debug!("reading {}", file);
let bc = time(sess.time_passes(),
format!("read {}.bytecode.deflate", name).as_slice(),
(),
|_| {
archive.read(format!("{}.bytecode.deflate",
- name).as_slice())
+ file).as_slice())
});
let bc = bc.expect("missing compressed bytecode in archive!");
let bc = time(sess.time_passes(),
- format!("inflate {}.bc", name).as_slice(),
+ format!("inflate {}.bc", file).as_slice(),
(),
|_| {
match flate::inflate_bytes(bc) {
E0091,
E0092,
E0093,
- E0094
+ E0094,
+ E0095,
+ E0096,
+ E0097,
+ E0098,
+ E0099,
+ E0100,
+ E0101,
+ E0102,
+ E0103,
+ E0104,
+ E0105,
+ E0106,
+ E0107,
+ E0108,
+ E0109,
+ E0110,
+ E0111,
+ E0112,
+ E0113,
+ E0114,
+ E0115,
+ E0116,
+ E0117,
+ E0118,
+ E0119,
+ E0120,
+ E0121,
+ E0122,
+ E0123,
+ E0124,
+ E0125,
+ E0126,
+ E0127,
+ E0128,
+ E0129,
+ E0130,
+ E0131,
+ E0132,
+ E0133,
+ E0134,
+ E0135,
+ E0136,
+ E0137,
+ E0138,
+ E0139,
+ E0140,
+ E0141,
+ E0142,
+ E0143,
+ E0144,
+ E0145,
+ E0146,
+ E0147,
+ E0148,
+ E0149,
+ E0150,
+ E0151,
+ E0152,
+ E0153,
+ E0154,
+ E0155,
+ E0156,
+ E0157
)
pub out_directory: Path,
pub out_filestem: String,
pub single_output_file: Option<Path>,
+ extra: String,
}
impl OutputFilenames {
}
pub fn temp_path(&self, flavor: link::OutputType) -> Path {
- let base = self.out_directory.join(self.out_filestem.as_slice());
+ let base = self.out_directory.join(self.filestem());
match flavor {
link::OutputTypeBitcode => base.with_extension("bc"),
link::OutputTypeAssembly => base.with_extension("s"),
}
pub fn with_extension(&self, extension: &str) -> Path {
- let stem = self.out_filestem.as_slice();
- self.out_directory.join(stem).with_extension(extension)
+ self.out_directory.join(self.filestem()).with_extension(extension)
+ }
+
+ fn filestem(&self) -> String {
+ format!("{}{}", self.out_filestem, self.extra)
}
}
out_directory: dirpath,
out_filestem: stem,
single_output_file: None,
+ extra: sess.opts.cg.extra_filename.clone(),
}
}
out_directory: out_file.dir_path(),
out_filestem: out_file.filestem_str().unwrap().to_string(),
single_output_file: ofile,
+ extra: sess.opts.cg.extra_filename.clone(),
}
}
}
ebml_w: &mut Encoder,
id: NodeId,
variants: &[P<Variant>],
- index: &mut Vec<entry<i64>>,
- generics: &ast::Generics) {
+ index: &mut Vec<entry<i64>>) {
debug!("encode_enum_variant_info(id={:?})", id);
let mut disr_val = 0;
encode_stability(ebml_w, stab);
match variant.node.kind {
- ast::TupleVariantKind(ref args)
- if args.len() > 0 && generics.ty_params.len() == 0 => {
- encode_symbol(ecx, ebml_w, variant.node.id);
- }
ast::TupleVariantKind(_) => {},
ast::StructVariantKind(_) => {
let fields = ty::lookup_struct_fields(ecx.tcx, def_id);
encode_stability(ebml_w, stab);
ebml_w.end_tag();
}
- ItemEnum(ref enum_definition, ref generics) => {
+ ItemEnum(ref enum_definition, _) => {
add_to_index(item, ebml_w, index);
ebml_w.start_tag(tag_items_data_item);
ebml_w,
item.id,
(*enum_definition).variants.as_slice(),
- index,
- generics);
+ index);
}
ItemStruct(struct_def, _) => {
let fields = ty::lookup_struct_fields(tcx, def_id);
match self.unsafe_context {
SafeContext => {
// Report an error.
- self.tcx.sess.span_err(span,
- format!("{} requires unsafe function or \
- block",
- description).as_slice())
+ span_err!(self.tcx.sess, span, E0133,
+ "{} requires unsafe function or block",
+ description);
}
UnsafeBlock(block_id) => {
// OK, but record this.
match ty::get(base_type).sty {
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty {
ty::ty_str => {
- self.tcx.sess.span_err(e.span,
- "modification of string types is not allowed");
+ span_err!(self.tcx.sess, e.span, E0134,
+ "modification of string types is not allowed");
}
_ => {}
},
ty::ty_str => {
- self.tcx.sess.span_err(e.span,
- "modification of string types is not allowed");
+ span_err!(self.tcx.sess, e.span, E0135,
+ "modification of string types is not allowed");
}
_ => {}
}
if ctxt.main_fn.is_none() {
ctxt.main_fn = Some((item.id, item.span));
} else {
- ctxt.session.span_err(
- item.span,
- "multiple 'main' functions");
+ span_err!(ctxt.session, item.span, E0136,
+ "multiple 'main' functions");
}
} else {
// This isn't main
if ctxt.attr_main_fn.is_none() {
ctxt.attr_main_fn = Some((item.id, item.span));
} else {
- ctxt.session.span_err(
- item.span,
- "multiple 'main' functions");
+ span_err!(ctxt.session, item.span, E0137,
+ "multiple functions with a #[main] attribute");
}
}
if ctxt.start_fn.is_none() {
ctxt.start_fn = Some((item.id, item.span));
} else {
- ctxt.session.span_err(
- item.span,
- "multiple 'start' functions");
+ span_err!(ctxt.session, item.span, E0138,
+ "multiple 'start' functions");
}
}
}
fn check_transmute(&self, span: Span, from: ty::t, to: ty::t) {
if type_size_is_affected_by_type_parameters(self.tcx, from) {
- self.tcx.sess.span_err(span,
- "cannot transmute from a type that \
- contains type parameters");
+ span_err!(self.tcx.sess, span, E0139,
+ "cannot transmute from a type that contains type parameters");
}
if type_size_is_affected_by_type_parameters(self.tcx, to) {
- self.tcx.sess.span_err(span,
- "cannot transmute to a type that contains \
- type parameters");
+ span_err!(self.tcx.sess, span, E0140,
+ "cannot transmute to a type that contains type parameters");
}
let restriction = TransmuteRestriction {
let struct_ty = ty::mk_struct(cx.tcx, struct_did,
subst::Substs::empty());
if !ty::type_is_sendable(cx.tcx, struct_ty) {
- cx.tcx.sess.span_err(span,
- "cannot implement a destructor on a \
- structure that does not satisfy Send");
- cx.tcx.sess.span_note(span,
- "use \"#[unsafe_destructor]\" on the \
- implementation to force the compiler to \
- allow this");
+ span_err!(cx.tcx.sess, span, E0125,
+ "cannot implement a destructor on a \
+ structure that does not satisfy Send");
+ span_note!(cx.tcx.sess, span,
+ "use \"#[unsafe_destructor]\" on the implementation \
+ to force the compiler to allow this");
}
} else {
- cx.tcx.sess.span_err(span,
- "cannot implement a destructor on a structure \
- with type parameters");
- cx.tcx.sess.span_note(span,
- "use \"#[unsafe_destructor]\" on the \
- implementation to force the compiler to \
- allow this");
+ span_err!(cx.tcx.sess, span, E0141,
+ "cannot implement a destructor on a structure \
+ with type parameters");
+ span_note!(cx.tcx.sess, span,
+ "use \"#[unsafe_destructor]\" on the implementation \
+ to force the compiler to allow this");
}
}
let self_ty: ty::t = ty::node_id_to_type(cx.tcx, it.id);
debug!("checking impl with self type {}", ty::get(self_ty).sty);
check_builtin_bounds(cx, self_ty, trait_def.bounds, |missing| {
- cx.tcx.sess.span_err(self_type.span,
- format!("the type `{}', which does not fulfill `{}`, cannot implement this \
- trait",
- ty_to_string(cx.tcx, self_ty),
- missing.user_string(cx.tcx)).as_slice());
- cx.tcx.sess.span_note(self_type.span,
- format!("types implementing this trait must fulfill `{}`",
- trait_def.bounds.user_string(cx.tcx)).as_slice());
+ span_err!(cx.tcx.sess, self_type.span, E0142,
+ "the type `{}', which does not fulfill `{}`, cannot implement this trait",
+ ty_to_string(cx.tcx, self_ty), missing.user_string(cx.tcx));
+ span_note!(cx.tcx.sess, self_type.span,
+ "types implementing this trait must fulfill `{}`",
+ trait_def.bounds.user_string(cx.tcx));
});
// If this is a destructor, check kinds.
}
fn check_for_bare(cx: &Context, fv: &freevar_entry) {
- cx.tcx.sess.span_err(
- fv.span,
- "can't capture dynamic environment in a fn item; \
- use the || { ... } closure form instead");
+ span_err!(cx.tcx.sess, fv.span, E0143,
+ "can't capture dynamic environment in a fn item; \
+ use the || {} closure form instead", "{ ... }");
} // same check is done in resolve.rs, but shouldn't be done
let fty = ty::node_id_to_type(cx.tcx, id);
ty,
type_param_def.bounds.builtin_bounds,
|missing| {
- cx.tcx.sess.span_err(
- sp,
- format!("instantiating a type parameter with an incompatible type \
- `{}`, which does not fulfill `{}`",
- ty_to_string(cx.tcx, ty),
- missing.user_string(cx.tcx)).as_slice());
+ span_err!(cx.tcx.sess, sp, E0144,
+ "instantiating a type parameter with an incompatible type \
+ `{}`, which does not fulfill `{}`",
+ ty_to_string(cx.tcx, ty),
+ missing.user_string(cx.tcx));
});
}
// Emit a less mysterious error message in this case.
match referenced_ty {
Some(rty) => {
- cx.tcx.sess.span_err(sp,
- format!("cannot implicitly borrow variable of type `{}` in a \
- bounded stack closure (implicit reference does not \
- fulfill `{}`)",
- ty_to_string(cx.tcx, rty),
- missing.user_string(cx.tcx)).as_slice())
+ span_err!(cx.tcx.sess, sp, E0145,
+ "cannot implicitly borrow variable of type `{}` in a \
+ bounded stack closure (implicit reference does not fulfill `{}`)",
+ ty_to_string(cx.tcx, rty), missing.user_string(cx.tcx));
}
None => {
- cx.tcx.sess.span_err(sp,
- format!("cannot capture variable of type `{}`, which does \
- not fulfill `{}`, in a bounded closure",
- ty_to_string(cx.tcx, ty),
- missing.user_string(cx.tcx)).as_slice())
+ span_err!(cx.tcx.sess, sp, E0146,
+ "cannot capture variable of type `{}`, which does \
+ not fulfill `{}`, in a bounded closure",
+ ty_to_string(cx.tcx, ty), missing.user_string(cx.tcx));
}
}
- cx.tcx.sess.span_note(
- sp,
- format!("this closure's environment must satisfy `{}`",
- bounds.user_string(cx.tcx)).as_slice());
+ span_note!(cx.tcx.sess, sp,
+ "this closure's environment must satisfy `{}`",
+ bounds.user_string(cx.tcx));
});
}
pub fn check_trait_cast_bounds(cx: &Context, sp: Span, ty: ty::t,
bounds: ty::BuiltinBounds) {
check_builtin_bounds(cx, ty, bounds, |missing| {
- cx.tcx.sess.span_err(sp,
- format!("cannot pack type `{}`, which does not fulfill \
- `{}`, as a trait bounded by {}",
- ty_to_string(cx.tcx, ty), missing.user_string(cx.tcx),
- bounds.user_string(cx.tcx)).as_slice());
+ span_err!(cx.tcx.sess, sp, E0147,
+ "cannot pack type `{}`, which does not fulfill `{}`, as a trait bounded by {}",
+ ty_to_string(cx.tcx, ty),
+ missing.user_string(cx.tcx),
+ bounds.user_string(cx.tcx));
});
}
ty_to_string(cx.tcx, ty),
ty::type_contents(cx.tcx, ty).to_string());
if ty::type_moves_by_default(cx.tcx, ty) {
- cx.tcx.sess.span_err(
- sp,
- format!("copying a value of non-copyable type `{}`",
- ty_to_string(cx.tcx, ty)).as_slice());
- cx.tcx.sess.span_note(sp, format!("{}", reason).as_slice());
+ span_err!(cx.tcx.sess, sp, E0148,
+ "copying a value of non-copyable type `{}`",
+ ty_to_string(cx.tcx, ty));
+ span_note!(cx.tcx.sess, sp, "{}", reason.as_slice());
}
}
pub fn check_static(tcx: &ty::ctxt, ty: ty::t, sp: Span) -> bool {
if !ty::type_is_static(tcx, ty) {
match ty::get(ty).sty {
- ty::ty_param(..) => {
- tcx.sess.span_err(sp,
- format!("value may contain references; \
- add `'static` bound to `{}`",
- ty_to_string(tcx, ty)).as_slice());
- }
- _ => {
- tcx.sess.span_err(sp, "value may contain references");
- }
+ ty::ty_param(..) => {
+ span_err!(tcx.sess, sp, E0149,
+ "value may contain references; \
+ add `'static` bound to `{}`",
+ ty_to_string(tcx, ty));
+ }
+ _ => {
+ span_err!(tcx.sess, sp, E0150,
+ "value may contain references");
+ }
}
false
} else {
// Ensure that `ty` has a statically known size (i.e., it has the `Sized` bound).
fn check_sized(tcx: &ty::ctxt, ty: ty::t, name: String, sp: Span) {
if !ty::type_is_sized(tcx, ty) {
- tcx.sess.span_err(sp,
- format!("variable `{}` has dynamically sized type \
- `{}`",
- name,
- ty_to_string(tcx, ty)).as_slice());
+ span_err!(tcx.sess, sp, E0151,
+ "variable `{}` has dynamically sized type `{}`",
+ name, ty_to_string(tcx, ty));
}
}
use syntax::ast;
use syntax::ast_util::local_def;
use syntax::attr::AttrMetaMethods;
+use syntax::codemap::{DUMMY_SP, Span};
use syntax::parse::token::InternedString;
use syntax::visit::Visitor;
use syntax::visit;
match item_index {
Some(item_index) => {
- self.collect_item(item_index, local_def(item.id))
+ self.collect_item(item_index, local_def(item.id), item.span)
}
None => {}
}
}
}
- pub fn collect_item(&mut self, item_index: uint, item_def_id: ast::DefId) {
+ pub fn collect_item(&mut self, item_index: uint,
+ item_def_id: ast::DefId, span: Span) {
// Check for duplicates.
match self.items.items.get(item_index) {
&Some(original_def_id) if original_def_id != item_def_id => {
- self.session.err(format!("duplicate entry for `{}`",
- LanguageItems::item_name(
- item_index)).as_slice());
+ span_err!(self.session, span, E0152,
+ "duplicate entry for `{}`", LanguageItems::item_name(item_index));
}
&Some(_) | &None => {
// OK.
crate_store.iter_crate_data(|crate_number, _crate_metadata| {
each_lang_item(crate_store, crate_number, |node_id, item_index| {
let def_id = ast::DefId { krate: crate_number, node: node_id };
- self.collect_item(item_index, def_id);
+ self.collect_item(item_index, def_id, DUMMY_SP);
true
});
})
this.record_def(path_id, (def, lp));
}
Some((DefStruct(_), _)) => {
- this.session.span_err(t.span,
- "super-struct is defined \
- in a different crate")
+ span_err!(this.session, t.span, E0154,
+ "super-struct is defined in a different crate");
},
- Some(_) => this.session.span_err(t.span,
- "super-struct is not a struct type"),
- None => this.session.span_err(t.span,
- "super-struct could not be resolved"),
+ Some(_) => {
+ span_err!(this.session, t.span, E0155,
+ "super-struct is not a struct type");
+ }
+ None => {
+ span_err!(this.session, t.span, E0156,
+ "super-struct could not be resolved");
+ }
}
},
_ => this.session.span_bug(t.span, "path not mapped to a TyPath")
if path.segments
.iter()
.any(|s| !s.lifetimes.is_empty()) {
- self.session.span_err(path.span,
- "lifetime parameters \
- are not allowed on \
- this type")
+ span_err!(self.session, path.span, E0157,
+ "lifetime parameters are not allowed on this type");
} else if path.segments
.iter()
.any(|s| s.types.len() > 0) {
- self.session.span_err(path.span,
- "type parameters are \
- not allowed on this \
- type")
+ span_err!(self.session, path.span, E0153,
+ "type parameters are not allowed on this type");
}
}
None => {
}
/**
- * Begin initializing a new value of the given case of the given
- * representation. The fields, if any, should then be initialized via
- * `trans_field_ptr`.
+ * Set the discriminant for a new value of the given case of the given
+ * representation.
*/
-pub fn trans_start_init(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr) {
+pub fn trans_set_discr(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr) {
match *r {
CEnum(ity, min, max) => {
assert_discr_in_range(ity, min, max, discr);
use std::cell::{Cell, RefCell};
use std::rc::Rc;
use std::{i8, i16, i32, i64};
-use std::gc::Gc;
use syntax::abi::{X86, X86_64, Arm, Mips, Mipsel, Rust, RustCall};
use syntax::abi::{RustIntrinsic, Abi};
use syntax::ast_util::{local_def, is_local};
llfndecl);
}
+pub fn trans_named_tuple_constructor<'a>(mut bcx: &'a Block<'a>,
+ ctor_ty: ty::t,
+ disr: ty::Disr,
+ args: callee::CallArgs,
+ dest: expr::Dest) -> Result<'a> {
+
+ let ccx = bcx.fcx.ccx;
+ let tcx = &ccx.tcx;
+
+ let result_ty = match ty::get(ctor_ty).sty {
+ ty::ty_bare_fn(ref bft) => bft.sig.output,
+ _ => ccx.sess().bug(
+ format!("trans_enum_variant_constructor: \
+ unexpected ctor return type {}",
+ ctor_ty.repr(tcx)).as_slice())
+ };
+
+ // Get location to store the result. If the user does not care about
+ // the result, just make a stack slot
+ let llresult = match dest {
+ expr::SaveIn(d) => d,
+ expr::Ignore => {
+ if !type_is_zero_size(ccx, result_ty) {
+ alloc_ty(bcx, result_ty, "constructor_result")
+ } else {
+ C_undef(type_of::type_of(ccx, result_ty))
+ }
+ }
+ };
+
+ if !type_is_zero_size(ccx, result_ty) {
+ let repr = adt::represent_type(ccx, result_ty);
+
+ match args {
+ callee::ArgExprs(exprs) => {
+ let fields = exprs.iter().map(|x| *x).enumerate().collect::<Vec<_>>();
+ bcx = expr::trans_adt(bcx, &*repr, disr, fields.as_slice(),
+ None, expr::SaveIn(llresult));
+ }
+ _ => ccx.sess().bug("expected expr as arguments for variant/struct tuple constructor")
+ }
+ }
+
+ // If the caller doesn't care about the result
+ // drop the temporary we made
+ let bcx = match dest {
+ expr::SaveIn(_) => bcx,
+ expr::Ignore => glue::drop_ty(bcx, llresult, result_ty)
+ };
+
+ Result::new(bcx, llresult)
+}
+
pub fn trans_tuple_struct(ccx: &CrateContext,
_fields: &[ast::StructField],
ctor_id: ast::NodeId,
if !type_is_zero_size(fcx.ccx, result_ty) {
let repr = adt::represent_type(ccx, result_ty);
- adt::trans_start_init(bcx, &*repr, fcx.llretptr.get().unwrap(), disr);
for (i, arg_datum) in arg_datums.move_iter().enumerate() {
let lldestptr = adt::trans_field_ptr(bcx,
&*repr,
i);
arg_datum.store_to(bcx, lldestptr);
}
+ adt::trans_set_discr(bcx, &*repr, fcx.llretptr.get().unwrap(), disr);
}
finish_fn(&fcx, bcx, result_ty);
}
-fn trans_enum_def(ccx: &CrateContext, enum_definition: &ast::EnumDef,
- sp: Span, id: ast::NodeId, vi: &[Rc<ty::VariantInfo>],
- i: &mut uint) {
- for variant in enum_definition.variants.iter() {
- let disr_val = vi[*i].disr_val;
- *i += 1;
-
- match variant.node.kind {
- ast::TupleVariantKind(ref args) if args.len() > 0 => {
- let llfn = get_item_val(ccx, variant.node.id);
- trans_enum_variant(ccx, id, &**variant, args.as_slice(),
- disr_val, ¶m_substs::empty(), llfn);
- }
- ast::TupleVariantKind(_) => {
- // Nothing to do.
- }
- ast::StructVariantKind(struct_def) => {
- trans_struct_def(ccx, struct_def);
- }
- }
- }
-
- enum_variant_size_lint(ccx, enum_definition, sp, id);
-}
-
fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &ast::EnumDef, sp: Span, id: ast::NodeId) {
let mut sizes = Vec::new(); // does no allocation if no pushes, thankfully
ast::ItemMod(ref m) => {
trans_mod(ccx, m);
}
- ast::ItemEnum(ref enum_definition, ref generics) => {
- if !generics.is_type_parameterized() {
- let vi = ty::enum_variants(ccx.tcx(), local_def(item.id));
- let mut i = 0;
- trans_enum_def(ccx, enum_definition, item.span, item.id, vi.as_slice(), &mut i);
- }
+ ast::ItemEnum(ref enum_definition, _) => {
+ enum_variant_size_lint(ccx, enum_definition, item.span, item.id);
}
ast::ItemStatic(_, m, ref expr) => {
// Recurse on the expression to catch items in blocks
ast::ItemForeignMod(ref foreign_mod) => {
foreign::trans_foreign_mod(ccx, foreign_mod);
}
- ast::ItemStruct(struct_def, ref generics) => {
- if !generics.is_type_parameterized() {
- trans_struct_def(ccx, struct_def);
- }
- }
ast::ItemTrait(..) => {
// Inside of this trait definition, we won't be actually translating any
// functions, but the trait still needs to be walked. Otherwise default
}
}
-pub fn trans_struct_def(ccx: &CrateContext, struct_def: Gc<ast::StructDef>) {
- // If this is a tuple-like struct, translate the constructor.
- match struct_def.ctor_id {
- // We only need to translate a constructor if there are fields;
- // otherwise this is a unit-like struct.
- Some(ctor_id) if struct_def.fields.len() > 0 => {
- let llfndecl = get_item_val(ccx, ctor_id);
- trans_tuple_struct(ccx, struct_def.fields.as_slice(),
- ctor_id, ¶m_substs::empty(), llfndecl);
- }
- Some(_) | None => {}
- }
-}
-
// Translate a module. Doing this amounts to translating the items in the
// module; there ends up being no artifact (aside from linkage names) of
// separate modules in the compiled program. That's because modules exist
use arena::TypedArena;
use back::abi;
use back::link;
+use driver::session;
use llvm::{ValueRef, get_param};
use llvm;
use metadata::csearch;
use std::gc::Gc;
use syntax::ast;
+use syntax::ast_map;
use synabi = syntax::abi;
pub struct MethodData {
pub enum CalleeData {
Closure(Datum<Lvalue>),
+ // Constructor for enum variant/tuple-like-struct
+ // i.e. Some, Ok
+ NamedTupleConstructor(subst::Substs, ty::Disr),
+
// Represents a (possibly monomorphized) top-level fn item or method
// item. Note that this is just the fn-ptr and is not a Rust closure
// value (which is a pair).
debug!("trans_def(def={}, ref_expr={})", def.repr(bcx.tcx()), ref_expr.repr(bcx.tcx()));
let expr_ty = node_id_type(bcx, ref_expr.id);
match def {
+ def::DefFn(did, _) if {
+ let def_id = if did.krate != ast::LOCAL_CRATE {
+ inline::maybe_instantiate_inline(bcx.ccx(), did)
+ } else {
+ did
+ };
+ match bcx.tcx().map.find(def_id.node) {
+ Some(ast_map::NodeStructCtor(_)) => true,
+ _ => false
+ }
+ } => {
+ let substs = node_id_substs(bcx, ExprId(ref_expr.id));
+ Callee {
+ bcx: bcx,
+ data: NamedTupleConstructor(substs, 0)
+ }
+ }
def::DefFn(did, _) if match ty::get(expr_ty).sty {
ty::ty_bare_fn(ref f) => f.abi == synabi::RustIntrinsic,
_ => false
ref_expr.id))
}
def::DefVariant(tid, vid, _) => {
- // nullary variants are not callable
- assert!(ty::enum_variant_with_id(bcx.tcx(),
- tid,
- vid).args.len() > 0u);
- fn_callee(bcx, trans_fn_ref(bcx, vid, ExprId(ref_expr.id)))
+ let vinfo = ty::enum_variant_with_id(bcx.tcx(), tid, vid);
+ let substs = node_id_substs(bcx, ExprId(ref_expr.id));
+
+ // Nullary variants are not callable
+ assert!(vinfo.args.len() > 0u);
+
+ Callee {
+ bcx: bcx,
+ data: NamedTupleConstructor(substs, vinfo.disr_val)
+ }
}
- def::DefStruct(def_id) => {
- fn_callee(bcx, trans_fn_ref(bcx, def_id, ExprId(ref_expr.id)))
+ def::DefStruct(_) => {
+ let substs = node_id_substs(bcx, ExprId(ref_expr.id));
+ Callee {
+ bcx: bcx,
+ data: NamedTupleConstructor(substs, 0)
+ }
}
def::DefStatic(..) |
def::DefArg(..) |
}
};
- // We must monomorphise if the fn has type parameters or is a default method.
- let must_monomorphise = !substs.types.is_empty() || is_default;
+ // We must monomorphise if the fn has type parameters, is a default method,
+ // or is a named tuple constructor.
+ let must_monomorphise = if !substs.types.is_empty() || is_default {
+ true
+ } else if def_id.krate == ast::LOCAL_CRATE {
+ let map_node = session::expect(
+ ccx.sess(),
+ tcx.map.find(def_id.node),
+ || "local item should be in ast map".to_string());
+
+ match map_node {
+ ast_map::NodeVariant(v) => match v.node.kind {
+ ast::TupleVariantKind(ref args) => args.len() > 0,
+ _ => false
+ },
+ ast_map::NodeStructCtor(_) => true,
+ _ => false
+ }
+ } else {
+ false
+ };
// Create a monomorphic version of generic functions
if must_monomorphise {
arg_cleanup_scope, args,
dest.unwrap(), substs);
}
+ NamedTupleConstructor(substs, disr) => {
+ assert!(dest.is_some());
+ fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
+
+ let ctor_ty = callee_ty.subst(bcx.tcx(), &substs);
+ return base::trans_named_tuple_constructor(bcx, ctor_ty, disr,
+ args, dest.unwrap());
+ }
};
// Intrinsics should not become actual functions.
let repr = adt::represent_type(bcx.ccx(), node_id_type(bcx, id));
// Create the closure.
- adt::trans_start_init(bcx, &*repr, dest_addr, 0);
for freevar in freevars_ptr.iter() {
let datum = expr::trans_local_var(bcx, freevar.def);
let upvar_slot_dest = adt::trans_field_ptr(bcx,
0);
bcx = datum.store_to(bcx, upvar_slot_dest);
}
+ adt::trans_set_discr(bcx, &*repr, dest_addr, 0);
bcx
}
// Nullary variant.
let ty = expr_ty(bcx, ref_expr);
let repr = adt::represent_type(bcx.ccx(), ty);
- adt::trans_start_init(bcx, &*repr, lldest,
- variant_info.disr_val);
+ adt::trans_set_discr(bcx, &*repr, lldest,
+ variant_info.disr_val);
return bcx;
}
}
match ty::get(ty).sty {
ty::ty_struct(did, _) if ty::has_dtor(bcx.tcx(), did) => {
let repr = adt::represent_type(bcx.ccx(), ty);
- adt::trans_start_init(bcx, &*repr, lldest, 0);
+ adt::trans_set_discr(bcx, &*repr, lldest, 0);
}
_ => {}
}
* Note that `fields` may be empty; the base expression must always be
* evaluated for side-effects.
*/
-struct StructBaseInfo {
+pub struct StructBaseInfo {
/// The base expression; will be evaluated after all explicit fields.
expr: Gc<ast::Expr>,
/// The indices of fields to copy paired with their types.
* - `optbase` contains information on the base struct (if any) from
* which remaining fields are copied; see comments on `StructBaseInfo`.
*/
-fn trans_adt<'a>(
- bcx: &'a Block<'a>,
- repr: &adt::Repr,
- discr: ty::Disr,
- fields: &[(uint, Gc<ast::Expr>)],
- optbase: Option<StructBaseInfo>,
- dest: Dest)
- -> &'a Block<'a> {
+pub fn trans_adt<'a>(bcx: &'a Block<'a>,
+ repr: &adt::Repr,
+ discr: ty::Disr,
+ fields: &[(uint, Gc<ast::Expr>)],
+ optbase: Option<StructBaseInfo>,
+ dest: Dest) -> &'a Block<'a> {
let _icx = push_ctxt("trans_adt");
let fcx = bcx.fcx;
let mut bcx = bcx;
// failure occur before the ADT as a whole is ready.
let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
- adt::trans_start_init(bcx, repr, addr, discr);
-
for &(i, ref e) in fields.iter() {
let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
let e_ty = expr_ty_adjusted(bcx, &**e);
}
}
+ adt::trans_set_discr(bcx, repr, addr, discr);
+
fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
return bcx;
match rscope.anon_regions(default_span, 1) {
Err(()) => {
debug!("optional region in illegal location");
- this.tcx().sess.span_err(
- default_span, "missing lifetime specifier");
+ span_err!(this.tcx().sess, default_span, E0106,
+ "missing lifetime specifier");
ty::ReStatic
}
rscope.anon_regions(path.span, expected_num_region_params);
if supplied_num_region_params != 0 || anon_regions.is_err() {
- tcx.sess.span_err(
- path.span,
- format!("wrong number of lifetime parameters: \
- expected {} but found {}",
- expected_num_region_params,
- supplied_num_region_params).as_slice());
+ span_err!(tcx.sess, path.span, E0107,
+ "wrong number of lifetime parameters: expected {} but found {}",
+ expected_num_region_params, supplied_num_region_params);
}
match anon_regions {
if supplied_ty_param_count > required_ty_param_count
&& !this.tcx().sess.features.default_type_params.get() {
- this.tcx().sess.span_err(path.span, "default type parameters are \
- experimental and possibly buggy");
- this.tcx().sess.span_note(path.span, "add #![feature(default_type_params)] \
- to the crate attributes to enable");
+ span_err!(this.tcx().sess, path.span, E0108,
+ "default type parameters are experimental and possibly buggy");
+ span_note!(this.tcx().sess, path.span,
+ "add #![feature(default_type_params)] to the crate attributes to enable");
}
let tps = path.segments.iter().flat_map(|s| s.types.iter())
flags: uint) {
if (flags & NO_TPS) != 0u {
if !path.segments.iter().all(|s| s.types.is_empty()) {
- tcx.sess.span_err(
- path.span,
+ span_err!(tcx.sess, path.span, E0109,
"type parameters are not allowed on this type");
}
}
if (flags & NO_REGIONS) != 0u {
if !path.segments.last().unwrap().lifetimes.is_empty() {
- tcx.sess.span_err(
- path.span,
+ span_err!(tcx.sess, path.span, E0110,
"region parameters are not allowed on this type");
}
}
Some(ty::mk_mach_float(ft))
}
ast::TyStr => {
- tcx.sess.span_err(ast_ty.span,
- "bare `str` is not a type");
+ span_err!(tcx.sess, ast_ty.span, E0037,
+ "bare `str` is not a type");
// return /something/ so they can at least get more errors
Some(ty::mk_uniq(tcx, ty::mk_str(tcx)))
}
.iter()
.flat_map(|s| s.types.iter())
.count() > 1 {
- this.tcx()
- .sess
- .span_err(path.span,
- "`Box` has only one type parameter")
+ span_err!(this.tcx().sess, path.span, E0047,
+ "`Box` has only one type parameter");
}
for inner_ast_type in path.segments
|typ| {
match ty::get(typ).sty {
ty::ty_str => {
- this.tcx()
- .sess
- .span_err(path.span,
- "`Box<str>` is not a type");
+ span_err!(this.tcx().sess, path.span, E0111,
+ "`Box<str>` is not a type");
ty::mk_err()
}
ty::ty_vec(_, None) => {
- this.tcx()
- .sess
- .span_err(path.span,
+ span_err!(this.tcx().sess, path.span, E0112,
"`Box<[T]>` is not a type");
ty::mk_err()
}
}
}))
}
- this.tcx().sess.span_err(path.span,
- "not enough type parameters \
- supplied to `Box<T>`");
+ span_err!(this.tcx().sess, path.span, E0113,
+ "not enough type parameters supplied to `Box<T>`");
Some(ty::mk_err())
}
def::DefTy(did) | def::DefStruct(did)
.iter()
.flat_map(|s| s.types.iter())
.count() > 1 {
- this.tcx()
- .sess
- .span_err(path.span,
- "`Gc` has only one type parameter")
+ span_err!(this.tcx().sess, path.span, E0048,
+ "`Gc` has only one type parameter");
}
for inner_ast_type in path.segments
|typ| {
match ty::get(typ).sty {
ty::ty_str => {
- this.tcx()
- .sess
- .span_err(path.span,
- "`Gc<str>` is not a type");
+ span_err!(this.tcx().sess, path.span, E0114,
+ "`Gc<str>` is not a type");
ty::mk_err()
}
ty::ty_vec(_, None) => {
- this.tcx()
- .sess
- .span_err(path.span,
- "`Gc<[T]>` is not a type");
+ span_err!(this.tcx().sess, path.span, E0115,
+ "`Gc<[T]>` is not a type");
ty::mk_err()
}
_ => ty::mk_box(this.tcx(), typ),
!ty::trait_ref_contains_error(&r_exp_trait_ref)
{
let tcx = vcx.tcx();
- tcx.sess.span_err(span,
- format!("expected {}, but found {} ({})",
- ppaux::trait_ref_to_string(tcx, &r_exp_trait_ref),
- ppaux::trait_ref_to_string(tcx, &r_act_trait_ref),
- ty::type_err_to_str(tcx, err)).as_slice());
+ span_err!(tcx.sess, span, E0095, "expected {}, but found {} ({})",
+ ppaux::trait_ref_to_string(tcx, &r_exp_trait_ref),
+ ppaux::trait_ref_to_string(tcx, &r_act_trait_ref),
+ ty::type_err_to_str(tcx, err));
}
}
}
1 => return Some(found.get(0).clone()),
_ => {
if !is_early {
- vcx.tcx().sess.span_err(span, "multiple applicable methods in scope");
+ span_err!(vcx.tcx().sess, span, E0096,
+ "multiple applicable methods in scope");
}
return Some(found.get(0).clone());
}
if !mutability_allowed(mt.mutbl, mutbl) => {
match ty::get(ty).sty {
ty::ty_trait(..) => {
- fcx.tcx()
- .sess
- .span_err(ex.span, "types differ in mutability");
+ span_err!(fcx.tcx().sess, ex.span, E0097, "types differ in mutability");
}
_ => {}
}
(&ty::ty_uniq(ty), _) => {
match ty::get(ty).sty {
ty::ty_trait(..) => {
- fcx.ccx.tcx.sess.span_err(
- ex.span,
- format!("can only cast an boxed pointer \
- to a boxed object, not a {}",
- ty::ty_sort_string(fcx.tcx(), src_ty)).as_slice());
+ span_err!(fcx.ccx.tcx.sess, ex.span, E0098,
+ "can only cast an boxed pointer to a boxed object, not a {}",
+ ty::ty_sort_string(fcx.tcx(), src_ty));
}
_ => {}
}
(&ty::ty_rptr(_, ty::mt{ty, ..}), _) => {
match ty::get(ty).sty {
ty::ty_trait(..) => {
- fcx.ccx.tcx.sess.span_err(
- ex.span,
- format!("can only cast an &-pointer \
- to an &-object, not a {}",
- ty::ty_sort_string(fcx.tcx(), src_ty)).as_slice());
+ span_err!(fcx.ccx.tcx.sess, ex.span, E0099,
+ "can only cast an &-pointer to an &-object, not a {}",
+ ty::ty_sort_string(fcx.tcx(), src_ty));
}
_ => {}
}
Some(&def::DefStruct(_)) => {
}
_ => {
- self.tcx().sess.span_err(
- reason.span(self.tcx()),
- "cannot coerce non-statically resolved bare fn")
+ span_err!(self.tcx().sess, reason.span(self.tcx()), E0100,
+ "cannot coerce non-statically resolved bare fn");
}
}
if !self.tcx.sess.has_errors() {
match self.reason {
ResolvingExpr(span) => {
- self.tcx.sess.span_err(
- span,
- format!("cannot determine a type for \
- this expression: {}",
- infer::fixup_err_to_string(e)).as_slice())
+ span_err!(self.tcx.sess, span, E0101,
+ "cannot determine a type for this expression: {}",
+ infer::fixup_err_to_string(e));
}
ResolvingLocal(span) => {
- self.tcx.sess.span_err(
- span,
- format!("cannot determine a type for \
- this local variable: {}",
- infer::fixup_err_to_string(e)).as_slice())
+ span_err!(self.tcx.sess, span, E0102,
+ "cannot determine a type for this local variable: {}",
+ infer::fixup_err_to_string(e));
}
ResolvingPattern(span) => {
- self.tcx.sess.span_err(
- span,
- format!("cannot determine a type for \
- this pattern binding: {}",
- infer::fixup_err_to_string(e)).as_slice())
+ span_err!(self.tcx.sess, span, E0103,
+ "cannot determine a type for this pattern binding: {}",
+ infer::fixup_err_to_string(e));
}
ResolvingUpvar(upvar_id) => {
let span = self.reason.span(self.tcx);
- self.tcx.sess.span_err(
- span,
- format!("cannot resolve lifetime for \
- captured variable `{}`: {}",
- ty::local_var_name_str(
- self.tcx,
- upvar_id.var_id).get().to_string(),
- infer::fixup_err_to_string(e)).as_slice());
+ span_err!(self.tcx.sess, span, E0104,
+ "cannot resolve lifetime for captured variable `{}`: {}",
+ ty::local_var_name_str(self.tcx, upvar_id.var_id).get().to_string(),
+ infer::fixup_err_to_string(e));
}
ResolvingImplRes(span) => {
- self.tcx
- .sess
- .span_err(span,
- "cannot determine a type for impl \
- supertrait");
+ span_err!(self.tcx.sess, span, E0105,
+ "cannot determine a type for impl supertrait");
}
ResolvingUnboxedClosure(_) => {
if !self.cc.ast_type_is_defined_in_local_crate(&**ast_ty) {
// This is an error.
let session = &self.cc.crate_context.tcx.sess;
- session.span_err(item.span,
- "cannot associate methods with a type outside the \
- crate the type is defined in; define and implement \
- a trait or new type instead");
+ span_err!(session, item.span, E0116,
+ "cannot associate methods with a type outside the \
+ crate the type is defined in; define and implement \
+ a trait or new type instead");
}
}
ItemImpl(_, Some(ref trait_ref), _, _) => {
if trait_def_id.krate != LOCAL_CRATE {
let session = &self.cc.crate_context.tcx.sess;
- session.span_err(item.span,
- "cannot provide an extension implementation \
- where both trait and type are not defined in this crate");
+ span_err!(session, item.span, E0117,
+ "cannot provide an extension implementation \
+ where both trait and type are not defined in this crate");
}
}
self_type.ty) {
None => {
let session = &self.crate_context.tcx.sess;
- session.span_err(item.span,
- "no base type found for inherent implementation; \
- implement a trait or new type instead");
+ span_err!(session, item.span, E0118,
+ "no base type found for inherent implementation; \
+ implement a trait or new type instead");
}
Some(_) => {
// Nothing to do.
if self.polytypes_unify(polytype_a.clone(), polytype_b) {
let session = &self.crate_context.tcx.sess;
- session.span_err(
- self.span_of_impl(impl_a),
- format!("conflicting implementations for trait `{}`",
- ty::item_path_str(
- self.crate_context.tcx,
- trait_def_id)).as_slice());
+ span_err!(session, self.span_of_impl(impl_a), E0119,
+ "conflicting implementations for trait `{}`",
+ ty::item_path_str(self.crate_context.tcx, trait_def_id));
if impl_b.krate == LOCAL_CRATE {
- session.span_note(self.span_of_impl(impl_b),
- "note conflicting implementation here");
+ span_note!(session, self.span_of_impl(impl_b),
+ "note conflicting implementation here");
} else {
let crate_store = &self.crate_context.tcx.sess.cstore;
let cdata = crate_store.get_crate_data(impl_b.krate);
- session.note(
- format!("conflicting implementation in crate \
- `{}`",
- cdata.name).as_slice());
+ span_note!(session, self.span_of_impl(impl_a),
+ "conflicting implementation in crate `{}`",
+ cdata.name);
}
}
}
{
match tcx.map.find(impl_did.node) {
Some(ast_map::NodeItem(item)) => {
- tcx.sess.span_err((*item).span,
- "the Drop trait may \
- only be implemented \
- on structures");
+ span_err!(tcx.sess, item.span, E0120,
+ "the Drop trait may only be implemented on structures");
}
_ => {
tcx.sess.bug("didn't find impl in ast \
}
fn ty_infer(&self, span: Span) -> ty::t {
- self.tcx.sess.span_err(span, "the type placeholder `_` is not \
- allowed within types on item \
- signatures.");
+ span_err!(self.tcx.sess, span, E0121,
+ "the type placeholder `_` is not allowed within types on item signatures.");
ty::mk_err()
}
}
thing: &'static str) {
for ty_param in generics.ty_params.iter() {
if ty_param.bounds.len() > 0 {
- ccx.tcx.sess.span_err(
- span,
- format!("trait bounds are not allowed in {} definitions",
- thing).as_slice());
+ span_err!(ccx.tcx.sess, span, E0122,
+ "trait bounds are not allowed in {} definitions", thing);
}
}
}
generics: &ast::Generics) {
if generics.ty_params.len() > 0 &&
!(abi == abi::Rust || abi == abi::RustIntrinsic) {
- ccx.tcx.sess.span_err(span,
- "foreign functions may not use type parameters");
+ span_err!(ccx.tcx.sess, span, E0123,
+ "foreign functions may not use type parameters");
}
}
if result.name != special_idents::unnamed_field.name {
let dup = match seen_fields.find(&result.name) {
Some(prev_span) => {
- tcx.sess.span_err(
- f.span,
- format!("field `{}` is already declared",
- token::get_name(result.name)).as_slice());
- tcx.sess.span_note(*prev_span,
- "previously declared here");
+ span_err!(tcx.sess, f.span, E0124,
+ "field `{}` is already declared",
+ token::get_name(result.name));
+ span_note!(tcx.sess, *prev_span, "previously declared here");
true
},
None => false,
Some(ast_map::NodeItem(i)) => match i.node {
ast::ItemStruct(struct_def, _) => {
if !struct_def.is_virtual {
- tcx.sess.span_err(t.span,
- "struct inheritance is only \
- allowed from virtual structs");
+ span_err!(tcx.sess, t.span, E0126,
+ "struct inheritance is only \
+ allowed from virtual structs");
}
},
_ => {},
{
// This means a trait inherited from the same
// supertrait more than once.
- tcx.sess.span_err(sp, "duplicate supertrait in \
- trait declaration");
+ span_err!(tcx.sess, sp, E0127,
+ "duplicate supertrait in trait declaration");
break;
} else {
ty_trait_refs.push(trait_ref);
ty::walk_ty(ty, |t| {
match ty::get(t).sty {
ty::ty_param(p) => if p.idx > cur_idx {
- ccx.tcx.sess.span_err(
- path.span,
- "type parameters with a default cannot use \
- forward declared identifiers")
+ span_err!(ccx.tcx.sess, path.span, E0128,
+ "type parameters with a default cannot use \
+ forward declared identifiers");
},
_ => {}
}
|trait_ref| {
let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id);
if trait_def.bounds.contains_elem(ty::BoundSized) {
- tcx.sess.span_err(span,
- format!("incompatible bounds on type parameter {}, \
- bound {} does not allow unsized type",
- token::get_ident(ident),
- ppaux::trait_ref_to_string(tcx,
- &*trait_ref)).as_slice());
+ span_err!(tcx.sess, span, E0129,
+ "incompatible bounds on type parameter {}, \
+ bound {} does not allow unsized type",
+ token::get_ident(ident),
+ ppaux::trait_ref_to_string(tcx, &*trait_ref));
}
true
});
match (*i).pat.node {
ast::PatIdent(_, _, _) => (),
ast::PatWild => (),
- _ => ccx.tcx.sess.span_err((*i).pat.span,
- "patterns aren't allowed in foreign function declarations")
+ _ => {
+ span_err!(ccx.tcx.sess, (*i).pat.span, E0130,
+ "patterns aren't allowed in foreign function declarations");
+ }
}
}
match it.node {
ast::ItemFn(_, _, _, ref ps, _)
if ps.is_parameterized() => {
- tcx.sess.span_err(
- main_span,
- "main function is not allowed to have type parameters");
+ span_err!(ccx.tcx.sess, main_span, E0131,
+ "main function is not allowed to have type parameters");
return;
}
_ => ()
match it.node {
ast::ItemFn(_,_,_,ref ps,_)
if ps.is_parameterized() => {
- tcx.sess.span_err(
- start_span,
- "start function is not allowed to have type parameters");
+ span_err!(tcx.sess, start_span, E0132,
+ "start function is not allowed to have type parameters");
return;
}
_ => ()
}
}
#[test]
+ #[ignore] // FIXME(#15763)
fn test_decode_errors_struct() {
check_err::<DecodeStruct>("[]", ExpectedError("Object".to_string(), "[]".to_string()));
check_err::<DecodeStruct>("{\"x\": true, \"y\": true, \"z\": \"\", \"w\": []}",
/// println!("{}", *book);
/// }
/// ```
+///
+/// The easiest way to use `HashSet` with a custom type is to derive
+/// `Eq` and `Hash`. We must also derive `PartialEq`, this will in the
+/// future be implied by `Eq`.
+///
+/// ```rust
+/// use std::collections::HashSet;
+///
+/// #[deriving(Hash, Eq, PartialEq, Show)]
+/// struct Viking<'a> {
+/// name: &'a str,
+/// power: uint,
+/// }
+///
+/// let mut vikings = HashSet::new();
+///
+/// vikings.insert(Viking { name: "Einar", power: 9u });
+/// vikings.insert(Viking { name: "Einar", power: 9u });
+/// vikings.insert(Viking { name: "Olaf", power: 4u });
+/// vikings.insert(Viking { name: "Harald", power: 8u });
+///
+/// // Use derived implementation to print the vikings.
+/// for x in vikings.iter() {
+/// println!("{}", x);
+/// }
+/// ```
#[deriving(Clone)]
pub struct HashSet<T, H = RandomSipHasher> {
map: HashMap<T, (), H>
}
-impl<T: Eq + Hash<S>, S, H: Hasher<S>> PartialEq for HashSet<T, H> {
- fn eq(&self, other: &HashSet<T, H>) -> bool {
- if self.len() != other.len() { return false; }
-
- self.iter().all(|key| other.contains(key))
- }
-}
-
-impl<T: Eq + Hash<S>, S, H: Hasher<S>> Eq for HashSet<T, H> {}
-
-impl<T: Eq + Hash<S>, S, H: Hasher<S>> Collection for HashSet<T, H> {
- fn len(&self) -> uint { self.map.len() }
-}
-
-impl<T: Eq + Hash<S>, S, H: Hasher<S>> Mutable for HashSet<T, H> {
- fn clear(&mut self) { self.map.clear() }
-}
-
-impl<T: Eq + Hash<S>, S, H: Hasher<S>> Set<T> for HashSet<T, H> {
- fn contains(&self, value: &T) -> bool { self.map.contains_key(value) }
-
- fn is_disjoint(&self, other: &HashSet<T, H>) -> bool {
- self.iter().all(|v| !other.contains(v))
- }
-
- fn is_subset(&self, other: &HashSet<T, H>) -> bool {
- self.iter().all(|v| other.contains(v))
- }
-}
-
-impl<T: Eq + Hash<S>, S, H: Hasher<S>> MutableSet<T> for HashSet<T, H> {
- fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()) }
-
- fn remove(&mut self, value: &T) -> bool { self.map.remove(value) }
-}
-
impl<T: Hash + Eq> HashSet<T, RandomSipHasher> {
- /// Create an empty HashSet
+ /// Create an empty HashSet.
///
/// # Example
///
/// ```rust
- /// # use std::collections::HashSet;
+ /// use std::collections::HashSet;
/// let mut set: HashSet<int> = HashSet::new();
/// ```
#[inline]
/// # Example
///
/// ```rust
- /// # use std::collections::HashSet;
+ /// use std::collections::HashSet;
/// let mut set: HashSet<int> = HashSet::with_capacity(10);
/// ```
#[inline]
/// keys.
///
/// The hash set is also created with the default initial capacity.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use std::collections::HashSet;
+ /// use std::hash::sip::SipHasher;
+ ///
+ /// let h = SipHasher::new();
+ /// let mut set = HashSet::with_hasher(h);
+ /// set.insert(2u);
+ /// ```
#[inline]
pub fn with_hasher(hasher: H) -> HashSet<T, H> {
HashSet::with_capacity_and_hasher(INITIAL_CAPACITY, hasher)
/// is designed to allow `HashSet`s to be resistant to attacks that
/// cause many collisions and very poor performance. Setting it
/// manually using this function can expose a DoS attack vector.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use std::collections::HashSet;
+ /// use std::hash::sip::SipHasher;
+ ///
+ /// let h = SipHasher::new();
+ /// let mut set = HashSet::with_capacity_and_hasher(10u, h);
+ /// set.insert(1i);
+ /// ```
#[inline]
pub fn with_capacity_and_hasher(capacity: uint, hasher: H) -> HashSet<T, H> {
HashSet { map: HashMap::with_capacity_and_hasher(capacity, hasher) }
/// # Example
///
/// ```rust
- /// # use std::collections::HashSet;
+ /// use std::collections::HashSet;
/// let mut set: HashSet<int> = HashSet::new();
/// set.reserve(10);
/// ```
/// Returns true if the hash set contains a value equivalent to the
/// given query value.
+ ///
+ /// # Example
+ ///
+ /// This is a slightly silly example where we define the number's
+ /// parity as the equivilance class. It is important that the
+ /// values hash the same, which is why we implement `Hash`.
+ ///
+ /// ```rust
+ /// use std::collections::HashSet;
+ /// use std::hash::Hash;
+ /// use std::hash::sip::SipState;
+ ///
+ /// #[deriving(Eq, PartialEq)]
+ /// struct EvenOrOdd {
+ /// num: uint
+ /// };
+ ///
+ /// impl Hash for EvenOrOdd {
+ /// fn hash(&self, state: &mut SipState) {
+ /// let parity = self.num % 2;
+ /// parity.hash(state);
+ /// }
+ /// }
+ ///
+ /// impl Equiv<EvenOrOdd> for EvenOrOdd {
+ /// fn equiv(&self, other: &EvenOrOdd) -> bool {
+ /// self.num % 2 == other.num % 2
+ /// }
+ /// }
+ ///
+ /// let mut set = HashSet::new();
+ /// set.insert(EvenOrOdd { num: 3u });
+ ///
+ /// assert!(set.contains_equiv(&EvenOrOdd { num: 3u }));
+ /// assert!(set.contains_equiv(&EvenOrOdd { num: 5u }));
+ /// assert!(!set.contains_equiv(&EvenOrOdd { num: 4u }));
+ /// assert!(!set.contains_equiv(&EvenOrOdd { num: 2u }));
+ ///
+ /// ```
pub fn contains_equiv<Q: Hash<S> + Equiv<T>>(&self, value: &Q) -> bool {
self.map.contains_key_equiv(value)
}
/// # Example
///
/// ```rust
- /// # use std::collections::HashSet;
+ /// use std::collections::HashSet;
+ ///
/// let mut set = HashSet::new();
/// set.insert("a");
/// set.insert("b");
/// # Example
///
/// ```rust
- /// # use std::collections::HashSet;
+ /// use std::collections::HashSet;
+ ///
/// let mut set = HashSet::new();
/// set.insert("a".to_string());
/// set.insert("b".to_string());
/// # Example
///
/// ```rust
- /// # use std::collections::HashSet;
+ /// use std::collections::HashSet;
+ ///
/// let a: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
/// let b: HashSet<int> = [4i, 2, 3, 4].iter().map(|&x| x).collect();
///
/// # Example
///
/// ```rust
- /// # use std::collections::HashSet;
+ /// use std::collections::HashSet;
+ ///
/// let a: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
/// let b: HashSet<int> = [4i, 2, 3, 4].iter().map(|&x| x).collect();
///
/// # Example
///
/// ```rust
- /// # use std::collections::HashSet;
+ /// use std::collections::HashSet;
+ ///
/// let a: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
/// let b: HashSet<int> = [4i, 2, 3, 4].iter().map(|&x| x).collect();
///
/// # Example
///
/// ```rust
- /// # use std::collections::HashSet;
+ /// use std::collections::HashSet;
+ ///
/// let a: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
/// let b: HashSet<int> = [4i, 2, 3, 4].iter().map(|&x| x).collect();
///
}
}
+impl<T: Eq + Hash<S>, S, H: Hasher<S>> PartialEq for HashSet<T, H> {
+ fn eq(&self, other: &HashSet<T, H>) -> bool {
+ if self.len() != other.len() { return false; }
+
+ self.iter().all(|key| other.contains(key))
+ }
+}
+
+impl<T: Eq + Hash<S>, S, H: Hasher<S>> Eq for HashSet<T, H> {}
+
+impl<T: Eq + Hash<S>, S, H: Hasher<S>> Collection for HashSet<T, H> {
+ fn len(&self) -> uint { self.map.len() }
+}
+
+impl<T: Eq + Hash<S>, S, H: Hasher<S>> Mutable for HashSet<T, H> {
+ fn clear(&mut self) { self.map.clear() }
+}
+
+impl<T: Eq + Hash<S>, S, H: Hasher<S>> Set<T> for HashSet<T, H> {
+ fn contains(&self, value: &T) -> bool { self.map.contains_key(value) }
+
+ fn is_disjoint(&self, other: &HashSet<T, H>) -> bool {
+ self.iter().all(|v| !other.contains(v))
+ }
+
+ fn is_subset(&self, other: &HashSet<T, H>) -> bool {
+ self.iter().all(|v| other.contains(v))
+ }
+}
+
+impl<T: Eq + Hash<S>, S, H: Hasher<S>> MutableSet<T> for HashSet<T, H> {
+ fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()) }
+
+ fn remove(&mut self, value: &T) -> bool { self.map.remove(value) }
+}
+
+
impl<T: Eq + Hash<S> + fmt::Show, S, H: Hasher<S>> fmt::Show for HashSet<T, H> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "{{"));
#[macro_export]
macro_rules! span_err(
- ($session:expr, $span:expr, $code:ident, $($arg:expr),*) => ({
+ ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
__diagnostic_used!($code);
- ($session).span_err_with_code($span, format!($($arg),*).as_slice(), stringify!($code))
+ $session.span_err_with_code($span, format!($($message)*).as_slice(), stringify!($code))
})
)
#[macro_export]
macro_rules! span_warn(
- ($session:expr, $span:expr, $code:ident, $($arg:expr),*) => ({
+ ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
__diagnostic_used!($code);
- ($session).span_warn_with_code($span, format!($($arg),*).as_slice(), stringify!($code))
+ $session.span_warn_with_code($span, format!($($message)*).as_slice(), stringify!($code))
})
)
#[macro_export]
macro_rules! span_note(
- ($session:expr, $span:expr, $($arg:expr),*) => ({
- ($session).span_note($span, format!($($arg),*).as_slice())
+ ($session:expr, $span:expr, $($message:tt)*) => ({
+ ($session).span_note($span, format!($($message)*).as_slice())
})
)
let chunk_size = h / WORKERS;
// Account for remainders in workload division, e.g. 1000 / 16 = 62.5
- let first_chunk_size = if h % WORKERS != 0 {
+ let last_chunk_size = if h % WORKERS != 0 {
chunk_size + h % WORKERS
} else {
chunk_size
let mut is = Vec::with_capacity(w / WORKERS);
let start = i * chunk_size;
- let end = if i == 0 {
- first_chunk_size
+ let end = if i == (WORKERS - 1) {
+ start + last_chunk_size
} else {
(i + 1) * chunk_size
};
--- /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 foo
+
+#![crate_name = "bar"]
+//~^ ERROR: --crate-name and #[crate_name] are required to match, but `foo` != `bar`
+
+fn main() {}
}
#[main]
-fn foo() { //~ ERROR multiple 'main' functions
+fn foo() { //~ ERROR multiple functions with a #[main] attribute
}
mod foo {
#[main]
- fn main2() { //~ ERROR multiple 'main' functions
+ fn main2() { //~ ERROR multiple functions with a #[main] attribute
}
}
rm $(TMPDIR)/$(call BIN,bar)
$(RUSTC) foo1.rs
rm $(TMPDIR)/$(call BIN,foo)
- $(RUSTC) foo1.rs --crate-name bar
- rm $(TMPDIR)/$(call BIN,bar)
- $(RUSTC) foo1.rs --crate-name bar -o $(TMPDIR)/bar1
+ $(RUSTC) foo1.rs -o $(TMPDIR)/bar1
rm $(TMPDIR)/$(call BIN,bar1)
--- /dev/null
+-include ../tools.mk
+
+all:
+ $(RUSTC) -C extra-filename=bar foo.rs -C save-temps
+ rm $(TMPDIR)/foobar.o
+ rm $(TMPDIR)/$(call BIN,foobar)
--- /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.
+
+fn main() {}
// compile-flags:--crate-name crate-name-attr-used -F unused-attribute
-#![crate_name = "test"]
+#![crate_name = "crate-name-attr-used"]
fn main() {}