From e1cd99f6ff2bc2aecec530801b8a71d898bff309 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 17 Apr 2023 13:14:03 +0000 Subject: [PATCH 01/11] Make `IndexVec::ensure_contains_elem` return a reference to the element --- compiler/rustc_ast_lowering/src/item.rs | 10 +++++----- compiler/rustc_ast_lowering/src/lib.rs | 15 +++++++-------- .../src/generator_interior/drop_ranges/mod.rs | 3 +-- compiler/rustc_index/src/interval.rs | 3 +-- compiler/rustc_index/src/vec.rs | 15 ++++++++------- compiler/rustc_metadata/src/rmeta/table.rs | 4 ++-- 6 files changed, 24 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index f89e254a2f54d..c061a244cf50a 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -89,9 +89,9 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { lctx.with_hir_id_owner(owner, |lctx| f(lctx)); for (def_id, info) in lctx.children { - self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); - debug_assert!(matches!(self.owners[def_id], hir::MaybeOwner::Phantom)); - self.owners[def_id] = info; + let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); + debug_assert!(matches!(owner, hir::MaybeOwner::Phantom)); + *owner = info; } } @@ -99,8 +99,8 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { &mut self, def_id: LocalDefId, ) -> hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>> { - self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); - if let hir::MaybeOwner::Phantom = self.owners[def_id] { + let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); + if let hir::MaybeOwner::Phantom = owner { let node = self.ast_index[def_id]; match node { AstOwner::NonOwner => {} diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 2af47e11637c5..537c2a0618348 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -368,8 +368,8 @@ fn index_crate<'a>( krate: &'a Crate, ) -> IndexVec> { let mut indexer = Indexer { node_id_to_def_id, index: IndexVec::new() }; - indexer.index.ensure_contains_elem(CRATE_DEF_ID, || AstOwner::NonOwner); - indexer.index[CRATE_DEF_ID] = AstOwner::Crate(krate); + *indexer.index.ensure_contains_elem(CRATE_DEF_ID, || AstOwner::NonOwner) = + AstOwner::Crate(krate); visit::walk_crate(&mut indexer, krate); return indexer.index; @@ -386,22 +386,21 @@ fn index_crate<'a>( fn visit_item(&mut self, item: &'a ast::Item) { let def_id = self.node_id_to_def_id[&item.id]; - self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner); - self.index[def_id] = AstOwner::Item(item); + *self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) = AstOwner::Item(item); visit::walk_item(self, item) } fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: visit::AssocCtxt) { let def_id = self.node_id_to_def_id[&item.id]; - self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner); - self.index[def_id] = AstOwner::AssocItem(item, ctxt); + *self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) = + AstOwner::AssocItem(item, ctxt); visit::walk_assoc_item(self, item, ctxt); } fn visit_foreign_item(&mut self, item: &'a ast::ForeignItem) { let def_id = self.node_id_to_def_id[&item.id]; - self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner); - self.index[def_id] = AstOwner::ForeignItem(item); + *self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) = + AstOwner::ForeignItem(item); visit::walk_foreign_item(self, item); } } diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs index f7b493bc2242b..d3685d21f2521 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs @@ -268,8 +268,7 @@ impl DropRangesBuilder { fn node_mut(&mut self, id: PostOrderId) -> &mut NodeInfo { let size = self.num_values(); - self.nodes.ensure_contains_elem(id, || NodeInfo::new(size)); - &mut self.nodes[id] + self.nodes.ensure_contains_elem(id, || NodeInfo::new(size)) } fn add_control_edge(&mut self, from: PostOrderId, to: PostOrderId) { diff --git a/compiler/rustc_index/src/interval.rs b/compiler/rustc_index/src/interval.rs index d809740c6ab31..4605d42a15b7d 100644 --- a/compiler/rustc_index/src/interval.rs +++ b/compiler/rustc_index/src/interval.rs @@ -261,8 +261,7 @@ impl SparseIntervalMatrix { } fn ensure_row(&mut self, row: R) -> &mut IntervalSet { - self.rows.ensure_contains_elem(row, || IntervalSet::new(self.column_size)); - &mut self.rows[row] + self.rows.ensure_contains_elem(row, || IntervalSet::new(self.column_size)) } pub fn union_row(&mut self, row: R, from: &IntervalSet) -> bool diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index ae2f52c513e9f..95600f7bcf16f 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -236,12 +236,16 @@ impl IndexVec { /// `elem`; if that is already true, then has no /// effect. Otherwise, inserts new values as needed by invoking /// `fill_value`. + /// + /// Returns a reference to the `elem` entry. #[inline] - pub fn ensure_contains_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) { + pub fn ensure_contains_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) -> &mut T { let min_new_len = elem.index() + 1; if self.len() < min_new_len { self.raw.resize_with(min_new_len, fill_value); } + + &mut self[elem] } #[inline] @@ -446,20 +450,17 @@ impl IndexSlice { impl IndexVec> { #[inline] pub fn insert(&mut self, index: I, value: T) -> Option { - self.ensure_contains_elem(index, || None); - self[index].replace(value) + self.ensure_contains_elem(index, || None).replace(value) } #[inline] pub fn get_or_insert_with(&mut self, index: I, value: impl FnOnce() -> T) -> &mut T { - self.ensure_contains_elem(index, || None); - self[index].get_or_insert_with(value) + self.ensure_contains_elem(index, || None).get_or_insert_with(value) } #[inline] pub fn remove(&mut self, index: I) -> Option { - self.ensure_contains_elem(index, || None); - self[index].take() + self.ensure_contains_elem(index, || None).take() } } diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 364fa74ab7b45..66e2518fa56e5 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -413,8 +413,8 @@ impl> TableBui // > Space requirements could perhaps be optimized by using the HAMT `popcnt` // > trick (i.e. divide things into buckets of 32 or 64 items and then // > store bit-masks of which item in each bucket is actually serialized). - self.blocks.ensure_contains_elem(i, || [0; N]); - value.write_to_bytes(&mut self.blocks[i]); + let block = self.blocks.ensure_contains_elem(i, || [0; N]); + value.write_to_bytes(block); } } From 556062ea6e11be560b7e0c176b36566c991e595d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 18 Apr 2023 03:06:15 +0000 Subject: [PATCH 02/11] Delay a good path bug for TypeErrCtxt --- compiler/rustc_infer/src/infer/error_reporting/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 992b07db1543d..fefc8a0f62bf1 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -74,7 +74,6 @@ use rustc_middle::ty::{ self, error::TypeError, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, }; -use rustc_span::DUMMY_SP; use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span}; use rustc_target::spec::abi; use std::ops::{ControlFlow, Deref}; @@ -138,7 +137,7 @@ impl Drop for TypeErrCtxt<'_, '_> { self.infcx .tcx .sess - .delay_span_bug(DUMMY_SP, "used a `TypeErrCtxt` without failing compilation"); + .delay_good_path_bug("used a `TypeErrCtxt` without raising an error or lint"); } } } From bd1dfcebe3ae34c4c7fb2ac0660707090a0cbe3a Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 17 Apr 2023 13:37:03 +0000 Subject: [PATCH 03/11] Don't allocate it `IndexVec::remove` --- compiler/rustc_index/src/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 95600f7bcf16f..18e779f786e14 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -460,7 +460,7 @@ impl IndexVec> { #[inline] pub fn remove(&mut self, index: I) -> Option { - self.ensure_contains_elem(index, || None).take() + self.get_mut(index)?.take() } } From c5e6ccb1ed0b1e8d4861d47d4728da4bda90efbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Tue, 18 Apr 2023 18:15:06 +0200 Subject: [PATCH 04/11] clippy: add test for https://github.com/rust-lang/rust-clippy/issues/10645 --- src/tools/clippy/tests/ui/crashes/ice-5207.rs | 5 ++++- .../clippy/tests/ui/crashes/ice-5207.stderr | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 src/tools/clippy/tests/ui/crashes/ice-5207.stderr diff --git a/src/tools/clippy/tests/ui/crashes/ice-5207.rs b/src/tools/clippy/tests/ui/crashes/ice-5207.rs index f463f78a99ab7..893c15f5d731c 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-5207.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-5207.rs @@ -1,5 +1,8 @@ -// Regression test for https://github.com/rust-lang/rust-clippy/issues/5207 +// compile-flags: --cap-lints=warn +// ^ for https://github.com/rust-lang/rust-clippy/issues/10645 +// Regression test for https://github.com/rust-lang/rust-clippy/issues/5207 +#![warn(clippy::future_not_send)] pub async fn bar<'a, T: 'a>(_: T) {} fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-5207.stderr b/src/tools/clippy/tests/ui/crashes/ice-5207.stderr new file mode 100644 index 0000000000000..367e9a08b7563 --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-5207.stderr @@ -0,0 +1,16 @@ +warning: future cannot be sent between threads safely + --> $DIR/ice-5207.rs:6:35 + | +LL | pub async fn bar<'a, T: 'a>(_: T) {} + | ^ future returned by `bar` is not `Send` + | +note: captured value is not `Send` + --> $DIR/ice-5207.rs:6:29 + | +LL | pub async fn bar<'a, T: 'a>(_: T) {} + | ^ has type `T` which is not `Send` + = note: `T` doesn't implement `std::marker::Send` + = note: `-D clippy::future-not-send` implied by `-D warnings` + +warning: 1 warning emitted + From 770c303c005261aa997e6a3a1b762c2831768365 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 16 Apr 2023 22:22:42 +0000 Subject: [PATCH 05/11] Report reason why index impl is not satisfied deeply --- compiler/rustc_hir_typeck/src/expr.rs | 97 +++++++++++++++++++ tests/ui/typeck/bad-index-due-to-nested.rs | 15 +++ .../ui/typeck/bad-index-due-to-nested.stderr | 29 ++++++ 3 files changed, 141 insertions(+) create mode 100644 tests/ui/typeck/bad-index-due-to-nested.rs create mode 100644 tests/ui/typeck/bad-index-due-to-nested.stderr diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index ffc73d64fc04b..5c45e8f9d9410 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -38,6 +38,7 @@ use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::InferOk; +use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::ObligationCause; use rustc_middle::middle::stability; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; @@ -53,6 +54,8 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_target::abi::FieldIdx; use rustc_target::spec::abi::Abi::RustIntrinsic; use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; +use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::{self, ObligationCauseCode}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -2800,6 +2803,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { element_ty } None => { + // Attempt to *shallowly* search for an impl which matches, + // but has nested obligations which are unsatisfied. + for (base_t, _) in self.autoderef(base.span, base_t).silence_errors() { + if let Some((_, index_ty, element_ty)) = + self.find_and_report_unsatisfied_index_impl(expr.hir_id, base, base_t) + { + self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No); + return element_ty; + } + } + let mut err = type_error_struct!( self.tcx.sess, expr.span, @@ -2843,6 +2857,89 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + /// Try to match an implementation of `Index` against a self type, and report + /// the unsatisfied predicates that result from confirming this impl. + /// + /// Given an index expression, sometimes the `Self` type shallowly but does not + /// deeply satisfy an impl predicate. Instead of simply saying that the type + /// does not support being indexed, we want to point out exactly what nested + /// predicates cause this to be, so that the user can add them to fix their code. + fn find_and_report_unsatisfied_index_impl( + &self, + index_expr_hir_id: HirId, + base_expr: &hir::Expr<'_>, + base_ty: Ty<'tcx>, + ) -> Option<(ErrorGuaranteed, Ty<'tcx>, Ty<'tcx>)> { + let index_trait_def_id = self.tcx.lang_items().index_trait()?; + + let mut relevant_impls = vec![]; + self.tcx.for_each_relevant_impl(index_trait_def_id, base_ty, |impl_def_id| { + relevant_impls.push(impl_def_id); + }); + let [impl_def_id] = relevant_impls[..] else { + // Only report unsatisfied impl predicates if there's one impl + return None; + }; + + self.commit_if_ok(|_| { + let ocx = ObligationCtxt::new_in_snapshot(self); + let impl_substs = self.fresh_substs_for_item(base_expr.span, impl_def_id); + let impl_trait_ref = + self.tcx.impl_trait_ref(impl_def_id).unwrap().subst(self.tcx, impl_substs); + let cause = self.misc(base_expr.span); + + // Match the impl self type against the base ty. If this fails, + // we just skip this impl, since it's not particularly useful. + let impl_trait_ref = ocx.normalize(&cause, self.param_env, impl_trait_ref); + ocx.eq(&cause, self.param_env, impl_trait_ref.self_ty(), base_ty)?; + + // Register the impl's predicates. One of these predicates + // must be unsatisfied, or else we wouldn't have gotten here + // in the first place. + ocx.register_obligations(traits::predicates_for_generics( + |idx, span| { + traits::ObligationCause::new( + base_expr.span, + self.body_id, + if span.is_dummy() { + traits::ExprItemObligation(impl_def_id, index_expr_hir_id, idx) + } else { + traits::ExprBindingObligation(impl_def_id, span, index_expr_hir_id, idx) + }, + ) + }, + self.param_env, + self.tcx.predicates_of(impl_def_id).instantiate(self.tcx, impl_substs), + )); + + // Normalize the output type, which we can use later on as the + // return type of the index expression... + let element_ty = ocx.normalize( + &cause, + self.param_env, + self.tcx.mk_projection( + self.tcx + .associated_items(index_trait_def_id) + .filter_by_name_unhygienic(sym::Output) + .next() + .unwrap() + .def_id, + impl_trait_ref.substs, + ), + ); + + let errors = ocx.select_where_possible(); + // There should be at least one error reported. If not, we + // will still delay a span bug in `report_fulfillment_errors`. + Ok::<_, NoSolution>(( + self.err_ctxt().report_fulfillment_errors(&errors), + impl_trait_ref.substs.type_at(1), + element_ty, + )) + }) + .ok() + } + fn point_at_index_if_possible( &self, errors: &mut Vec>, diff --git a/tests/ui/typeck/bad-index-due-to-nested.rs b/tests/ui/typeck/bad-index-due-to-nested.rs new file mode 100644 index 0000000000000..8f3b97dc74147 --- /dev/null +++ b/tests/ui/typeck/bad-index-due-to-nested.rs @@ -0,0 +1,15 @@ +use std::collections::HashMap; + +pub struct Graph { + node_index_map: HashMap, +} + +impl Graph { + pub fn node_index(&self, node: V) -> usize { + self.node_index_map[&node] + //~^ ERROR the trait bound `V: Eq` is not satisfied + //~| ERROR the trait bound `V: Hash` is not satisfied + } +} + +fn main() {} diff --git a/tests/ui/typeck/bad-index-due-to-nested.stderr b/tests/ui/typeck/bad-index-due-to-nested.stderr new file mode 100644 index 0000000000000..fdacba793961b --- /dev/null +++ b/tests/ui/typeck/bad-index-due-to-nested.stderr @@ -0,0 +1,29 @@ +error[E0277]: the trait bound `V: Eq` is not satisfied + --> $DIR/bad-index-due-to-nested.rs:9:9 + | +LL | self.node_index_map[&node] + | ^^^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `V` + | +note: required by a bound in ` as Index<&Q>>` + --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL +help: consider restricting type parameter `V` + | +LL | impl Graph { + | ++++++++++++++ + +error[E0277]: the trait bound `V: Hash` is not satisfied + --> $DIR/bad-index-due-to-nested.rs:9:9 + | +LL | self.node_index_map[&node] + | ^^^^^^^^^^^^^^^^^^^ the trait `Hash` is not implemented for `V` + | +note: required by a bound in ` as Index<&Q>>` + --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL +help: consider restricting type parameter `V` + | +LL | impl Graph { + | +++++++++++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. From d84b5f9b3d18cd6f6c273c4fe6ab09dba1edd6fb Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 18 Apr 2023 18:55:17 +0000 Subject: [PATCH 06/11] Use a diagnostic item instead of filtering for Index::Output --- compiler/rustc_hir_typeck/src/expr.rs | 11 ++--------- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/ops/index.rs | 1 + 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 5c45e8f9d9410..0c0a7515d9c3b 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2871,6 +2871,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base_ty: Ty<'tcx>, ) -> Option<(ErrorGuaranteed, Ty<'tcx>, Ty<'tcx>)> { let index_trait_def_id = self.tcx.lang_items().index_trait()?; + let index_trait_output_def_id = self.tcx.get_diagnostic_item(sym::IndexOutput)?; let mut relevant_impls = vec![]; self.tcx.for_each_relevant_impl(index_trait_def_id, base_ty, |impl_def_id| { @@ -2917,15 +2918,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let element_ty = ocx.normalize( &cause, self.param_env, - self.tcx.mk_projection( - self.tcx - .associated_items(index_trait_def_id) - .filter_by_name_unhygienic(sym::Output) - .next() - .unwrap() - .def_id, - impl_trait_ref.substs, - ), + self.tcx.mk_projection(index_trait_output_def_id, impl_trait_ref.substs), ); let errors = ocx.select_where_possible(); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 6ce0b66ef6a45..d6ee7ac34aaca 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -204,6 +204,7 @@ symbols! { HashSet, Hasher, Implied, + IndexOutput, Input, Into, IntoDiagnostic, diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs index 228efb0bc0a5c..f3754484f6a06 100644 --- a/library/core/src/ops/index.rs +++ b/library/core/src/ops/index.rs @@ -59,6 +59,7 @@ pub trait Index { /// The returned type after indexing. #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_diagnostic_item = "IndexOutput"] type Output: ?Sized; /// Performs the indexing (`container[index]`) operation. From 8d75a8f699c921724b1e01ce932de77d08533957 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 18 Apr 2023 19:25:57 +0000 Subject: [PATCH 07/11] Test downstream errors from bad index expr --- tests/ui/typeck/bad-index-due-to-nested.rs | 30 +++++--- .../ui/typeck/bad-index-due-to-nested.stderr | 73 ++++++++++++++----- 2 files changed, 75 insertions(+), 28 deletions(-) diff --git a/tests/ui/typeck/bad-index-due-to-nested.rs b/tests/ui/typeck/bad-index-due-to-nested.rs index 8f3b97dc74147..2564b530004e5 100644 --- a/tests/ui/typeck/bad-index-due-to-nested.rs +++ b/tests/ui/typeck/bad-index-due-to-nested.rs @@ -1,15 +1,27 @@ -use std::collections::HashMap; +use std::hash::Hash; +use std::marker::PhantomData; +use std::ops::Index; -pub struct Graph { - node_index_map: HashMap, -} +struct HashMap(PhantomData<(K, V)>); + +impl Index<&K> for HashMap +where + K: Hash, + V: Copy, +{ + type Output = V; -impl Graph { - pub fn node_index(&self, node: V) -> usize { - self.node_index_map[&node] - //~^ ERROR the trait bound `V: Eq` is not satisfied - //~| ERROR the trait bound `V: Hash` is not satisfied + fn index(&self, k: &K) -> &V { + todo!() } } +fn index<'a, K, V>(map: &'a HashMap, k: K) -> &'a V { + map[k] + //~^ ERROR the trait bound `K: Hash` is not satisfied + //~| ERROR the trait bound `V: Copy` is not satisfied + //~| ERROR mismatched types + //~| ERROR mismatched types +} + fn main() {} diff --git a/tests/ui/typeck/bad-index-due-to-nested.stderr b/tests/ui/typeck/bad-index-due-to-nested.stderr index fdacba793961b..e03b06b336eef 100644 --- a/tests/ui/typeck/bad-index-due-to-nested.stderr +++ b/tests/ui/typeck/bad-index-due-to-nested.stderr @@ -1,29 +1,64 @@ -error[E0277]: the trait bound `V: Eq` is not satisfied - --> $DIR/bad-index-due-to-nested.rs:9:9 +error[E0277]: the trait bound `K: Hash` is not satisfied + --> $DIR/bad-index-due-to-nested.rs:20:5 | -LL | self.node_index_map[&node] - | ^^^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `V` +LL | map[k] + | ^^^ the trait `Hash` is not implemented for `K` | -note: required by a bound in ` as Index<&Q>>` - --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL -help: consider restricting type parameter `V` +note: required by a bound in ` as Index<&K>>` + --> $DIR/bad-index-due-to-nested.rs:9:8 + | +LL | K: Hash, + | ^^^^ required by this bound in ` as Index<&K>>` +help: consider restricting type parameter `K` | -LL | impl Graph { - | ++++++++++++++ +LL | fn index<'a, K: std::hash::Hash, V>(map: &'a HashMap, k: K) -> &'a V { + | +++++++++++++++++ -error[E0277]: the trait bound `V: Hash` is not satisfied - --> $DIR/bad-index-due-to-nested.rs:9:9 +error[E0277]: the trait bound `V: Copy` is not satisfied + --> $DIR/bad-index-due-to-nested.rs:20:5 + | +LL | map[k] + | ^^^ the trait `Copy` is not implemented for `V` | -LL | self.node_index_map[&node] - | ^^^^^^^^^^^^^^^^^^^ the trait `Hash` is not implemented for `V` +note: required by a bound in ` as Index<&K>>` + --> $DIR/bad-index-due-to-nested.rs:10:8 | -note: required by a bound in ` as Index<&Q>>` - --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL +LL | V: Copy, + | ^^^^ required by this bound in ` as Index<&K>>` help: consider restricting type parameter `V` | -LL | impl Graph { - | +++++++++++++++++ +LL | fn index<'a, K, V: std::marker::Copy>(map: &'a HashMap, k: K) -> &'a V { + | +++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/bad-index-due-to-nested.rs:20:9 + | +LL | fn index<'a, K, V>(map: &'a HashMap, k: K) -> &'a V { + | - this type parameter +LL | map[k] + | ^ + | | + | expected `&K`, found type parameter `K` + | help: consider borrowing here: `&k` + | + = note: expected reference `&K` + found type parameter `K` + +error[E0308]: mismatched types + --> $DIR/bad-index-due-to-nested.rs:20:5 + | +LL | fn index<'a, K, V>(map: &'a HashMap, k: K) -> &'a V { + | - this type parameter ----- expected `&'a V` because of return type +LL | map[k] + | ^^^^^^ + | | + | expected `&V`, found type parameter `V` + | help: consider borrowing here: `&map[k]` + | + = note: expected reference `&'a V` + found type parameter `V` -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. From 2c5867bab4300586462a921e6580bc213943def8 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 18 Apr 2023 22:26:35 +0100 Subject: [PATCH 08/11] boostrap: print output during building tools --- src/bootstrap/tool.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 79fab00efe703..79eec6f848c27 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -121,7 +121,7 @@ impl Step for ToolBuild { builder.info(&msg); let mut cargo = Command::from(cargo); - let is_expected = builder.try_run_quiet(&mut cargo); + let is_expected = builder.try_run(&mut cargo); builder.save_toolstate( tool, From 522bc5f817696c113a03a462a5dbec794263dfcb Mon Sep 17 00:00:00 2001 From: Kyle Matsuda Date: Mon, 17 Apr 2023 11:46:01 -0600 Subject: [PATCH 09/11] add EarlyBinder to return type of collect_return_position_impl_trait_in_trait_tys query; remove bound_X version --- .../rustc_hir_analysis/src/check/compare_impl_item.rs | 6 +++--- compiler/rustc_hir_analysis/src/collect/type_of.rs | 2 +- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_middle/src/arena.rs | 6 +++++- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/util.rs | 7 ------- compiler/rustc_query_impl/src/on_disk_cache.rs | 4 +++- compiler/rustc_trait_selection/src/traits/project.rs | 9 ++++----- 8 files changed, 18 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 863a9977446c1..fe87aae8ed111 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -579,7 +579,7 @@ fn compare_asyncness<'tcx>( pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( tcx: TyCtxt<'tcx>, impl_m_def_id: LocalDefId, -) -> Result<&'tcx FxHashMap>, ErrorGuaranteed> { +) -> Result<&'tcx FxHashMap>>, ErrorGuaranteed> { let impl_m = tcx.opt_associated_item(impl_m_def_id.to_def_id()).unwrap(); let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap(); let impl_trait_ref = @@ -782,14 +782,14 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( }) }); debug!(%ty); - collected_tys.insert(def_id, ty); + collected_tys.insert(def_id, ty::EarlyBinder(ty)); } Err(err) => { let reported = tcx.sess.delay_span_bug( return_span, format!("could not fully resolve: {ty} => {err:?}"), ); - collected_tys.insert(def_id, tcx.ty_error(reported)); + collected_tys.insert(def_id, ty::EarlyBinder(tcx.ty_error(reported))); } } } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index c173bd913a84c..f82fad474224b 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -251,7 +251,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder { let assoc_item = tcx.associated_item(def_id); - return ty::EarlyBinder(map[&assoc_item.trait_item_def_id.unwrap()]); + return map[&assoc_item.trait_item_def_id.unwrap()]; } Err(_) => { return ty::EarlyBinder(tcx.ty_error_with_message( diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index dc77a079b075d..a6a34765324fe 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -416,7 +416,7 @@ define_tables! { macro_definition: Table>, proc_macro: Table, deduced_param_attrs: Table>, - trait_impl_trait_tys: Table>>>, + trait_impl_trait_tys: Table>>>>, doc_link_resolutions: Table>, doc_link_traits_in_scope: Table>, } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index dd1e254f405b6..60d7cf59d0470 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -114,7 +114,11 @@ macro_rules! arena_types { [] dep_kind: rustc_middle::dep_graph::DepKindStruct<'tcx>, - [decode] trait_impl_trait_tys: rustc_data_structures::fx::FxHashMap>, + [decode] trait_impl_trait_tys: + rustc_data_structures::fx::FxHashMap< + rustc_hir::def_id::DefId, + rustc_middle::ty::EarlyBinder> + >, [] bit_set_u32: rustc_index::bit_set::BitSet, [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<'tcx>, [decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 6fc9190b0905d..7e26e05025ff1 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -181,7 +181,7 @@ rustc_queries! { } query collect_return_position_impl_trait_in_trait_tys(key: DefId) - -> Result<&'tcx FxHashMap>, ErrorGuaranteed> + -> Result<&'tcx FxHashMap>>, ErrorGuaranteed> { desc { "comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process" } cache_on_disk_if { key.is_local() } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index c8a78ec03d947..dab5baae5ee87 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -694,13 +694,6 @@ impl<'tcx> TyCtxt<'tcx> { if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) } } - pub fn bound_return_position_impl_trait_in_trait_tys( - self, - def_id: DefId, - ) -> ty::EarlyBinder>, ErrorGuaranteed>> { - ty::EarlyBinder(self.collect_return_position_impl_trait_in_trait_tys(def_id)) - } - pub fn bound_explicit_item_bounds( self, def_id: DefId, diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index 30477c7bd4422..4ff72fee0863e 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -806,7 +806,9 @@ impl<'a, 'tcx> Decodable> for &'tcx UnordSet } } -impl<'a, 'tcx> Decodable> for &'tcx FxHashMap> { +impl<'a, 'tcx> Decodable> + for &'tcx FxHashMap>> +{ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { RefDecodable::decode(d) } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 826fc63ca0653..5e042ffc60367 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -2277,11 +2277,10 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>( obligation.param_env, cause.clone(), obligation.recursion_depth + 1, - tcx.bound_return_position_impl_trait_in_trait_tys(impl_fn_def_id) - .map_bound(|tys| { - tys.map_or_else(|guar| tcx.ty_error(guar), |tys| tys[&obligation.predicate.def_id]) - }) - .subst(tcx, impl_fn_substs), + tcx.collect_return_position_impl_trait_in_trait_tys(impl_fn_def_id).map_or_else( + |guar| tcx.ty_error(guar), + |tys| tys[&obligation.predicate.def_id].subst(tcx, impl_fn_substs), + ), &mut obligations, ); From 238756e45d88a603c143b89f7408717516a03e03 Mon Sep 17 00:00:00 2001 From: Bryan Garza <1396101+bryangarza@users.noreply.github.com> Date: Tue, 18 Apr 2023 16:31:05 -0700 Subject: [PATCH 10/11] Fix ICE for transmutability in candidate assembly Don't skip transmutability check just because there may be generics in the ParamEnv. Fixes #110467 --- .../src/traits/select/candidate_assembly.rs | 2 +- tests/ui/transmutability/issue-110467.rs | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 tests/ui/transmutability/issue-110467.rs diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 1f5bbc178f7d7..a019d00461be1 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -775,7 +775,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) { - if obligation.has_non_region_param() { + if obligation.predicate.has_non_region_param() { return; } diff --git a/tests/ui/transmutability/issue-110467.rs b/tests/ui/transmutability/issue-110467.rs new file mode 100644 index 0000000000000..358733b9832c2 --- /dev/null +++ b/tests/ui/transmutability/issue-110467.rs @@ -0,0 +1,17 @@ +// check-pass +#![crate_type = "lib"] +#![feature(transmutability)] +use std::mem::BikeshedIntrinsicFrom; +pub struct Context; + +pub fn is_maybe_transmutable() +where + Dst: BikeshedIntrinsicFrom, +{ +} + +// The `T` here should not have any effect on checking +// if transmutability is allowed or not. +fn function_with_generic() { + is_maybe_transmutable::<(), ()>(); +} From 625619551d6e33ada03186d4b9ae0ab7f2c07add Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Wed, 19 Apr 2023 12:00:14 +1200 Subject: [PATCH 11/11] make `non_upper_case_globals` lint not report trait impls --- compiler/rustc_lint/src/nonstandard_style.rs | 15 +++++++++------ .../lint/lint-non-uppercase-trait-assoc-const.rs | 15 +++++++++++++++ .../lint-non-uppercase-trait-assoc-const.stderr | 14 ++++++++++++++ 3 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 tests/ui/lint/lint-non-uppercase-trait-assoc-const.rs create mode 100644 tests/ui/lint/lint-non-uppercase-trait-assoc-const.stderr diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 9efc14849c76f..648a7c6eed66d 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -494,6 +494,15 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { hir::ItemKind::Const(..) => { NonUpperCaseGlobals::check_upper_case(cx, "constant", &it.ident); } + // we only want to check inherent associated consts, trait consts + // are linted at def-site. + hir::ItemKind::Impl(hir::Impl { of_trait: None, items, .. }) => { + for it in *items { + if let hir::AssocItemKind::Const = it.kind { + NonUpperCaseGlobals::check_upper_case(cx, "associated constant", &it.ident); + } + } + } _ => {} } } @@ -504,12 +513,6 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { } } - fn check_impl_item(&mut self, cx: &LateContext<'_>, ii: &hir::ImplItem<'_>) { - if let hir::ImplItemKind::Const(..) = ii.kind { - NonUpperCaseGlobals::check_upper_case(cx, "associated constant", &ii.ident); - } - } - fn check_pat(&mut self, cx: &LateContext<'_>, p: &hir::Pat<'_>) { // Lint for constants that look like binding identifiers (#7526) if let PatKind::Path(hir::QPath::Resolved(None, ref path)) = p.kind { diff --git a/tests/ui/lint/lint-non-uppercase-trait-assoc-const.rs b/tests/ui/lint/lint-non-uppercase-trait-assoc-const.rs new file mode 100644 index 0000000000000..4409611c200fc --- /dev/null +++ b/tests/ui/lint/lint-non-uppercase-trait-assoc-const.rs @@ -0,0 +1,15 @@ +#![deny(non_upper_case_globals)] + +trait Trait { + const item: usize; + //~^ ERROR associated constant `item` should have an upper case name [non_upper_case_globals] +} + +struct Foo; + +impl Trait for Foo { + const item: usize = 5; + // ^^^ there should be no error here (in the trait `impl`) +} + +fn main() {} diff --git a/tests/ui/lint/lint-non-uppercase-trait-assoc-const.stderr b/tests/ui/lint/lint-non-uppercase-trait-assoc-const.stderr new file mode 100644 index 0000000000000..98d8d1dd27f35 --- /dev/null +++ b/tests/ui/lint/lint-non-uppercase-trait-assoc-const.stderr @@ -0,0 +1,14 @@ +error: associated constant `item` should have an upper case name + --> $DIR/lint-non-uppercase-trait-assoc-const.rs:4:11 + | +LL | const item: usize; + | ^^^^ help: convert the identifier to upper case: `ITEM` + | +note: the lint level is defined here + --> $DIR/lint-non-uppercase-trait-assoc-const.rs:1:9 + | +LL | #![deny(non_upper_case_globals)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error +