Auto merge of #70931 - Dylan-DPC:rollup-f8orcao, r=Dylan-DPC
Rollup of 9 pull requests Successful merges: - #70789 (remove false positives of unused_braces) - #70847 (ci: move /var/lib/docker to /mnt on GHA) - #70850 (BTreeMap first last proposal tweaks) - #70876 (Use a `SmallVec` for `Cache::predecessors`.) - #70883 (Clean up E0507 explanation) - #70892 (wf: refactor `compute_trait_ref`) - #70914 (Corrects a typo in rustdoc documentation.) - #70915 (Remove unnecessary TypeFlags::NOMINAL_FLAGS) - #70927 (Clean up E0510 explanation) Failed merges: r? @ghost
This commit is contained in:
commit
485c5fb6e1
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -653,11 +653,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
||||
/// assert_eq!(map.first_key_value(), Some((&1, &"b")));
|
||||
/// ```
|
||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||
pub fn first_key_value<T: ?Sized>(&self) -> Option<(&K, &V)>
|
||||
where
|
||||
T: Ord,
|
||||
K: Borrow<T>,
|
||||
{
|
||||
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)
|
||||
}
|
||||
@ -667,7 +663,38 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Contrived way to `clear` a map:
|
||||
/// ```
|
||||
/// #![feature(map_first_last)]
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map = BTreeMap::new();
|
||||
/// map.insert(1, "a");
|
||||
/// map.insert(2, "b");
|
||||
/// 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<OccupiedEntry<'_, K, V>> {
|
||||
let front = self.root.as_mut()?.as_mut().first_leaf_edge();
|
||||
let kv = front.right_kv().ok()?;
|
||||
Some(OccupiedEntry {
|
||||
handle: kv.forget_node_type(),
|
||||
length: &mut self.length,
|
||||
_marker: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
/// 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)]
|
||||
@ -676,27 +703,14 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
||||
/// 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));
|
||||
/// 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 first_entry<T: ?Sized>(&mut self) -> Option<OccupiedEntry<'_, K, V>>
|
||||
where
|
||||
T: Ord,
|
||||
K: Borrow<T>,
|
||||
{
|
||||
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
|
||||
}
|
||||
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.
|
||||
@ -716,11 +730,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
||||
/// assert_eq!(map.last_key_value(), Some((&2, &"a")));
|
||||
/// ```
|
||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||
pub fn last_key_value<T: ?Sized>(&self) -> Option<(&K, &V)>
|
||||
where
|
||||
T: Ord,
|
||||
K: Borrow<T>,
|
||||
{
|
||||
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)
|
||||
}
|
||||
@ -730,7 +740,38 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Contrived way to `clear` a map:
|
||||
/// ```
|
||||
/// #![feature(map_first_last)]
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map = BTreeMap::new();
|
||||
/// map.insert(1, "a");
|
||||
/// map.insert(2, "b");
|
||||
/// 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<OccupiedEntry<'_, K, V>> {
|
||||
let back = self.root.as_mut()?.as_mut().last_leaf_edge();
|
||||
let kv = back.left_kv().ok()?;
|
||||
Some(OccupiedEntry {
|
||||
handle: kv.forget_node_type(),
|
||||
length: &mut self.length,
|
||||
_marker: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
/// 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)]
|
||||
@ -739,27 +780,14 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
||||
/// 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));
|
||||
/// 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 last_entry<T: ?Sized>(&mut self) -> Option<OccupiedEntry<'_, K, V>>
|
||||
where
|
||||
T: Ord,
|
||||
K: Borrow<T>,
|
||||
{
|
||||
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
|
||||
}
|
||||
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.
|
||||
|
@ -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:
|
||||
|
||||
```
|
||||
|
@ -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!
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -355,6 +355,19 @@ impl From<UnusedDelimsCtx> 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
|
||||
}
|
||||
|
@ -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<IndexVec<BasicBlock, Vec<BasicBlock>>>,
|
||||
// Typically 95%+ of the inner vectors have 4 or fewer elements.
|
||||
predecessors: Option<IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>>>,
|
||||
}
|
||||
|
||||
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<BasicBlock, Vec<BasicBlock>> {
|
||||
// njn: typedef?
|
||||
fn predecessors(
|
||||
&mut self,
|
||||
body: &Body<'_>,
|
||||
) -> &IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>> {
|
||||
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<BasicBlock, Vec<BasicBlock>> {
|
||||
pub fn predecessors(&mut self) -> &IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>> {
|
||||
self.cache.predecessors(&self.body)
|
||||
}
|
||||
|
||||
@ -199,7 +205,7 @@ impl ReadOnlyBodyAndCache<'a, 'tcx> {
|
||||
Self { body, cache }
|
||||
}
|
||||
|
||||
pub fn predecessors(&self) -> &IndexVec<BasicBlock, Vec<BasicBlock>> {
|
||||
pub fn predecessors(&self) -> &IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>> {
|
||||
self.cache.predecessors.as_ref().unwrap()
|
||||
}
|
||||
|
||||
|
@ -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`
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<Item = 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 `<Foo2 as Bar2>::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 `<Foo2 as Bar2>::Ok == ()`
|
||||
// --> $DIR/point-at-type-on-obligation-failure.rs:13:5
|
||||
// |
|
||||
// LL | type Ok;
|
||||
// | -- associated type defined here
|
||||
// LL | type Sibling: Bar2<Ok=Self::Ok>;
|
||||
// | -------------------------------- 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 <Self as Foo>>::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 `<Foo2 as Bar2>::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 `<Foo2 as Bar2>::Ok == ()`
|
||||
// --> $DIR/point-at-type-on-obligation-failure.rs:13:5
|
||||
// |
|
||||
// LL | type Ok;
|
||||
// | -- associated type defined here
|
||||
// LL | type Sibling: Bar2<Ok=Self::Ok>;
|
||||
// | -------------------------------- 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 <Self as Foo>>::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)
|
||||
});
|
||||
|
@ -1,29 +1,48 @@
|
||||
// check-pass
|
||||
#![warn(unused_braces, unused_parens)]
|
||||
|
||||
fn consume<T>(_: 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 } {
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -10,13 +10,15 @@ struct A {
|
||||
b: u32,
|
||||
}
|
||||
|
||||
fn consume<T>(_: 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
|
||||
}
|
@ -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)]
|
||||
| ^^^^^^^^^^^^^
|
Loading…
Reference in New Issue
Block a user