Auto merge of #110522 - matthiaskrgr:rollup-9m7rw3u, r=matthiaskrgr

Rollup of 7 pull requests

Successful merges:

 - #110432 (Report more detailed reason why `Index` impl is not satisfied)
 - #110451 (Minor changes to `IndexVec::ensure_contains_elem` & related methods)
 - #110476 (Delay a good path bug on drop for `TypeErrCtxt` (instead of a regular delayed bug))
 - #110498 (Switch to `EarlyBinder` for `collect_return_position_impl_trait_in_trait_tys`)
 - #110507 (boostrap: print output during building tools)
 - #110510 (Fix ICE for transmutability in candidate assembly)
 - #110513 (make `non_upper_case_globals` lint not report trait impls)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-04-19 05:08:54 +00:00
commit c781584079
28 changed files with 303 additions and 57 deletions

View File

@ -89,9 +89,9 @@ fn with_lctx(
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 @@ pub(super) fn lower_node(
&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 => {}

View File

@ -368,8 +368,8 @@ fn index_crate<'a>(
krate: &'a Crate,
) -> IndexVec<LocalDefId, AstOwner<'a>> {
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 visit_attribute(&mut self, _: &'a Attribute) {
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);
}
}

View File

@ -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<DefId, Ty<'tcx>>, ErrorGuaranteed> {
) -> Result<&'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>, 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)));
}
}
}

View File

@ -251,7 +251,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
match tcx.collect_return_position_impl_trait_in_trait_tys(fn_def_id) {
Ok(map) => {
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(

View File

@ -38,6 +38,7 @@
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_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 @@ fn check_expr_index(
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,82 @@ fn check_expr_index(
}
}
/// 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 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| {
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(index_trait_output_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<traits::FulfillmentError<'tcx>>,

View File

@ -268,8 +268,7 @@ fn num_values(&self) -> usize {
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) {

View File

@ -261,8 +261,7 @@ pub fn row(&self, row: R) -> Option<&IntervalSet<C>> {
}
fn ensure_row(&mut self, row: R) -> &mut IntervalSet<C> {
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<C>) -> bool

View File

@ -236,12 +236,16 @@ pub fn convert_index_type<Ix: Idx>(self) -> IndexVec<Ix, T> {
/// `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 @@ pub fn invert_bijective_mapping(&self) -> IndexVec<J, I> {
impl<I: Idx, T> IndexVec<I, Option<T>> {
#[inline]
pub fn insert(&mut self, index: I, value: T) -> Option<T> {
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<T> {
self.ensure_contains_elem(index, || None);
self[index].take()
self.get_mut(index)?.take()
}
}

View File

@ -74,7 +74,6 @@
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 @@ fn drop(&mut self) {
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");
}
}
}

View File

@ -494,6 +494,15 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
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 @@ fn check_trait_item(&mut self, cx: &LateContext<'_>, ti: &hir::TraitItem<'_>) {
}
}
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 {

View File

@ -416,7 +416,7 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
macro_definition: Table<DefIndex, LazyValue<ast::DelimArgs>>,
proc_macro: Table<DefIndex, MacroKind>,
deduced_param_attrs: Table<DefIndex, LazyArray<DeducedParamAttrs>>,
trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, Ty<'static>>>>,
trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, ty::EarlyBinder<Ty<'static>>>>>,
doc_link_resolutions: Table<DefIndex, LazyValue<DocLinkResMap>>,
doc_link_traits_in_scope: Table<DefIndex, LazyArray<DefId>>,
}

View File

@ -413,8 +413,8 @@ pub(crate) fn set(&mut self, i: I, value: T) {
// > 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);
}
}

View File

@ -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<rustc_hir::def_id::DefId, rustc_middle::ty::Ty<'tcx>>,
[decode] trait_impl_trait_tys:
rustc_data_structures::fx::FxHashMap<
rustc_hir::def_id::DefId,
rustc_middle::ty::EarlyBinder<rustc_middle::ty::Ty<'tcx>>
>,
[] bit_set_u32: rustc_index::bit_set::BitSet<u32>,
[] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<'tcx>,
[decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap,

View File

@ -181,7 +181,7 @@
}
query collect_return_position_impl_trait_in_trait_tys(key: DefId)
-> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed>
-> Result<&'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>, 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() }

View File

@ -694,13 +694,6 @@ pub fn try_expand_impl_trait_type(
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<Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed>> {
ty::EarlyBinder(self.collect_return_position_impl_trait_in_trait_tys(def_id))
}
pub fn bound_explicit_item_bounds(
self,
def_id: DefId,

View File

@ -807,7 +807,9 @@ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
}
}
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx FxHashMap<DefId, Ty<'tcx>> {
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
for &'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>
{
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
RefDecodable::decode(d)
}

View File

@ -204,6 +204,7 @@
HashSet,
Hasher,
Implied,
IndexOutput,
Input,
Into,
IntoDiagnostic,

View File

@ -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,
);

View File

@ -775,7 +775,7 @@ fn assemble_candidates_for_transmutability(
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
) {
if obligation.has_non_region_param() {
if obligation.predicate.has_non_region_param() {
return;
}

View File

@ -59,6 +59,7 @@
pub trait Index<Idx: ?Sized> {
/// 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.

View File

@ -121,7 +121,7 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
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,

View File

@ -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() {}

View File

@ -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

View File

@ -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() {}

View File

@ -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

View File

@ -0,0 +1,17 @@
// check-pass
#![crate_type = "lib"]
#![feature(transmutability)]
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context>,
{
}
// The `T` here should not have any effect on checking
// if transmutability is allowed or not.
fn function_with_generic<T>() {
is_maybe_transmutable::<(), ()>();
}

View File

@ -0,0 +1,27 @@
use std::hash::Hash;
use std::marker::PhantomData;
use std::ops::Index;
struct HashMap<K, V>(PhantomData<(K, V)>);
impl<K, V> Index<&K> for HashMap<K, V>
where
K: Hash,
V: Copy,
{
type Output = V;
fn index(&self, k: &K) -> &V {
todo!()
}
}
fn index<'a, K, V>(map: &'a HashMap<K, V>, 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() {}

View File

@ -0,0 +1,64 @@
error[E0277]: the trait bound `K: Hash` is not satisfied
--> $DIR/bad-index-due-to-nested.rs:20:5
|
LL | map[k]
| ^^^ the trait `Hash` is not implemented for `K`
|
note: required by a bound in `<HashMap<K, V> as Index<&K>>`
--> $DIR/bad-index-due-to-nested.rs:9:8
|
LL | K: Hash,
| ^^^^ required by this bound in `<HashMap<K, V> as Index<&K>>`
help: consider restricting type parameter `K`
|
LL | fn index<'a, K: std::hash::Hash, V>(map: &'a HashMap<K, V>, k: K) -> &'a V {
| +++++++++++++++++
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`
|
note: required by a bound in `<HashMap<K, V> as Index<&K>>`
--> $DIR/bad-index-due-to-nested.rs:10:8
|
LL | V: Copy,
| ^^^^ required by this bound in `<HashMap<K, V> as Index<&K>>`
help: consider restricting type parameter `V`
|
LL | fn index<'a, K, V: std::marker::Copy>(map: &'a HashMap<K, V>, 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, V>, 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, V>, 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 4 previous errors
Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.