From d90a7b3b006be912493ddf15d0dc5895a6929b38 Mon Sep 17 00:00:00 2001 From: f001 Date: Sun, 5 Feb 2017 17:39:52 +0800 Subject: [PATCH 1/7] std: Add retain method for HashMap and HashSet Fix #36648 --- src/libstd/collections/hash/map.rs | 114 ++++++++++++++++++--------- src/libstd/collections/hash/set.rs | 33 ++++++++ src/libstd/collections/hash/table.rs | 81 +++++++++++++++++-- 3 files changed, 182 insertions(+), 46 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 8058972e75093..f689589dfa25f 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -416,22 +416,26 @@ fn search_hashed(table: M, hash: SafeHash, mut is_match: F) -> Inter } } -fn pop_internal(starting_bucket: FullBucketMut) -> (K, V) { +fn pop_internal(starting_bucket: FullBucketMut) + -> (K, V, &mut RawTable) +{ let (empty, retkey, retval) = starting_bucket.take(); let mut gap = match empty.gap_peek() { - Some(b) => b, - None => return (retkey, retval), + Ok(b) => b, + Err(b) => return (retkey, retval, b.into_table()), }; while gap.full().displacement() != 0 { gap = match gap.shift() { - Some(b) => b, - None => break, + Ok(b) => b, + Err(b) => { + return (retkey, retval, b.into_table()); + }, }; } // Now we've done all our shifting. Return the value we grabbed earlier. - (retkey, retval) + (retkey, retval, gap.into_bucket().into_table()) } /// Perform robin hood bucket stealing at the given `bucket`. You must @@ -721,38 +725,7 @@ impl HashMap return; } - // Grow the table. - // Specialization of the other branch. - let mut bucket = Bucket::first(&mut old_table); - - // "So a few of the first shall be last: for many be called, - // but few chosen." - // - // We'll most likely encounter a few buckets at the beginning that - // have their initial buckets near the end of the table. They were - // placed at the beginning as the probe wrapped around the table - // during insertion. We must skip forward to a bucket that won't - // get reinserted too early and won't unfairly steal others spot. - // This eliminates the need for robin hood. - loop { - bucket = match bucket.peek() { - Full(full) => { - if full.displacement() == 0 { - // This bucket occupies its ideal spot. - // It indicates the start of another "cluster". - bucket = full.into_bucket(); - break; - } - // Leaving this bucket in the last cluster for later. - full.into_bucket() - } - Empty(b) => { - // Encountered a hole between clusters. - b.into_bucket() - } - }; - bucket.next(); - } + let mut bucket = Bucket::head_bucket(&mut old_table); // This is how the buckets might be laid out in memory: // ($ marks an initialized bucket) @@ -1208,6 +1181,57 @@ impl HashMap self.search_mut(k).into_occupied_bucket().map(|bucket| pop_internal(bucket).1) } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all pairs `(k, v)` such that `f(&k,&mut v)` returns `false`. + /// + /// # Examples + /// + /// ``` + /// #![feature(retain_hash_collection)] + /// use std::collections::HashMap; + /// + /// let mut map: HashMap = (0..8).map(|x|(x, x*10)).collect(); + /// map.retain(|&k, _| k % 2 == 0); + /// assert_eq!(map.len(), 4); + /// ``` + #[unstable(feature = "retain_hash_collection", issue = "36648")] + pub fn retain(&mut self, mut f: F) + where F: FnMut(&K, &mut V) -> bool + { + if self.table.capacity() == 0 || self.table.size() == 0 { + return; + } + let mut bucket = Bucket::head_bucket(&mut self.table); + bucket.prev(); + let tail = bucket.index(); + loop { + bucket = match bucket.peek() { + Full(mut full) => { + let should_remove = { + let (k, v) = full.read_mut(); + !f(k, v) + }; + if should_remove { + let prev_idx = full.index(); + let prev_raw = full.raw(); + let (_, _, t) = pop_internal(full); + Bucket::new_from(prev_raw, prev_idx, t) + } else { + full.into_bucket() + } + }, + Empty(b) => { + b.into_bucket() + } + }; + bucket.prev(); // reverse iteration + if bucket.index() == tail { + break; + } + } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1862,7 +1886,8 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// ``` #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] pub fn remove_entry(self) -> (K, V) { - pop_internal(self.elem) + let (k, v, _) = pop_internal(self.elem); + (k, v) } /// Gets a reference to the value in the entry. @@ -3156,4 +3181,15 @@ mod test_map { assert_eq!(a.len(), 1); assert_eq!(a[key], value); } + + #[test] + fn test_retain() { + let mut map: HashMap = (0..100).map(|x|(x, x*10)).collect(); + + map.retain(|&k, _| k % 2 == 0); + assert_eq!(map.len(), 50); + assert_eq!(map[&2], 20); + assert_eq!(map[&4], 40); + assert_eq!(map[&6], 60); + } } diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 341b050862f5c..8de742db46110 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -624,6 +624,28 @@ impl HashSet { Recover::take(&mut self.map, value) } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(&e)` returns `false`. + /// + /// # Examples + /// + /// ``` + /// #![feature(retain_hash_collection)] + /// use std::collections::HashSet; + /// + /// let xs = [1,2,3,4,5,6]; + /// let mut set: HashSet = xs.iter().cloned().collect(); + /// set.retain(|&k| k % 2 == 0); + /// assert_eq!(set.len(), 3); + /// ``` + #[unstable(feature = "retain_hash_collection", issue = "36648")] + pub fn retain(&mut self, mut f: F) + where F: FnMut(&T) -> bool + { + self.map.retain(|k, _| f(k)); + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1605,4 +1627,15 @@ mod test_set { assert!(a.contains(&5)); assert!(a.contains(&6)); } + + #[test] + fn test_retain() { + let xs = [1,2,3,4,5,6]; + let mut set: HashSet = xs.iter().cloned().collect(); + set.retain(|&k| k % 2 == 0); + assert_eq!(set.len(), 3); + assert!(set.contains(&2)); + assert!(set.contains(&4)); + assert!(set.contains(&6)); + } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 1ab62130cd3dd..9e92b4750145e 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -85,7 +85,7 @@ pub struct RawTable { unsafe impl Send for RawTable {} unsafe impl Sync for RawTable {} -struct RawBucket { +pub struct RawBucket { hash: *mut HashUint, // We use *const to ensure covariance with respect to K and V pair: *const (K, V), @@ -216,6 +216,10 @@ impl FullBucket { pub fn index(&self) -> usize { self.idx } + /// Get the raw bucket. + pub fn raw(&self) -> RawBucket { + self.raw + } } impl EmptyBucket { @@ -230,6 +234,10 @@ impl Bucket { pub fn index(&self) -> usize { self.idx } + /// get the table. + pub fn into_table(self) -> M { + self.table + } } impl Deref for FullBucket @@ -275,6 +283,16 @@ impl>> Bucket { Bucket::at_index(table, hash.inspect() as usize) } + pub fn new_from(r: RawBucket, i: usize, t: M) + -> Bucket + { + Bucket { + raw: r, + idx: i, + table: t, + } + } + pub fn at_index(table: M, ib_index: usize) -> Bucket { // if capacity is 0, then the RawBucket will be populated with bogus pointers. // This is an uncommon case though, so avoid it in release builds. @@ -296,6 +314,40 @@ impl>> Bucket { } } + // "So a few of the first shall be last: for many be called, + // but few chosen." + // + // We'll most likely encounter a few buckets at the beginning that + // have their initial buckets near the end of the table. They were + // placed at the beginning as the probe wrapped around the table + // during insertion. We must skip forward to a bucket that won't + // get reinserted too early and won't unfairly steal others spot. + // This eliminates the need for robin hood. + pub fn head_bucket(table: M) -> Bucket { + let mut bucket = Bucket::first(table); + + loop { + bucket = match bucket.peek() { + Full(full) => { + if full.displacement() == 0 { + // This bucket occupies its ideal spot. + // It indicates the start of another "cluster". + bucket = full.into_bucket(); + break; + } + // Leaving this bucket in the last cluster for later. + full.into_bucket() + } + Empty(b) => { + // Encountered a hole between clusters. + b.into_bucket() + } + }; + bucket.next(); + } + bucket + } + /// Reads a bucket at a given index, returning an enum indicating whether /// it's initialized or not. You need to match on this enum to get /// the appropriate types to call most of the other functions in @@ -333,6 +385,17 @@ impl>> Bucket { self.raw = self.raw.offset(dist); } } + + /// Modifies the bucket pointer in place to make it point to the previous slot. + pub fn prev(&mut self) { + let range = self.table.capacity(); + let new_idx = self.idx.wrapping_sub(1) & (range - 1); + let dist = (new_idx as isize).wrapping_sub(self.idx as isize); + self.idx = new_idx; + unsafe { + self.raw = self.raw.offset(dist); + } + } } impl>> EmptyBucket { @@ -352,7 +415,7 @@ impl>> EmptyBucket { } } - pub fn gap_peek(self) -> Option> { + pub fn gap_peek(self) -> Result, Bucket> { let gap = EmptyBucket { raw: self.raw, idx: self.idx, @@ -361,12 +424,12 @@ impl>> EmptyBucket { match self.next().peek() { Full(bucket) => { - Some(GapThenFull { + Ok(GapThenFull { gap: gap, full: bucket, }) } - Empty(..) => None, + Empty(e) => Err(e.into_bucket()), } } } @@ -529,7 +592,11 @@ impl GapThenFull &self.full } - pub fn shift(mut self) -> Option> { + pub fn into_bucket(self) -> Bucket { + self.full.into_bucket() + } + + pub fn shift(mut self) -> Result, Bucket> { unsafe { *self.gap.raw.hash = mem::replace(&mut *self.full.raw.hash, EMPTY_BUCKET); ptr::copy_nonoverlapping(self.full.raw.pair, self.gap.raw.pair as *mut (K, V), 1); @@ -544,9 +611,9 @@ impl GapThenFull self.full = bucket; - Some(self) + Ok(self) } - Empty(..) => None, + Empty(b) => Err(b.into_bucket()), } } } From fb9104768c0991b935e4b5cbc67180e49d425f2c Mon Sep 17 00:00:00 2001 From: Brian Vincent Date: Thu, 2 Feb 2017 00:58:18 -0600 Subject: [PATCH 2/7] Dont segfault if btree range is not in order --- src/libcollections/btree/map.rs | 204 +++++++++++++--------------- src/libcollections/btree/search.rs | 3 +- src/libcollectionstest/btree/map.rs | 42 ++++++ 3 files changed, 134 insertions(+), 115 deletions(-) diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index e1fabe2cc496b..7218d15ded5f8 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -714,6 +714,11 @@ impl BTreeMap { /// `range((Excluded(4), Included(10)))` will yield a left-exclusive, right-inclusive /// range from 4 to 10. /// + /// # Panics + /// + /// Panics if range `start > end`. + /// Panics if range `start == end` and both bounds are `Excluded`. + /// /// # Examples /// /// Basic usage: @@ -739,64 +744,11 @@ impl BTreeMap { pub fn range(&self, range: R) -> Range where T: Ord, K: Borrow, R: RangeArgument { - let min = range.start(); - let max = range.end(); - let front = match min { - Included(key) => { - match search::search_tree(self.root.as_ref(), key) { - Found(kv_handle) => { - match kv_handle.left_edge().force() { - Leaf(bottom) => bottom, - Internal(internal) => last_leaf_edge(internal.descend()), - } - } - GoDown(bottom) => bottom, - } - } - Excluded(key) => { - match search::search_tree(self.root.as_ref(), key) { - Found(kv_handle) => { - match kv_handle.right_edge().force() { - Leaf(bottom) => bottom, - Internal(internal) => first_leaf_edge(internal.descend()), - } - } - GoDown(bottom) => bottom, - } - } - Unbounded => first_leaf_edge(self.root.as_ref()), - }; + let root1 = self.root.as_ref(); + let root2 = self.root.as_ref(); + let (f, b) = range_search(root1, root2, range); - let back = match max { - Included(key) => { - match search::search_tree(self.root.as_ref(), key) { - Found(kv_handle) => { - match kv_handle.right_edge().force() { - Leaf(bottom) => bottom, - Internal(internal) => first_leaf_edge(internal.descend()), - } - } - GoDown(bottom) => bottom, - } - } - Excluded(key) => { - match search::search_tree(self.root.as_ref(), key) { - Found(kv_handle) => { - match kv_handle.left_edge().force() { - Leaf(bottom) => bottom, - Internal(internal) => last_leaf_edge(internal.descend()), - } - } - GoDown(bottom) => bottom, - } - } - Unbounded => last_leaf_edge(self.root.as_ref()), - }; - - Range { - front: front, - back: back, - } + Range { front: f, back: b} } /// Constructs a mutable double-ended iterator over a sub-range of elements in the map. @@ -806,6 +758,11 @@ impl BTreeMap { /// `range((Excluded(4), Included(10)))` will yield a left-exclusive, right-inclusive /// range from 4 to 10. /// + /// # Panics + /// + /// Panics if range `start > end`. + /// Panics if range `start == end` and both bounds are `Excluded`. + /// /// # Examples /// /// Basic usage: @@ -831,66 +788,13 @@ impl BTreeMap { pub fn range_mut(&mut self, range: R) -> RangeMut where T: Ord, K: Borrow, R: RangeArgument { - let min = range.start(); - let max = range.end(); let root1 = self.root.as_mut(); let root2 = unsafe { ptr::read(&root1) }; - - let front = match min { - Included(key) => { - match search::search_tree(root1, key) { - Found(kv_handle) => { - match kv_handle.left_edge().force() { - Leaf(bottom) => bottom, - Internal(internal) => last_leaf_edge(internal.descend()), - } - } - GoDown(bottom) => bottom, - } - } - Excluded(key) => { - match search::search_tree(root1, key) { - Found(kv_handle) => { - match kv_handle.right_edge().force() { - Leaf(bottom) => bottom, - Internal(internal) => first_leaf_edge(internal.descend()), - } - } - GoDown(bottom) => bottom, - } - } - Unbounded => first_leaf_edge(root1), - }; - - let back = match max { - Included(key) => { - match search::search_tree(root2, key) { - Found(kv_handle) => { - match kv_handle.right_edge().force() { - Leaf(bottom) => bottom, - Internal(internal) => first_leaf_edge(internal.descend()), - } - } - GoDown(bottom) => bottom, - } - } - Excluded(key) => { - match search::search_tree(root2, key) { - Found(kv_handle) => { - match kv_handle.left_edge().force() { - Leaf(bottom) => bottom, - Internal(internal) => last_leaf_edge(internal.descend()), - } - } - GoDown(bottom) => bottom, - } - } - Unbounded => last_leaf_edge(root2), - }; + let (f, b) = range_search(root1, root2, range); RangeMut { - front: front, - back: back, + front: f, + back: b, _marker: PhantomData, } } @@ -1827,6 +1731,80 @@ fn last_leaf_edge } } +fn range_search>( + root1: NodeRef, + root2: NodeRef, + range: R +)-> (Handle, marker::Edge>, + Handle, marker::Edge>) + where Q: Ord, K: Borrow +{ + match (range.start(), range.end()) { + (Excluded(s), Excluded(e)) if s==e => + panic!("range start and end are equal and excluded in BTreeMap"), + (Included(s), Included(e)) | + (Included(s), Excluded(e)) | + (Excluded(s), Included(e)) | + (Excluded(s), Excluded(e)) if s>e => + panic!("range start is greater than range end in BTreeMap"), + _ => {}, + }; + + let mut min_node = root1; + let mut max_node = root2; + let mut min_found = false; + let mut max_found = false; + let mut diverged = false; + + loop { + let min_edge = match (min_found, range.start()) { + (false, Included(key)) => match search::search_linear(&min_node, key) { + (i, true) => { min_found = true; i }, + (i, false) => i, + }, + (false, Excluded(key)) => match search::search_linear(&min_node, key) { + (i, true) => { min_found = true; i+1 }, + (i, false) => i, + }, + (_, Unbounded) => 0, + (true, Included(_)) => min_node.keys().len(), + (true, Excluded(_)) => 0, + }; + + let max_edge = match (max_found, range.end()) { + (false, Included(key)) => match search::search_linear(&max_node, key) { + (i, true) => { max_found = true; i+1 }, + (i, false) => i, + }, + (false, Excluded(key)) => match search::search_linear(&max_node, key) { + (i, true) => { max_found = true; i }, + (i, false) => i, + }, + (_, Unbounded) => max_node.keys().len(), + (true, Included(_)) => 0, + (true, Excluded(_)) => max_node.keys().len(), + }; + + if !diverged { + if max_edge < min_edge { panic!("Ord is ill-defined in BTreeMap range") } + if min_edge != max_edge { diverged = true; } + } + + let front = Handle::new_edge(min_node, min_edge); + let back = Handle::new_edge(max_node, max_edge); + match (front.force(), back.force()) { + (Leaf(f), Leaf(b)) => { + return (f, b); + }, + (Internal(min_int), Internal(max_int)) => { + min_node = min_int.descend(); + max_node = max_int.descend(); + }, + _ => unreachable!("BTreeMap has different depths"), + }; + } +} + #[inline(always)] unsafe fn unwrap_unchecked(val: Option) -> T { val.unwrap_or_else(|| { diff --git a/src/libcollections/btree/search.rs b/src/libcollections/btree/search.rs index c94b570bfed8b..bc1272fbc786e 100644 --- a/src/libcollections/btree/search.rs +++ b/src/libcollections/btree/search.rs @@ -58,7 +58,7 @@ pub fn search_node( } } -fn search_linear( +pub fn search_linear( node: &NodeRef, key: &Q ) -> (usize, bool) @@ -73,4 +73,3 @@ fn search_linear( } (node.keys().len(), false) } - diff --git a/src/libcollectionstest/btree/map.rs b/src/libcollectionstest/btree/map.rs index 11be13426e49c..f33923f996319 100644 --- a/src/libcollectionstest/btree/map.rs +++ b/src/libcollectionstest/btree/map.rs @@ -178,6 +178,48 @@ fn test_range_small() { assert_eq!(j, size - 2); } +#[test] +fn test_range_equal_empty_cases() { + let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect(); + assert_eq!(map.range((Included(2), Excluded(2))).next(), None); + assert_eq!(map.range((Excluded(2), Included(2))).next(), None); +} + +#[test] +#[should_panic] +fn test_range_equal_excluded() { + let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect(); + map.range((Excluded(2), Excluded(2))); +} + +#[test] +#[should_panic] +fn test_range_backwards_1() { + let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect(); + map.range((Included(3), Included(2))); +} + +#[test] +#[should_panic] +fn test_range_backwards_2() { + let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect(); + map.range((Included(3), Excluded(2))); +} + +#[test] +#[should_panic] +fn test_range_backwards_3() { + let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect(); + map.range((Excluded(3), Included(2))); +} + +#[test] +#[should_panic] +fn test_range_backwards_4() { + let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect(); + map.range((Excluded(3), Excluded(2))); +} + #[test] fn test_range_1000() { let size = 1000; From 530d09c5d6782d4329b21661a2adacdc11806082 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 13 Feb 2017 17:50:58 +1300 Subject: [PATCH 3/7] save-analysis: emit info about impls and super-traits in JSON --- src/librustc_save_analysis/dump_visitor.rs | 17 +------ src/librustc_save_analysis/json_api_dumper.rs | 47 ++++++++++++++++++ src/librustc_save_analysis/json_dumper.rs | 49 +++++++++++++++++-- src/librustc_save_analysis/lib.rs | 4 +- 4 files changed, 97 insertions(+), 20 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 41f91a1d2acc1..292f1eb13663b 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -747,21 +747,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { trait_ref: &'l Option, typ: &'l ast::Ty, impl_items: &'l [ast::ImplItem]) { - let mut has_self_ref = false; if let Some(impl_data) = self.save_ctxt.get_item_data(item) { down_cast_data!(impl_data, ImplData, item.span); - if let Some(ref self_ref) = impl_data.self_ref { - has_self_ref = true; - if !self.span.filter_generated(Some(self_ref.span), item.span) { - self.dumper.type_ref(self_ref.clone().lower(self.tcx)); - } - } - if let Some(ref trait_ref_data) = impl_data.trait_ref { - if !self.span.filter_generated(Some(trait_ref_data.span), item.span) { - self.dumper.type_ref(trait_ref_data.clone().lower(self.tcx)); - } - } - if !self.span.filter_generated(Some(impl_data.span), item.span) { self.dumper.impl_data(ImplData { id: impl_data.id, @@ -772,9 +759,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { }.lower(self.tcx)); } } - if !has_self_ref { - self.visit_ty(&typ); - } + self.visit_ty(&typ); if let &Some(ref trait_ref) = trait_ref { self.process_path(trait_ref.ref_id, &trait_ref.path, Some(recorder::TypeRef)); } diff --git a/src/librustc_save_analysis/json_api_dumper.rs b/src/librustc_save_analysis/json_api_dumper.rs index 342c33af2f896..277535f9e6513 100644 --- a/src/librustc_save_analysis/json_api_dumper.rs +++ b/src/librustc_save_analysis/json_api_dumper.rs @@ -74,6 +74,15 @@ impl<'b, W: Write + 'b> Dump for JsonApiDumper<'b, W> { impl_fn!(mod_data, ModData, defs); impl_fn!(typedef, TypeDefData, defs); impl_fn!(variable, VariableData, defs); + + fn impl_data(&mut self, data: ImplData) { + if data.self_ref.is_some() { + self.result.relations.push(From::from(data)); + } + } + fn inheritance(&mut self, data: InheritanceData) { + self.result.relations.push(From::from(data)); + } } // FIXME methods. The defs have information about possible overriding and the @@ -87,6 +96,7 @@ struct Analysis { prelude: Option, imports: Vec, defs: Vec, + relations: Vec, // These two fields are dummies so that clients can parse the two kinds of // JSON data in the same way. refs: Vec<()>, @@ -100,6 +110,7 @@ impl Analysis { prelude: None, imports: vec![], defs: vec![], + relations: vec![], refs: vec![], macro_refs: vec![], } @@ -427,6 +438,42 @@ impl From for Option { } } +#[derive(Debug, RustcEncodable)] +struct Relation { + span: SpanData, + kind: RelationKind, + from: Id, + to: Id, +} + +#[derive(Debug, RustcEncodable)] +enum RelationKind { + Impl, + SuperTrait, +} + +impl From for Relation { + fn from(data: ImplData) -> Relation { + Relation { + span: data.span, + kind: RelationKind::Impl, + from: From::from(data.self_ref.unwrap_or(null_def_id())), + to: From::from(data.trait_ref.unwrap_or(null_def_id())), + } + } +} + +impl From for Relation { + fn from(data: InheritanceData) -> Relation { + Relation { + span: data.span, + kind: RelationKind::SuperTrait, + from: From::from(data.base_id), + to: From::from(data.deriv_id), + } + } +} + #[derive(Debug, RustcEncodable)] pub struct JsonSignature { span: SpanData, diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index 16c06a556df0e..09752994290c9 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -112,9 +112,14 @@ impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> { self.result.defs.push(def); } - // FIXME store this instead of throwing it away. - fn impl_data(&mut self, _data: ImplData) {} - fn inheritance(&mut self, _data: InheritanceData) {} + fn impl_data(&mut self, data: ImplData) { + if data.self_ref.is_some() { + self.result.relations.push(From::from(data)); + } + } + fn inheritance(&mut self, data: InheritanceData) { + self.result.relations.push(From::from(data)); + } } // FIXME do we want to change ExternalData to this mode? It will break DXR. @@ -131,6 +136,7 @@ struct Analysis { defs: Vec, refs: Vec, macro_refs: Vec, + relations: Vec, } impl Analysis { @@ -142,6 +148,7 @@ impl Analysis { defs: vec![], refs: vec![], macro_refs: vec![], + relations: vec![], } } } @@ -508,6 +515,42 @@ impl From for MacroRef { } } +#[derive(Debug, RustcEncodable)] +struct Relation { + span: SpanData, + kind: RelationKind, + from: Id, + to: Id, +} + +#[derive(Debug, RustcEncodable)] +enum RelationKind { + Impl, + SuperTrait, +} + +impl From for Relation { + fn from(data: ImplData) -> Relation { + Relation { + span: data.span, + kind: RelationKind::Impl, + from: From::from(data.self_ref.unwrap_or(null_def_id())), + to: From::from(data.trait_ref.unwrap_or(null_def_id())), + } + } +} + +impl From for Relation { + fn from(data: InheritanceData) -> Relation { + Relation { + span: data.span, + kind: RelationKind::SuperTrait, + from: From::from(data.base_id), + to: From::from(data.deriv_id), + } + } +} + #[derive(Debug, RustcEncodable)] pub struct JsonSignature { span: SpanData, diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index ebb33a12c8703..ddc60fe5f81d8 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -239,7 +239,9 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { match typ.node { // Common case impl for a struct or something basic. ast::TyKind::Path(None, ref path) => { - filter!(self.span_utils, None, path.span, None); + if generated_code(path.span) { + return None; + } sub_span = self.span_utils.sub_span_for_type_name(path.span); type_data = self.lookup_ref_id(typ.id).map(|id| { TypeRefData { From 51a2e2fd826c82252d101ad1e1904319699e417e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 Feb 2017 19:50:54 +0100 Subject: [PATCH 4/7] Allow more Cell methods for non-Copy types Contributes to #39264 --- src/libcore/cell.rs | 120 ++++++++++++++++++++++---------------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index ab44342ebf02f..1570428cf18b4 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -212,66 +212,6 @@ impl Cell { pub fn get(&self) -> T { unsafe{ *self.value.get() } } - - /// Returns a reference to the underlying `UnsafeCell`. - /// - /// # Examples - /// - /// ``` - /// #![feature(as_unsafe_cell)] - /// - /// use std::cell::Cell; - /// - /// let c = Cell::new(5); - /// - /// let uc = c.as_unsafe_cell(); - /// ``` - #[inline] - #[unstable(feature = "as_unsafe_cell", issue = "27708")] - #[rustc_deprecated(since = "1.12.0", reason = "renamed to as_ptr")] - pub fn as_unsafe_cell(&self) -> &UnsafeCell { - &self.value - } - - /// Returns a raw pointer to the underlying data in this cell. - /// - /// # Examples - /// - /// ``` - /// use std::cell::Cell; - /// - /// let c = Cell::new(5); - /// - /// let ptr = c.as_ptr(); - /// ``` - #[inline] - #[stable(feature = "cell_as_ptr", since = "1.12.0")] - pub fn as_ptr(&self) -> *mut T { - self.value.get() - } - - /// Returns a mutable reference to the underlying data. - /// - /// This call borrows `Cell` mutably (at compile-time) which guarantees - /// that we possess the only reference. - /// - /// # Examples - /// - /// ``` - /// use std::cell::Cell; - /// - /// let mut c = Cell::new(5); - /// *c.get_mut() += 1; - /// - /// assert_eq!(c.get(), 6); - /// ``` - #[inline] - #[stable(feature = "cell_get_mut", since = "1.11.0")] - pub fn get_mut(&mut self) -> &mut T { - unsafe { - &mut *self.value.get() - } - } } #[stable(feature = "rust1", since = "1.0.0")] @@ -369,6 +309,66 @@ impl Cell { } } + /// Returns a reference to the underlying `UnsafeCell`. + /// + /// # Examples + /// + /// ``` + /// #![feature(as_unsafe_cell)] + /// + /// use std::cell::Cell; + /// + /// let c = Cell::new(5); + /// + /// let uc = c.as_unsafe_cell(); + /// ``` + #[inline] + #[unstable(feature = "as_unsafe_cell", issue = "27708")] + #[rustc_deprecated(since = "1.12.0", reason = "renamed to as_ptr")] + pub fn as_unsafe_cell(&self) -> &UnsafeCell { + &self.value + } + + /// Returns a raw pointer to the underlying data in this cell. + /// + /// # Examples + /// + /// ``` + /// use std::cell::Cell; + /// + /// let c = Cell::new(5); + /// + /// let ptr = c.as_ptr(); + /// ``` + #[inline] + #[stable(feature = "cell_as_ptr", since = "1.12.0")] + pub fn as_ptr(&self) -> *mut T { + self.value.get() + } + + /// Returns a mutable reference to the underlying data. + /// + /// This call borrows `Cell` mutably (at compile-time) which guarantees + /// that we possess the only reference. + /// + /// # Examples + /// + /// ``` + /// use std::cell::Cell; + /// + /// let mut c = Cell::new(5); + /// *c.get_mut() += 1; + /// + /// assert_eq!(c.get(), 6); + /// ``` + #[inline] + #[stable(feature = "cell_get_mut", since = "1.11.0")] + pub fn get_mut(&mut self) -> &mut T { + unsafe { + &mut *self.value.get() + } + } + /// Sets the contained value. /// /// # Examples From 044ed10fee3351da2315d5d8e26949929ad918ce Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Feb 2017 09:46:03 +0100 Subject: [PATCH 5/7] Remove Copy bound from some Cell trait impls Contributes to #39264 --- src/libcore/cell.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 1570428cf18b4..2b4ce3a35fcca 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -229,7 +229,7 @@ impl Clone for Cell { } #[stable(feature = "rust1", since = "1.0.0")] -impl Default for Cell { +impl Default for Cell { /// Creates a `Cell`, with the `Default` value for T. #[inline] fn default() -> Cell { @@ -285,7 +285,7 @@ impl Ord for Cell { } #[stable(feature = "cell_from", since = "1.12.0")] -impl From for Cell { +impl From for Cell { fn from(t: T) -> Cell { Cell::new(t) } From ca54fc76ae3045917273c5c102f5d9e0e99deb7e Mon Sep 17 00:00:00 2001 From: Sebastian Waisbrot Date: Tue, 14 Feb 2017 01:32:05 -0300 Subject: [PATCH 6/7] Show five traits implementation in help when there are exactly five --- src/librustc/traits/error_reporting.rs | 9 ++-- .../issue-39802-show-5-trait-impls.rs | 37 ++++++++++++++++ .../issue-39802-show-5-trait-impls.stderr | 43 +++++++++++++++++++ 3 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.rs create mode 100644 src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 024c14ce9d922..70ca5fe83a932 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -36,7 +36,6 @@ use ty::fold::TypeFolder; use ty::subst::Subst; use util::nodemap::{FxHashMap, FxHashSet}; -use std::cmp; use std::fmt; use syntax::ast; use hir::{intravisit, Local, Pat}; @@ -392,12 +391,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { return; } - let end = cmp::min(4, impl_candidates.len()); + let end = if impl_candidates.len() <= 5 { + impl_candidates.len() + } else { + 4 + }; err.help(&format!("the following implementations were found:{}{}", &impl_candidates[0..end].iter().map(|candidate| { format!("\n {:?}", candidate) }).collect::(), - if impl_candidates.len() > 4 { + if impl_candidates.len() > 5 { format!("\nand {} others", impl_candidates.len() - 4) } else { "".to_owned() diff --git a/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.rs b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.rs new file mode 100644 index 0000000000000..68b1f79c89bbe --- /dev/null +++ b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.rs @@ -0,0 +1,37 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo { + fn bar(&self){} +} + +impl Foo for i8 {} +impl Foo for i8 {} +impl Foo for i8 {} +impl Foo for i8 {} +impl Foo for i8 {} + +impl Foo for u8 {} +impl Foo for u8 {} +impl Foo for u8 {} +impl Foo for u8 {} + +impl Foo for bool {} +impl Foo for bool {} +impl Foo for bool {} +impl Foo for bool {} +impl Foo for bool {} +impl Foo for bool {} + +fn main() { + Foo::::bar(&1i8); + Foo::::bar(&1u8); + Foo::::bar(&true); +} diff --git a/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr new file mode 100644 index 0000000000000..4ea4adfcfe0fc --- /dev/null +++ b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr @@ -0,0 +1,43 @@ +error[E0277]: the trait bound `i8: Foo` is not satisfied + --> $DIR/issue-39802-show-5-trait-impls.rs:34:5 + | +34 | Foo::::bar(&1i8); + | ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i8` + | + = help: the following implementations were found: + > + > + > + > + > + = note: required by `Foo::bar` + +error[E0277]: the trait bound `u8: Foo` is not satisfied + --> $DIR/issue-39802-show-5-trait-impls.rs:35:5 + | +35 | Foo::::bar(&1u8); + | ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `u8` + | + = help: the following implementations were found: + > + > + > + > + = note: required by `Foo::bar` + +error[E0277]: the trait bound `bool: Foo` is not satisfied + --> $DIR/issue-39802-show-5-trait-impls.rs:36:5 + | +36 | Foo::::bar(&true); + | ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `bool` + | + = help: the following implementations were found: + > + > + > + > + and 2 others + = note: required by `Foo::bar` + +error: aborting due to 3 previous errors + From 963843b1b346278fcf6f7f065cabdaaae775a0a1 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Tue, 31 Jan 2017 22:46:16 -0500 Subject: [PATCH 7/7] Conversions between CStr/OsStr/Path and boxes. --- src/liballoc/boxed.rs | 8 ++++++ src/libstd/ffi/c_str.rs | 42 +++++++++++++++++++++++++++++++- src/libstd/ffi/os_str.rs | 38 +++++++++++++++++++++++++++++ src/libstd/path.rs | 40 ++++++++++++++++++++++++++++++ src/libstd/sys/redox/os_str.rs | 16 ++++++++++++ src/libstd/sys/unix/os_str.rs | 16 ++++++++++++ src/libstd/sys/windows/os_str.rs | 14 +++++++++++ src/libstd/sys_common/wtf8.rs | 19 +++++++++++++++ 8 files changed, 192 insertions(+), 1 deletion(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index ac9439974a491..d0fce70612868 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -315,6 +315,14 @@ impl Default for Box<[T]> { } } +#[stable(feature = "default_box_extra", since = "1.17.0")] +impl Default for Box { + fn default() -> Box { + let default: Box<[u8]> = Default::default(); + unsafe { mem::transmute(default) } + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Box { /// Returns a new box with a `clone()` of this box's contents. diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index d1b8fcd744003..dc3855367ae27 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -303,6 +303,12 @@ impl CString { &self.inner } + /// Converts this `CString` into a boxed `CStr`. + #[unstable(feature = "into_boxed_c_str", issue = "0")] + pub fn into_boxed_c_str(self) -> Box { + unsafe { mem::transmute(self.into_inner()) } + } + // Bypass "move out of struct which implements `Drop` trait" restriction. fn into_inner(self) -> Box<[u8]> { unsafe { @@ -380,6 +386,22 @@ impl Borrow for CString { fn borrow(&self) -> &CStr { self } } +#[stable(feature = "box_from_c_str", since = "1.17.0")] +impl<'a> From<&'a CStr> for Box { + fn from(s: &'a CStr) -> Box { + let boxed: Box<[u8]> = Box::from(s.to_bytes_with_nul()); + unsafe { mem::transmute(boxed) } + } +} + +#[stable(feature = "default_box_extra", since = "1.17.0")] +impl Default for Box { + fn default() -> Box { + let boxed: Box<[u8]> = Box::from([0]); + unsafe { mem::transmute(boxed) } + } +} + impl NulError { /// Returns the position of the nul byte in the slice that was provided to /// `CString::new`. @@ -686,7 +708,7 @@ impl ToOwned for CStr { type Owned = CString; fn to_owned(&self) -> CString { - CString { inner: self.to_bytes_with_nul().to_vec().into_boxed_slice() } + CString { inner: self.to_bytes_with_nul().into() } } } @@ -847,4 +869,22 @@ mod tests { let cstr = CStr::from_bytes_with_nul(data); assert!(cstr.is_err()); } + + #[test] + fn into_boxed() { + let orig: &[u8] = b"Hello, world!\0"; + let cstr = CStr::from_bytes_with_nul(orig).unwrap(); + let cstring = cstr.to_owned(); + let box1: Box = Box::from(cstr); + let box2 = cstring.into_boxed_c_str(); + assert_eq!(cstr, &*box1); + assert_eq!(box1, box2); + assert_eq!(&*box2, cstr); + } + + #[test] + fn boxed_default() { + let boxed = >::default(); + assert_eq!(boxed.to_bytes_with_nul(), &[0]); + } } diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 273b717f4678b..7b8bf42e0a74a 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -204,6 +204,12 @@ impl OsString { pub fn reserve_exact(&mut self, additional: usize) { self.inner.reserve_exact(additional) } + + /// Converts this `OsString` into a boxed `OsStr`. + #[unstable(feature = "into_boxed_os_str", issue = "0")] + pub fn into_boxed_os_str(self) -> Box { + unsafe { mem::transmute(self.inner.into_box()) } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -445,6 +451,20 @@ impl OsStr { } } +#[stable(feature = "box_from_os_str", since = "1.17.0")] +impl<'a> From<&'a OsStr> for Box { + fn from(s: &'a OsStr) -> Box { + unsafe { mem::transmute(s.inner.into_box()) } + } +} + +#[stable(feature = "box_default_extra", since = "1.17.0")] +impl Default for Box { + fn default() -> Box { + unsafe { mem::transmute(Slice::empty_box()) } + } +} + #[stable(feature = "osstring_default", since = "1.9.0")] impl<'a> Default for &'a OsStr { /// Creates an empty `OsStr`. @@ -741,4 +761,22 @@ mod tests { let os_str: &OsStr = Default::default(); assert_eq!("", os_str); } + + #[test] + fn into_boxed() { + let orig = "Hello, world!"; + let os_str = OsStr::new(orig); + let os_string = os_str.to_owned(); + let box1: Box = Box::from(os_str); + let box2 = os_string.into_boxed_os_str(); + assert_eq!(os_str, &*box1); + assert_eq!(box1, box2); + assert_eq!(&*box2, os_str); + } + + #[test] + fn boxed_default() { + let boxed = >::default(); + assert!(boxed.is_empty()); + } } diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 07b43cd89ac71..245a6d945b5a3 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1194,6 +1194,28 @@ impl PathBuf { pub fn into_os_string(self) -> OsString { self.inner } + + /// Converts this `PathBuf` into a boxed `Path`. + #[unstable(feature = "into_boxed_path", issue = "0")] + pub fn into_boxed_path(self) -> Box { + unsafe { mem::transmute(self.inner.into_boxed_os_str()) } + } +} + +#[stable(feature = "box_from_path", since = "1.17.0")] +impl<'a> From<&'a Path> for Box { + fn from(path: &'a Path) -> Box { + let boxed: Box = path.inner.into(); + unsafe { mem::transmute(boxed) } + } +} + +#[stable(feature = "box_default_extra", since = "1.17.0")] +impl Default for Box { + fn default() -> Box { + let boxed: Box = Default::default(); + unsafe { mem::transmute(boxed) } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -3676,4 +3698,22 @@ mod tests { let actual = format!("{:?}", iter); assert_eq!(expected, actual); } + + #[test] + fn into_boxed() { + let orig: &str = "some/sort/of/path"; + let path = Path::new(orig); + let path_buf = path.to_owned(); + let box1: Box = Box::from(path); + let box2 = path_buf.into_boxed_path(); + assert_eq!(path, &*box1); + assert_eq!(box1, box2); + assert_eq!(&*box2, path); + } + + #[test] + fn boxed_default() { + let boxed = >::default(); + assert!(boxed.as_os_str().is_empty()); + } } diff --git a/src/libstd/sys/redox/os_str.rs b/src/libstd/sys/redox/os_str.rs index 8922bf04f56da..0f967863899cb 100644 --- a/src/libstd/sys/redox/os_str.rs +++ b/src/libstd/sys/redox/os_str.rs @@ -94,6 +94,11 @@ impl Buf { pub fn push_slice(&mut self, s: &Slice) { self.inner.extend_from_slice(&s.inner) } + + #[inline] + pub fn into_box(self) -> Box { + unsafe { mem::transmute(self.inner.into_boxed_slice()) } + } } impl Slice { @@ -116,4 +121,15 @@ impl Slice { pub fn to_owned(&self) -> Buf { Buf { inner: self.inner.to_vec() } } + + #[inline] + pub fn into_box(&self) -> Box { + let boxed: Box<[u8]> = self.inner.into(); + unsafe { mem::transmute(boxed) } + } + + pub fn empty_box() -> Box { + let boxed: Box<[u8]> = Default::default(); + unsafe { mem::transmute(boxed) } + } } diff --git a/src/libstd/sys/unix/os_str.rs b/src/libstd/sys/unix/os_str.rs index 5a733c0cb8763..938bcfc6d162e 100644 --- a/src/libstd/sys/unix/os_str.rs +++ b/src/libstd/sys/unix/os_str.rs @@ -94,6 +94,11 @@ impl Buf { pub fn push_slice(&mut self, s: &Slice) { self.inner.extend_from_slice(&s.inner) } + + #[inline] + pub fn into_box(self) -> Box { + unsafe { mem::transmute(self.inner.into_boxed_slice()) } + } } impl Slice { @@ -116,4 +121,15 @@ impl Slice { pub fn to_owned(&self) -> Buf { Buf { inner: self.inner.to_vec() } } + + #[inline] + pub fn into_box(&self) -> Box { + let boxed: Box<[u8]> = self.inner.into(); + unsafe { mem::transmute(boxed) } + } + + pub fn empty_box() -> Box { + let boxed: Box<[u8]> = Default::default(); + unsafe { mem::transmute(boxed) } + } } diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index a065c7a7fd013..04e45dcf54963 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -88,6 +88,11 @@ impl Buf { pub fn reserve_exact(&mut self, additional: usize) { self.inner.reserve_exact(additional) } + + #[inline] + pub fn into_box(self) -> Box { + unsafe { mem::transmute(self.inner.into_box()) } + } } impl Slice { @@ -108,4 +113,13 @@ impl Slice { buf.push_wtf8(&self.inner); Buf { inner: buf } } + + #[inline] + pub fn into_box(&self) -> Box { + unsafe { mem::transmute(self.inner.into_box()) } + } + + pub fn empty_box() -> Box { + unsafe { mem::transmute(Wtf8::empty_box()) } + } } diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index 0a94ff1e95823..1d61181a4ee0f 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -340,6 +340,12 @@ impl Wtf8Buf { } } } + + /// Converts this `Wtf8Buf` into a boxed `Wtf8`. + #[inline] + pub fn into_box(self) -> Box { + unsafe { mem::transmute(self.bytes.into_boxed_slice()) } + } } /// Create a new WTF-8 string from an iterator of code points. @@ -583,6 +589,19 @@ impl Wtf8 { _ => None } } + + /// Boxes this `Wtf8`. + #[inline] + pub fn into_box(&self) -> Box { + let boxed: Box<[u8]> = self.bytes.into(); + unsafe { mem::transmute(boxed) } + } + + /// Creates a boxed, empty `Wtf8`. + pub fn empty_box() -> Box { + let boxed: Box<[u8]> = Default::default(); + unsafe { mem::transmute(boxed) } + } }