Skip to content

Commit 257d324

Browse files
committed
Auto merge of #30980 - gereeter:fix-btree-iter-variance, r=apasel422
This takes the approach of making `NodeRef` universally covariant. Fixes #30979.
2 parents d0bac3f + 7a9c4a4 commit 257d324

File tree

4 files changed

+118
-17
lines changed

4 files changed

+118
-17
lines changed

src/libcollections/btree/map.rs

+26-9
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use core::cmp::Ordering;
1212
use core::fmt::Debug;
1313
use core::hash::{Hash, Hasher};
1414
use core::iter::FromIterator;
15+
use core::marker::PhantomData;
1516
use core::ops::Index;
1617
use core::{fmt, intrinsics, mem, ptr};
1718

@@ -158,7 +159,8 @@ impl<K, Q: ?Sized> super::Recover<Q> for BTreeMap<K, ()>
158159
Found(handle) => {
159160
Some(OccupiedEntry {
160161
handle: handle,
161-
length: &mut self.length
162+
length: &mut self.length,
163+
_marker: PhantomData,
162164
}.remove_kv().0)
163165
},
164166
GoDown(_) => None
@@ -172,7 +174,8 @@ impl<K, Q: ?Sized> super::Recover<Q> for BTreeMap<K, ()>
172174
VacantEntry {
173175
key: key,
174176
handle: handle,
175-
length: &mut self.length
177+
length: &mut self.length,
178+
_marker: PhantomData,
176179
}.insert(());
177180
None
178181
}
@@ -223,7 +226,10 @@ pub struct Range<'a, K: 'a, V: 'a> {
223226
/// A mutable iterator over a sub-range of BTreeMap's entries.
224227
pub struct RangeMut<'a, K: 'a, V: 'a> {
225228
front: Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>,
226-
back: Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>
229+
back: Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>,
230+
231+
// Be invariant in `K` and `V`
232+
_marker: PhantomData<&'a mut (K, V)>,
227233
}
228234

229235
/// A view into a single entry in a map, which may either be vacant or occupied.
@@ -247,7 +253,10 @@ pub enum Entry<'a, K: 'a, V: 'a> {
247253
pub struct VacantEntry<'a, K: 'a, V: 'a> {
248254
key: K,
249255
handle: Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>,
250-
length: &'a mut usize
256+
length: &'a mut usize,
257+
258+
// Be invariant in `K` and `V`
259+
_marker: PhantomData<&'a mut (K, V)>,
251260
}
252261

253262
/// An occupied Entry.
@@ -259,7 +268,10 @@ pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
259268
marker::LeafOrInternal
260269
>, marker::KV>,
261270

262-
length: &'a mut usize
271+
length: &'a mut usize,
272+
273+
// Be invariant in `K` and `V`
274+
_marker: PhantomData<&'a mut (K, V)>,
263275
}
264276

265277
impl<K: Ord, V> BTreeMap<K, V> {
@@ -415,7 +427,8 @@ impl<K: Ord, V> BTreeMap<K, V> {
415427
Found(handle) => {
416428
Some(OccupiedEntry {
417429
handle: handle,
418-
length: &mut self.length
430+
length: &mut self.length,
431+
_marker: PhantomData,
419432
}.remove())
420433
},
421434
GoDown(_) => None
@@ -568,7 +581,8 @@ impl<K: Ord, V> BTreeMap<K, V> {
568581

569582
RangeMut {
570583
front: front,
571-
back: back
584+
back: back,
585+
_marker: PhantomData
572586
}
573587
}
574588

@@ -593,12 +607,14 @@ impl<K: Ord, V> BTreeMap<K, V> {
593607
match search::search_tree(self.root.as_mut(), &key) {
594608
Found(handle) => Occupied(OccupiedEntry {
595609
handle: handle,
596-
length: &mut self.length
610+
length: &mut self.length,
611+
_marker: PhantomData,
597612
}),
598613
GoDown(handle) => Vacant(VacantEntry {
599614
key: key,
600615
handle: handle,
601-
length: &mut self.length
616+
length: &mut self.length,
617+
_marker: PhantomData,
602618
})
603619
}
604620
}
@@ -1235,6 +1251,7 @@ impl<K, V> BTreeMap<K, V> {
12351251
range: RangeMut {
12361252
front: first_leaf_edge(root1),
12371253
back: last_leaf_edge(root2),
1254+
_marker: PhantomData,
12381255
},
12391256
length: self.length
12401257
}

src/libcollections/btree/node.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,13 @@ impl<K, V> BoxedNode<K, V> {
9797
}
9898
}
9999

100-
unsafe fn from_ptr(ptr: NonZero<*mut LeafNode<K, V>>) -> Self {
101-
BoxedNode { ptr: Unique::new(*ptr) }
100+
unsafe fn from_ptr(ptr: NonZero<*const LeafNode<K, V>>) -> Self {
101+
BoxedNode { ptr: Unique::new(*ptr as *mut LeafNode<K, V>) }
102102
}
103103

104-
fn as_ptr(&self) -> NonZero<*mut LeafNode<K, V>> {
104+
fn as_ptr(&self) -> NonZero<*const LeafNode<K, V>> {
105105
unsafe {
106-
NonZero::new(*self.ptr)
106+
NonZero::new(*self.ptr as *const LeafNode<K, V>)
107107
}
108108
}
109109
}
@@ -209,6 +209,11 @@ impl<K, V> Root<K, V> {
209209
}
210210
}
211211

212+
// N.B. `NodeRef` is always covariant in `K` and `V`, even when the `BorrowType`
213+
// is `Mut`. This is technically wrong, but cannot result in any unsafety due to
214+
// internal use of `NodeRef` because we stay completely generic over `K` and `V`.
215+
// However, whenever a public type wraps `NodeRef`, make sure that it has the
216+
// correct variance.
212217
/// A reference to a node.
213218
///
214219
/// This type has a number of paramaters that controls how it acts:
@@ -223,8 +228,8 @@ impl<K, V> Root<K, V> {
223228
/// `NodeRef` could be pointing to either type of node.
224229
pub struct NodeRef<BorrowType, K, V, Type> {
225230
height: usize,
226-
node: NonZero<*mut LeafNode<K, V>>,
227-
root: *mut Root<K, V>,
231+
node: NonZero<*const LeafNode<K, V>>,
232+
root: *const Root<K, V>,
228233
_marker: PhantomData<(BorrowType, Type)>
229234
}
230235

@@ -401,7 +406,7 @@ impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
401406

402407
fn as_leaf_mut(&mut self) -> &mut LeafNode<K, V> {
403408
unsafe {
404-
&mut **self.node
409+
&mut *(*self.node as *mut LeafNode<K, V>)
405410
}
406411
}
407412

@@ -434,7 +439,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
434439
impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
435440
pub fn into_root_mut(self) -> &'a mut Root<K, V> {
436441
unsafe {
437-
&mut *self.root
442+
&mut *(self.root as *mut Root<K, V>)
438443
}
439444
}
440445

src/libcollectionstest/btree/map.rs

+16
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,22 @@ fn test_clone() {
378378
}
379379
}
380380

381+
#[test]
382+
fn test_variance() {
383+
use std::collections::btree_map::{Iter, IntoIter, Range, Keys, Values};
384+
385+
fn map_key<'new>(v: BTreeMap<&'static str, ()>) -> BTreeMap<&'new str, ()> { v }
386+
fn map_val<'new>(v: BTreeMap<(), &'static str>) -> BTreeMap<(), &'new str> { v }
387+
fn iter_key<'a, 'new>(v: Iter<'a, &'static str, ()>) -> Iter<'a, &'new str, ()> { v }
388+
fn iter_val<'a, 'new>(v: Iter<'a, (), &'static str>) -> Iter<'a, (), &'new str> { v }
389+
fn into_iter_key<'new>(v: IntoIter<&'static str, ()>) -> IntoIter<&'new str, ()> { v }
390+
fn into_iter_val<'new>(v: IntoIter<(), &'static str>) -> IntoIter<(), &'new str> { v }
391+
fn range_key<'a, 'new>(v: Range<'a, &'static str, ()>) -> Range<'a, &'new str, ()> { v }
392+
fn range_val<'a, 'new>(v: Range<'a, (), &'static str>) -> Range<'a, (), &'new str> { v }
393+
fn keys<'a, 'new>(v: Keys<'a, &'static str, ()>) -> Keys<'a, &'new str, ()> { v }
394+
fn vals<'a, 'new>(v: Values<'a, (), &'static str>) -> Values<'a, (), &'new str> { v }
395+
}
396+
381397
mod bench {
382398
use std::collections::BTreeMap;
383399
use std::__rand::{Rng, thread_rng};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(rustc_attrs)]
12+
13+
use std::collections::btree_map::{IterMut, OccupiedEntry, VacantEntry};
14+
15+
fn iter_cov_key<'a, 'new>(v: IterMut<'a, &'static (), ()>) -> IterMut<'a, &'new (), ()> {
16+
v //~ ERROR mismatched types
17+
}
18+
fn iter_cov_val<'a, 'new>(v: IterMut<'a, (), &'static ()>) -> IterMut<'a, (), &'new ()> {
19+
v //~ ERROR mismatched types
20+
}
21+
fn iter_contra_key<'a, 'new>(v: IterMut<'a, &'new (), ()>) -> IterMut<'a, &'static (), ()> {
22+
v //~ ERROR mismatched types
23+
}
24+
fn iter_contra_val<'a, 'new>(v: IterMut<'a, (), &'new ()>) -> IterMut<'a, (), &'static ()> {
25+
v //~ ERROR mismatched types
26+
}
27+
28+
fn occ_cov_key<'a, 'new>(v: OccupiedEntry<'a, &'static (), ()>)
29+
-> OccupiedEntry<'a, &'new (), ()> {
30+
v //~ ERROR mismatched types
31+
}
32+
fn occ_cov_val<'a, 'new>(v: OccupiedEntry<'a, (), &'static ()>)
33+
-> OccupiedEntry<'a, (), &'new ()> {
34+
v //~ ERROR mismatched types
35+
}
36+
fn occ_contra_key<'a, 'new>(v: OccupiedEntry<'a, &'new (), ()>)
37+
-> OccupiedEntry<'a, &'static (), ()> {
38+
v //~ ERROR mismatched types
39+
}
40+
fn occ_contra_val<'a, 'new>(v: OccupiedEntry<'a, (), &'new ()>)
41+
-> OccupiedEntry<'a, (), &'static ()> {
42+
v //~ ERROR mismatched types
43+
}
44+
45+
fn vac_cov_key<'a, 'new>(v: VacantEntry<'a, &'static (), ()>)
46+
-> VacantEntry<'a, &'new (), ()> {
47+
v //~ ERROR mismatched types
48+
}
49+
fn vac_cov_val<'a, 'new>(v: VacantEntry<'a, (), &'static ()>)
50+
-> VacantEntry<'a, (), &'new ()> {
51+
v //~ ERROR mismatched types
52+
}
53+
fn vac_contra_key<'a, 'new>(v: VacantEntry<'a, &'new (), ()>)
54+
-> VacantEntry<'a, &'static (), ()> {
55+
v //~ ERROR mismatched types
56+
}
57+
fn vac_contra_val<'a, 'new>(v: VacantEntry<'a, (), &'new ()>)
58+
-> VacantEntry<'a, (), &'static ()> {
59+
v //~ ERROR mismatched types
60+
}
61+
62+
#[rustc_error]
63+
fn main() { }

0 commit comments

Comments
 (0)