From 1ce9257ebd184d079af40a72fd1a618893743ec9 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Mon, 6 Apr 2020 18:09:08 +0200 Subject: [PATCH 01/11] ci: move /var/lib/docker to /mnt on GHA There are some builders that are running out of disk space while building the Docker images, such as arm-android. This moves and symlinks /var/lib/docker to the /mnt partition on Linux GHA. --- src/ci/scripts/symlink-build-dir.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ci/scripts/symlink-build-dir.sh b/src/ci/scripts/symlink-build-dir.sh index c77059c00ac..50178b9c33e 100755 --- a/src/ci/scripts/symlink-build-dir.sh +++ b/src/ci/scripts/symlink-build-dir.sh @@ -24,4 +24,10 @@ elif isLinux && isGitHubActions; then mv "${current_dir}" /mnt/more-space/workspace ln -s /mnt/more-space/workspace "${current_dir}" cd "${current_dir}" + + # Move the Docker data directory to /mnt + sudo systemctl stop docker.service + sudo mv /var/lib/docker /mnt/docker + sudo ln -s /mnt/docker /var/lib/docker + sudo systemctl start docker.service fi From bdbe56ecb837ce462f99508837ff66fc09d23cd8 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Sat, 4 Apr 2020 20:32:07 +0200 Subject: [PATCH 02/11] BTreeMap first/last: simplify implementations --- src/liballoc/collections/btree/map.rs | 54 ++++++++------------------- 1 file changed, 16 insertions(+), 38 deletions(-) diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 70968964f47..c782fb4f6a9 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -653,11 +653,7 @@ impl BTreeMap { /// assert_eq!(map.first_key_value(), Some((&1, &"b"))); /// ``` #[unstable(feature = "map_first_last", issue = "62924")] - pub fn first_key_value(&self) -> Option<(&K, &V)> - where - T: Ord, - K: Borrow, - { + pub fn first_key_value(&self) -> Option<(&K, &V)> { let front = self.root.as_ref()?.as_ref().first_leaf_edge(); front.right_kv().ok().map(Handle::into_kv) } @@ -682,21 +678,14 @@ impl BTreeMap { /// } /// ``` #[unstable(feature = "map_first_last", issue = "62924")] - pub fn first_entry(&mut self) -> Option> - where - T: Ord, - K: Borrow, - { + pub fn first_entry(&mut self) -> Option> { let front = self.root.as_mut()?.as_mut().first_leaf_edge(); - if let Ok(kv) = front.right_kv() { - Some(OccupiedEntry { - handle: kv.forget_node_type(), - length: &mut self.length, - _marker: PhantomData, - }) - } else { - None - } + let kv = front.right_kv().ok()?; + Some(OccupiedEntry { + handle: kv.forget_node_type(), + length: &mut self.length, + _marker: PhantomData, + }) } /// Returns the last key-value pair in the map. @@ -716,11 +705,7 @@ impl BTreeMap { /// assert_eq!(map.last_key_value(), Some((&2, &"a"))); /// ``` #[unstable(feature = "map_first_last", issue = "62924")] - pub fn last_key_value(&self) -> Option<(&K, &V)> - where - T: Ord, - K: Borrow, - { + pub fn last_key_value(&self) -> Option<(&K, &V)> { let back = self.root.as_ref()?.as_ref().last_leaf_edge(); back.left_kv().ok().map(Handle::into_kv) } @@ -745,21 +730,14 @@ impl BTreeMap { /// } /// ``` #[unstable(feature = "map_first_last", issue = "62924")] - pub fn last_entry(&mut self) -> Option> - where - T: Ord, - K: Borrow, - { + pub fn last_entry(&mut self) -> Option> { let back = self.root.as_mut()?.as_mut().last_leaf_edge(); - if let Ok(kv) = back.left_kv() { - Some(OccupiedEntry { - handle: kv.forget_node_type(), - length: &mut self.length, - _marker: PhantomData, - }) - } else { - None - } + let kv = back.left_kv().ok()?; + Some(OccupiedEntry { + handle: kv.forget_node_type(), + length: &mut self.length, + _marker: PhantomData, + }) } /// Returns `true` if the map contains a value for the specified key. From c23ee767d94a8ea5e0aa782731f89f4e00fbdc7e Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Mon, 6 Apr 2020 19:03:18 +0200 Subject: [PATCH 03/11] BTreeMap first/last: make examples more to the point --- src/liballoc/collections/btree/map.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index c782fb4f6a9..d550856b6ed 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -663,8 +663,6 @@ impl BTreeMap { /// /// # Examples /// - /// Contrived way to `clear` a map: - /// /// ``` /// #![feature(map_first_last)] /// use std::collections::BTreeMap; @@ -672,10 +670,13 @@ impl BTreeMap { /// let mut map = BTreeMap::new(); /// map.insert(1, "a"); /// map.insert(2, "b"); - /// while let Some(entry) = map.first_entry() { - /// let (key, val) = entry.remove_entry(); - /// assert!(!map.contains_key(&key)); + /// if let Some(mut entry) = map.first_entry() { + /// if *entry.key() > 0 { + /// entry.insert("first"); + /// } /// } + /// assert_eq!(*map.get(&1).unwrap(), "first"); + /// assert_eq!(*map.get(&2).unwrap(), "b"); /// ``` #[unstable(feature = "map_first_last", issue = "62924")] pub fn first_entry(&mut self) -> Option> { @@ -715,8 +716,6 @@ impl BTreeMap { /// /// # Examples /// - /// Contrived way to `clear` a map: - /// /// ``` /// #![feature(map_first_last)] /// use std::collections::BTreeMap; @@ -724,10 +723,13 @@ impl BTreeMap { /// let mut map = BTreeMap::new(); /// map.insert(1, "a"); /// map.insert(2, "b"); - /// while let Some(entry) = map.last_entry() { - /// let (key, val) = entry.remove_entry(); - /// assert!(!map.contains_key(&key)); + /// if let Some(mut entry) = map.last_entry() { + /// if *entry.key() > 0 { + /// entry.insert("last"); + /// } /// } + /// assert_eq!(*map.get(&1).unwrap(), "a"); + /// assert_eq!(*map.get(&2).unwrap(), "last"); /// ``` #[unstable(feature = "map_first_last", issue = "62924")] pub fn last_entry(&mut self) -> Option> { From 8212b9772e486ae272639fb22ee3b6e7f9047d3f Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Sun, 5 Apr 2020 18:56:07 +0200 Subject: [PATCH 04/11] BTreeMap first/last: add pop methods --- src/liballoc/collections/btree/map.rs | 48 +++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index d550856b6ed..a1e59b2e6af 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -689,6 +689,30 @@ impl BTreeMap { }) } + /// Removes and returns the first element in the map. + /// The key of this element is the minimum key that was in the map. + /// + /// # Examples + /// + /// Draining elements in ascending order, while keeping a usable map each iteration. + /// + /// ``` + /// #![feature(map_first_last)] + /// use std::collections::BTreeMap; + /// + /// let mut map = BTreeMap::new(); + /// map.insert(1, "a"); + /// map.insert(2, "b"); + /// while let Some((key, _val)) = map.pop_first() { + /// assert!(map.iter().all(|(k, _v)| *k > key)); + /// } + /// assert!(map.is_empty()); + /// ``` + #[unstable(feature = "map_first_last", issue = "62924")] + pub fn pop_first(&mut self) -> Option<(K, V)> { + self.first_entry().map(|entry| entry.remove_entry()) + } + /// Returns the last key-value pair in the map. /// The key in this pair is the maximum key in the map. /// @@ -742,6 +766,30 @@ impl BTreeMap { }) } + /// Removes and returns the last element in the map. + /// The key of this element is the maximum key that was in the map. + /// + /// # Examples + /// + /// Draining elements in descending order, while keeping a usable map each iteration. + /// + /// ``` + /// #![feature(map_first_last)] + /// use std::collections::BTreeMap; + /// + /// let mut map = BTreeMap::new(); + /// map.insert(1, "a"); + /// map.insert(2, "b"); + /// while let Some((key, _val)) = map.pop_last() { + /// assert!(map.iter().all(|(k, _v)| *k < key)); + /// } + /// assert!(map.is_empty()); + /// ``` + #[unstable(feature = "map_first_last", issue = "62924")] + pub fn pop_last(&mut self) -> Option<(K, V)> { + self.last_entry().map(|entry| entry.remove_entry()) + } + /// Returns `true` if the map contains a value for the specified key. /// /// The key may be any borrowed form of the map's key type, but the ordering From a90661a780134439fefdd17e42576b946d7102d5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 7 Apr 2020 15:12:50 +1000 Subject: [PATCH 05/11] Use a `SmallVec` for `Cache::predecessors`. This is a very small win. --- src/librustc_middle/mir/cache.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/librustc_middle/mir/cache.rs b/src/librustc_middle/mir/cache.rs index 00ecc7a7a0a..af0f7efc3e3 100644 --- a/src/librustc_middle/mir/cache.rs +++ b/src/librustc_middle/mir/cache.rs @@ -5,13 +5,15 @@ use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_index::vec::IndexVec; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; +use smallvec::SmallVec; use std::iter; use std::ops::{Deref, DerefMut, Index, IndexMut}; use std::vec::IntoIter; #[derive(Clone, Debug)] pub struct Cache { - predecessors: Option>>, + // Typically 95%+ of the inner vectors have 4 or fewer elements. + predecessors: Option>>, } impl rustc_serialize::Encodable for Cache { @@ -44,7 +46,7 @@ impl Cache { pub fn ensure_predecessors(&mut self, body: &Body<'_>) { if self.predecessors.is_none() { - let mut result = IndexVec::from_elem(vec![], body.basic_blocks()); + let mut result = IndexVec::from_elem(smallvec![], body.basic_blocks()); for (bb, data) in body.basic_blocks().iter_enumerated() { if let Some(ref term) = data.terminator { for &tgt in term.successors() { @@ -58,7 +60,11 @@ impl Cache { } /// This will recompute the predecessors cache if it is not available - fn predecessors(&mut self, body: &Body<'_>) -> &IndexVec> { + // njn: typedef? + fn predecessors( + &mut self, + body: &Body<'_>, + ) -> &IndexVec> { self.ensure_predecessors(body); self.predecessors.as_ref().unwrap() } @@ -137,7 +143,7 @@ impl BodyAndCache<'tcx> { self.cache.ensure_predecessors(&self.body); } - pub fn predecessors(&mut self) -> &IndexVec> { + pub fn predecessors(&mut self) -> &IndexVec> { self.cache.predecessors(&self.body) } @@ -199,7 +205,7 @@ impl ReadOnlyBodyAndCache<'a, 'tcx> { Self { body, cache } } - pub fn predecessors(&self) -> &IndexVec> { + pub fn predecessors(&self) -> &IndexVec> { self.cache.predecessors.as_ref().unwrap() } From 6569a2ec1bef59bd409b13967278c95afb4bec28 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 7 Apr 2020 14:07:57 +0200 Subject: [PATCH 06/11] Clean up E0507 explanation --- src/librustc_error_codes/error_codes/E0507.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0507.md b/src/librustc_error_codes/error_codes/E0507.md index 1e3457e96c5..254751fc45e 100644 --- a/src/librustc_error_codes/error_codes/E0507.md +++ b/src/librustc_error_codes/error_codes/E0507.md @@ -1,9 +1,4 @@ -You tried to move out of a value which was borrowed. - -This can also happen when using a type implementing `Fn` or `FnMut`, as neither -allows moving out of them (they usually represent closures which can be called -more than once). Much of the text following applies equally well to non-`FnOnce` -closure bodies. +A borrowed value was moved out. Erroneous code example: @@ -32,6 +27,11 @@ you have three choices: * Somehow reclaim the ownership. * Implement the `Copy` trait on the type. +This can also happen when using a type implementing `Fn` or `FnMut`, as neither +allows moving out of them (they usually represent closures which can be called +more than once). Much of the text following applies equally well to non-`FnOnce` +closure bodies. + Examples: ``` From ab4178bd7db366004c60381c254797575b042fe5 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 7 Apr 2020 17:49:02 +0200 Subject: [PATCH 07/11] wf: refactor `compute_trait_ref` --- src/librustc_trait_selection/traits/wf.rs | 306 +++++++++++----------- 1 file changed, 151 insertions(+), 155 deletions(-) diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index 6b38749e1e7..d506ddab909 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -134,6 +134,152 @@ enum Elaborate { None, } +fn extend_cause_with_original_assoc_item_obligation<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ref: &ty::TraitRef<'tcx>, + item: Option<&hir::Item<'tcx>>, + cause: &mut traits::ObligationCause<'tcx>, + pred: &ty::Predicate<'_>, + mut trait_assoc_items: impl Iterator, +) { + let trait_item = + tcx.hir().as_local_hir_id(trait_ref.def_id).and_then(|trait_id| tcx.hir().find(trait_id)); + let (trait_name, trait_generics) = match trait_item { + Some(hir::Node::Item(hir::Item { + ident, + kind: hir::ItemKind::Trait(.., generics, _, _), + .. + })) + | Some(hir::Node::Item(hir::Item { + ident, + kind: hir::ItemKind::TraitAlias(generics, _), + .. + })) => (Some(ident), Some(generics)), + _ => (None, None), + }; + + let item_span = item.map(|i| tcx.sess.source_map().guess_head_span(i.span)); + match pred { + ty::Predicate::Projection(proj) => { + // The obligation comes not from the current `impl` nor the `trait` being + // implemented, but rather from a "second order" obligation, like in + // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs`: + // + // error[E0271]: type mismatch resolving `::Ok == ()` + // --> $DIR/point-at-type-on-obligation-failure.rs:13:5 + // | + // LL | type Ok; + // | -- associated type defined here + // ... + // LL | impl Bar for Foo { + // | ---------------- in this `impl` item + // LL | type Ok = (); + // | ^^^^^^^^^^^^^ expected `u32`, found `()` + // | + // = note: expected type `u32` + // found type `()` + // + // FIXME: we would want to point a span to all places that contributed to this + // obligation. In the case above, it should be closer to: + // + // error[E0271]: type mismatch resolving `::Ok == ()` + // --> $DIR/point-at-type-on-obligation-failure.rs:13:5 + // | + // LL | type Ok; + // | -- associated type defined here + // LL | type Sibling: Bar2; + // | -------------------------------- obligation set here + // ... + // LL | impl Bar for Foo { + // | ---------------- in this `impl` item + // LL | type Ok = (); + // | ^^^^^^^^^^^^^ expected `u32`, found `()` + // ... + // LL | impl Bar2 for Foo2 { + // | ---------------- in this `impl` item + // LL | type Ok = u32; + // | -------------- obligation set here + // | + // = note: expected type `u32` + // found type `()` + if let Some(hir::ItemKind::Impl { items, .. }) = item.map(|i| &i.kind) { + let trait_assoc_item = tcx.associated_item(proj.projection_def_id()); + if let Some(impl_item) = + items.iter().find(|item| item.ident == trait_assoc_item.ident) + { + cause.span = impl_item.span; + cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData { + impl_span: item_span, + original: trait_assoc_item.ident.span, + bounds: vec![], + })); + } + } + } + ty::Predicate::Trait(proj, _) => { + // An associated item obligation born out of the `trait` failed to be met. + // Point at the `impl` that failed the obligation, the associated item that + // needed to meet the obligation, and the definition of that associated item, + // which should hold the obligation in most cases. An example can be seen in + // `src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs`: + // + // error[E0277]: the trait bound `bool: Bar` is not satisfied + // --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5 + // | + // LL | type Assoc: Bar; + // | ----- associated type defined here + // ... + // LL | impl Foo for () { + // | --------------- in this `impl` item + // LL | type Assoc = bool; + // | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool` + // + // If the obligation comes from the where clause in the `trait`, we point at it: + // + // error[E0277]: the trait bound `bool: Bar` is not satisfied + // --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5 + // | + // | trait Foo where >::Assoc: Bar { + // | -------------------------- restricted in this bound + // LL | type Assoc; + // | ----- associated type defined here + // ... + // LL | impl Foo for () { + // | --------------- in this `impl` item + // LL | type Assoc = bool; + // | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool` + if let ( + ty::Projection(ty::ProjectionTy { item_def_id, .. }), + Some(hir::ItemKind::Impl { items, .. }), + ) = (&proj.skip_binder().self_ty().kind, item.map(|i| &i.kind)) + { + if let Some((impl_item, trait_assoc_item)) = trait_assoc_items + .find(|i| i.def_id == *item_def_id) + .and_then(|trait_assoc_item| { + items + .iter() + .find(|i| i.ident == trait_assoc_item.ident) + .map(|impl_item| (impl_item, trait_assoc_item)) + }) + { + let bounds = trait_generics + .map(|generics| { + get_generic_bound_spans(&generics, trait_name, trait_assoc_item.ident) + }) + .unwrap_or_else(Vec::new); + cause.span = impl_item.span; + cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData { + impl_span: item_span, + original: trait_assoc_item.ident.span, + bounds, + })); + } + } + } + _ => {} + } +} + impl<'a, 'tcx> WfPredicates<'a, 'tcx> { fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { traits::ObligationCause::new(self.span, self.body_id, code) @@ -163,170 +309,20 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let cause = self.cause(traits::MiscObligation); let param_env = self.param_env; - let item = &self.item; - let extend_cause_with_original_assoc_item_obligation = - |cause: &mut traits::ObligationCause<'_>, - pred: &ty::Predicate<'_>, - trait_assoc_items: &[ty::AssocItem]| { - let trait_item = tcx - .hir() - .as_local_hir_id(trait_ref.def_id) - .and_then(|trait_id| tcx.hir().find(trait_id)); - let (trait_name, trait_generics) = match trait_item { - Some(hir::Node::Item(hir::Item { - ident, - kind: hir::ItemKind::Trait(.., generics, _, _), - .. - })) - | Some(hir::Node::Item(hir::Item { - ident, - kind: hir::ItemKind::TraitAlias(generics, _), - .. - })) => (Some(ident), Some(generics)), - _ => (None, None), - }; - - let item_span = item.map(|i| tcx.sess.source_map().guess_head_span(i.span)); - match pred { - ty::Predicate::Projection(proj) => { - // The obligation comes not from the current `impl` nor the `trait` being - // implemented, but rather from a "second order" obligation, like in - // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs`: - // - // error[E0271]: type mismatch resolving `::Ok == ()` - // --> $DIR/point-at-type-on-obligation-failure.rs:13:5 - // | - // LL | type Ok; - // | -- associated type defined here - // ... - // LL | impl Bar for Foo { - // | ---------------- in this `impl` item - // LL | type Ok = (); - // | ^^^^^^^^^^^^^ expected `u32`, found `()` - // | - // = note: expected type `u32` - // found type `()` - // - // FIXME: we would want to point a span to all places that contributed to this - // obligation. In the case above, it should be closer to: - // - // error[E0271]: type mismatch resolving `::Ok == ()` - // --> $DIR/point-at-type-on-obligation-failure.rs:13:5 - // | - // LL | type Ok; - // | -- associated type defined here - // LL | type Sibling: Bar2; - // | -------------------------------- obligation set here - // ... - // LL | impl Bar for Foo { - // | ---------------- in this `impl` item - // LL | type Ok = (); - // | ^^^^^^^^^^^^^ expected `u32`, found `()` - // ... - // LL | impl Bar2 for Foo2 { - // | ---------------- in this `impl` item - // LL | type Ok = u32; - // | -------------- obligation set here - // | - // = note: expected type `u32` - // found type `()` - if let Some(hir::ItemKind::Impl { items, .. }) = item.map(|i| &i.kind) { - let trait_assoc_item = tcx.associated_item(proj.projection_def_id()); - if let Some(impl_item) = - items.iter().find(|item| item.ident == trait_assoc_item.ident) - { - cause.span = impl_item.span; - cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData { - impl_span: item_span, - original: trait_assoc_item.ident.span, - bounds: vec![], - })); - } - } - } - ty::Predicate::Trait(proj, _) => { - // An associated item obligation born out of the `trait` failed to be met. - // Point at the `impl` that failed the obligation, the associated item that - // needed to meet the obligation, and the definition of that associated item, - // which should hold the obligation in most cases. An example can be seen in - // `src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs`: - // - // error[E0277]: the trait bound `bool: Bar` is not satisfied - // --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5 - // | - // LL | type Assoc: Bar; - // | ----- associated type defined here - // ... - // LL | impl Foo for () { - // | --------------- in this `impl` item - // LL | type Assoc = bool; - // | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool` - // - // If the obligation comes from the where clause in the `trait`, we point at it: - // - // error[E0277]: the trait bound `bool: Bar` is not satisfied - // --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5 - // | - // | trait Foo where >::Assoc: Bar { - // | -------------------------- restricted in this bound - // LL | type Assoc; - // | ----- associated type defined here - // ... - // LL | impl Foo for () { - // | --------------- in this `impl` item - // LL | type Assoc = bool; - // | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool` - if let ( - ty::Projection(ty::ProjectionTy { item_def_id, .. }), - Some(hir::ItemKind::Impl { items, .. }), - ) = (&proj.skip_binder().self_ty().kind, item.map(|i| &i.kind)) - { - if let Some((impl_item, trait_assoc_item)) = trait_assoc_items - .iter() - .find(|i| i.def_id == *item_def_id) - .and_then(|trait_assoc_item| { - items - .iter() - .find(|i| i.ident == trait_assoc_item.ident) - .map(|impl_item| (impl_item, trait_assoc_item)) - }) - { - let bounds = trait_generics - .map(|generics| { - get_generic_bound_spans( - &generics, - trait_name, - trait_assoc_item.ident, - ) - }) - .unwrap_or_else(Vec::new); - cause.span = impl_item.span; - cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData { - impl_span: item_span, - original: trait_assoc_item.ident.span, - bounds, - })); - } - } - } - _ => {} - } - }; + let item = self.item; if let Elaborate::All = elaborate { - // FIXME: Make `extend_cause_with_original_assoc_item_obligation` take an iterator - // instead of a slice. - let trait_assoc_items: Vec<_> = - tcx.associated_items(trait_ref.def_id).in_definition_order().copied().collect(); - let predicates = obligations.iter().map(|obligation| obligation.predicate).collect(); let implied_obligations = traits::elaborate_predicates(tcx, predicates); let implied_obligations = implied_obligations.map(|pred| { let mut cause = cause.clone(); extend_cause_with_original_assoc_item_obligation( + tcx, + trait_ref, + item, &mut cause, &pred, - &*trait_assoc_items, + tcx.associated_items(trait_ref.def_id).in_definition_order().copied(), ); traits::Obligation::new(cause, param_env, pred) }); From 817f05986ae77538e5721223a55b14cd780dbd73 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 4 Apr 2020 22:40:31 +0200 Subject: [PATCH 08/11] remove false positives of unused_braces --- src/librustc_lint/unused.rs | 26 ++++++++++++++-- src/test/ui/lint/unused_braces.rs | 31 +++++++++++++++---- src/test/ui/lint/unused_braces.stderr | 26 ++++++++++------ ...rens_borrow.rs => unused_braces_borrow.rs} | 6 ++-- ...row.stderr => unused_braces_borrow.stderr} | 8 ++--- 5 files changed, 72 insertions(+), 25 deletions(-) rename src/test/ui/lint/{unused_parens_borrow.rs => unused_braces_borrow.rs} (81%) rename src/test/ui/lint/{unused_parens_borrow.stderr => unused_braces_borrow.stderr} (50%) diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index c74b399555a..aa7c87e9f7b 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -355,6 +355,19 @@ impl From for &'static str { trait UnusedDelimLint { const DELIM_STR: &'static str; + /// Due to `ref` pattern, there can be a difference between using + /// `{ expr }` and `expr` in pattern-matching contexts. This means + /// that we should only lint `unused_parens` and not `unused_braces` + /// in this case. + /// + /// ```rust + /// let mut a = 7; + /// let ref b = { a }; // We actually borrow a copy of `a` here. + /// a += 1; // By mutating `a` we invalidate any borrows of `a`. + /// assert_eq!(b + 1, a); // `b` does not borrow `a`, so we can still use it here. + /// ``` + const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool; + // this cannot be a constant is it refers to a static. fn lint(&self) -> &'static Lint; @@ -454,7 +467,10 @@ trait UnusedDelimLint { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { use rustc_ast::ast::ExprKind::*; let (value, ctx, followed_by_block, left_pos, right_pos) = match e.kind { - If(ref cond, ref block, ..) => { + // Do not lint `unused_braces` in `if let` expressions. + If(ref cond, ref block, ..) + if !matches!(cond.kind, Let(_, _)) || Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => + { let left = e.span.lo() + rustc_span::BytePos(2); let right = block.span.lo(); (cond, UnusedDelimsCtx::IfCond, true, Some(left), Some(right)) @@ -470,7 +486,7 @@ trait UnusedDelimLint { (cond, UnusedDelimsCtx::ForIterExpr, true, None, Some(block.span.lo())) } - Match(ref head, _) => { + Match(ref head, _) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => { let left = e.span.lo() + rustc_span::BytePos(5); (head, UnusedDelimsCtx::MatchScrutineeExpr, true, Some(left), None) } @@ -512,7 +528,7 @@ trait UnusedDelimLint { fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) { match s.kind { - StmtKind::Local(ref local) => { + StmtKind::Local(ref local) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => { if let Some(ref value) = local.init { self.check_unused_delims_expr( cx, @@ -565,6 +581,8 @@ declare_lint_pass!(UnusedParens => [UNUSED_PARENS]); impl UnusedDelimLint for UnusedParens { const DELIM_STR: &'static str = "parentheses"; + const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool = true; + fn lint(&self) -> &'static Lint { UNUSED_PARENS } @@ -736,6 +754,8 @@ declare_lint_pass!(UnusedBraces => [UNUSED_BRACES]); impl UnusedDelimLint for UnusedBraces { const DELIM_STR: &'static str = "braces"; + const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool = false; + fn lint(&self) -> &'static Lint { UNUSED_BRACES } diff --git a/src/test/ui/lint/unused_braces.rs b/src/test/ui/lint/unused_braces.rs index de456ee6c23..952398ef068 100644 --- a/src/test/ui/lint/unused_braces.rs +++ b/src/test/ui/lint/unused_braces.rs @@ -1,29 +1,48 @@ // check-pass #![warn(unused_braces, unused_parens)] +fn consume(_: T) {} + fn main() { let _ = (7); //~^WARN unnecessary parentheses - let _ = { 7 }; - //~^ WARN unnecessary braces + // Do not emit a lint in these cases, + // as we have to be careful with + // `ref` patterns. + { + let _ = { 7 }; - if let 7 = { 7 } { + if let 7 = { 7 } { } + + match { 7 } { + _ => (), + } + } + + if { true } { + //~^ WARN unnecessary braces + } + + while { false } { //~^ WARN unnecessary braces } let _: [u8; { 3 }]; //~^ WARN unnecessary braces - // do not emit error for multiline blocks. + consume({ 7 }); + //~^ WARN unnecessary braces + + // Do not emit lint for multiline blocks. let _ = { 7 }; - // do not emit error for unsafe blocks. + // Do not emit lint for unsafe blocks. let _ = unsafe { 7 }; - // do not emit error, as the `{` would then + // Do not emit lint, as the `{` would then // be parsed as part of the `return`. if { return } { diff --git a/src/test/ui/lint/unused_braces.stderr b/src/test/ui/lint/unused_braces.stderr index 72f425ffc3e..f195c002418 100644 --- a/src/test/ui/lint/unused_braces.stderr +++ b/src/test/ui/lint/unused_braces.stderr @@ -1,5 +1,5 @@ warning: unnecessary parentheses around assigned value - --> $DIR/unused_braces.rs:5:13 + --> $DIR/unused_braces.rs:7:13 | LL | let _ = (7); | ^^^ help: remove these parentheses @@ -10,11 +10,11 @@ note: the lint level is defined here LL | #![warn(unused_braces, unused_parens)] | ^^^^^^^^^^^^^ -warning: unnecessary braces around assigned value - --> $DIR/unused_braces.rs:8:13 +warning: unnecessary braces around `if` condition + --> $DIR/unused_braces.rs:23:8 | -LL | let _ = { 7 }; - | ^^^^^ help: remove these braces +LL | if { true } { + | ^^^^^^^^ help: remove these braces | note: the lint level is defined here --> $DIR/unused_braces.rs:2:9 @@ -22,15 +22,21 @@ note: the lint level is defined here LL | #![warn(unused_braces, unused_parens)] | ^^^^^^^^^^^^^ -warning: unnecessary braces around `let` scrutinee expression - --> $DIR/unused_braces.rs:11:16 +warning: unnecessary braces around `while` condition + --> $DIR/unused_braces.rs:27:11 | -LL | if let 7 = { 7 } { - | ^^^^^ help: remove these braces +LL | while { false } { + | ^^^^^^^^^ help: remove these braces warning: unnecessary braces around const expression - --> $DIR/unused_braces.rs:15:17 + --> $DIR/unused_braces.rs:31:17 | LL | let _: [u8; { 3 }]; | ^^^^^ help: remove these braces +warning: unnecessary braces around function argument + --> $DIR/unused_braces.rs:34:13 + | +LL | consume({ 7 }); + | ^^^^^ help: remove these braces + diff --git a/src/test/ui/lint/unused_parens_borrow.rs b/src/test/ui/lint/unused_braces_borrow.rs similarity index 81% rename from src/test/ui/lint/unused_parens_borrow.rs rename to src/test/ui/lint/unused_braces_borrow.rs index 98dbbecfedd..d0b059744e1 100644 --- a/src/test/ui/lint/unused_parens_borrow.rs +++ b/src/test/ui/lint/unused_braces_borrow.rs @@ -10,13 +10,15 @@ struct A { b: u32, } +fn consume(_: T) {} + fn main() { let a = A { a: 42, b: 1729, }; - let _ = &{ a.b }; - let _ = { a.b }; + consume(&{ a.b }); + consume({ a.b }); //~^ WARN unnecessary braces } diff --git a/src/test/ui/lint/unused_parens_borrow.stderr b/src/test/ui/lint/unused_braces_borrow.stderr similarity index 50% rename from src/test/ui/lint/unused_parens_borrow.stderr rename to src/test/ui/lint/unused_braces_borrow.stderr index 7e3839ae4e0..82fb4375611 100644 --- a/src/test/ui/lint/unused_parens_borrow.stderr +++ b/src/test/ui/lint/unused_braces_borrow.stderr @@ -1,11 +1,11 @@ -warning: unnecessary braces around assigned value - --> $DIR/unused_parens_borrow.rs:20:13 +warning: unnecessary braces around function argument + --> $DIR/unused_braces_borrow.rs:22:13 | -LL | let _ = { a.b }; +LL | consume({ a.b }); | ^^^^^^^ help: remove these braces | note: the lint level is defined here - --> $DIR/unused_parens_borrow.rs:2:9 + --> $DIR/unused_braces_borrow.rs:2:9 | LL | #![warn(unused_braces)] | ^^^^^^^^^^^^^ From d55c3998e07032d01e6e68874f9f7e66b2866081 Mon Sep 17 00:00:00 2001 From: Theo Sandstrom Date: Tue, 7 Apr 2020 18:23:49 -0400 Subject: [PATCH 09/11] Corrects a typo in rustdoc documentation. Fixes rust-lang#70856 --- src/doc/rustdoc/src/documentation-tests.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/rustdoc/src/documentation-tests.md b/src/doc/rustdoc/src/documentation-tests.md index 78181156e25..efadae1c5fb 100644 --- a/src/doc/rustdoc/src/documentation-tests.md +++ b/src/doc/rustdoc/src/documentation-tests.md @@ -352,9 +352,9 @@ are added. /// ``` ``` -`edition2018` tells `rustdoc` that the code sample should be compiled the 2018 -edition of Rust. Similarly, you can specify `edition2015` to compile the code -with the 2015 edition. +`edition2018` tells `rustdoc` that the code sample should be compiled using +the 2018 edition of Rust. Similarly, you can specify `edition2015` to compile +the code with the 2015 edition. ## Syntax reference From 4cdb2065eff17ffbaa72181b63ff2827ef76720c Mon Sep 17 00:00:00 2001 From: Theo Sandstrom Date: Tue, 7 Apr 2020 21:57:31 -0400 Subject: [PATCH 10/11] Remove unnecessary TypeFlags::NOMINAL_FLAGS This was a relic from when we had "nominal flags" and "cached properties." The latter no longer exists, so nominal flags are no longer necessary. In fact, every flag is considered a nominal flag. I went ahead and removed all references to NOMINAL_FLAGS. Fixes rust-lang#70836 --- src/librustc_middle/ty/flags.rs | 2 +- src/librustc_middle/ty/mod.rs | 23 ----------------------- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/src/librustc_middle/ty/flags.rs b/src/librustc_middle/ty/flags.rs index 99a6511b297..7c3c96348b5 100644 --- a/src/librustc_middle/ty/flags.rs +++ b/src/librustc_middle/ty/flags.rs @@ -28,7 +28,7 @@ impl FlagComputation { } fn add_flags(&mut self, flags: TypeFlags) { - self.flags = self.flags | (flags & TypeFlags::NOMINAL_FLAGS); + self.flags = self.flags | flags; } /// indicates that `self` refers to something at binding level `binder` diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 1870856150f..57ac18185d0 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -598,29 +598,6 @@ bitflags! { /// Does this value have parameters/placeholders/inference variables which could be /// replaced later, in a way that would change the results of `impl` specialization? const STILL_FURTHER_SPECIALIZABLE = 1 << 18; - - /// Flags representing the nominal content of a type, - /// computed by FlagsComputation. If you add a new nominal - /// flag, it should be added here too. - const NOMINAL_FLAGS = TypeFlags::HAS_TY_PARAM.bits - | TypeFlags::HAS_RE_PARAM.bits - | TypeFlags::HAS_CT_PARAM.bits - | TypeFlags::HAS_TY_INFER.bits - | TypeFlags::HAS_RE_INFER.bits - | TypeFlags::HAS_CT_INFER.bits - | TypeFlags::HAS_TY_PLACEHOLDER.bits - | TypeFlags::HAS_RE_PLACEHOLDER.bits - | TypeFlags::HAS_CT_PLACEHOLDER.bits - | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits - | TypeFlags::HAS_TY_PROJECTION.bits - | TypeFlags::HAS_TY_OPAQUE.bits - | TypeFlags::HAS_CT_PROJECTION.bits - | TypeFlags::KEEP_IN_LOCAL_TCX.bits - | TypeFlags::HAS_TY_ERR.bits - | TypeFlags::HAS_FREE_REGIONS.bits - | TypeFlags::HAS_RE_LATE_BOUND.bits - | TypeFlags::HAS_RE_ERASED.bits - | TypeFlags::STILL_FURTHER_SPECIALIZABLE.bits; } } From 80e3126ec1134d81dca7c698d88156307a50a3ba Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 8 Apr 2020 15:05:52 +0200 Subject: [PATCH 11/11] Clean up E0510 explanation --- src/librustc_error_codes/error_codes/E0510.md | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0510.md b/src/librustc_error_codes/error_codes/E0510.md index d5be417888b..e045e04bdbe 100644 --- a/src/librustc_error_codes/error_codes/E0510.md +++ b/src/librustc_error_codes/error_codes/E0510.md @@ -1,16 +1,29 @@ -Cannot mutate place in this match guard. +The matched value was assigned in a match guard. -When matching on a variable it cannot be mutated in the match guards, as this -could cause the match to be non-exhaustive: +Erroneous code example: ```compile_fail,E0510 let mut x = Some(0); match x { - None => (), - Some(_) if { x = None; false } => (), - Some(v) => (), // No longer matches + None => {} + Some(_) if { x = None; false } => {} // error! + Some(_) => {} } ``` +When matching on a variable it cannot be mutated in the match guards, as this +could cause the match to be non-exhaustive. + Here executing `x = None` would modify the value being matched and require us -to go "back in time" to the `None` arm. +to go "back in time" to the `None` arm. To fix it, change the value in the match +arm: + +``` +let mut x = Some(0); +match x { + None => {} + Some(_) => { + x = None; // ok! + } +} +```