diff options
Diffstat (limited to 'compiler/rustc_hir_analysis')
26 files changed, 425 insertions, 383 deletions
diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index 581ef2272d1..196d7d99e93 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -13,7 +13,7 @@ itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } -rustc_attr = { path = "../rustc_attr" } +rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index a2df0ba265c..0c3ed9b5c60 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -249,6 +249,12 @@ hir_analysis_invalid_receiver_ty_help = hir_analysis_invalid_receiver_ty_help_no_arbitrary_self_types = consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) +hir_analysis_invalid_receiver_ty_help_nonnull_note = + `NonNull` does not implement `Receiver` because it has methods that may shadow the referent; consider wrapping your `NonNull` in a newtype wrapper for which you implement `Receiver` + +hir_analysis_invalid_receiver_ty_help_weak_note = + `Weak` does not implement `Receiver` because it has methods that may shadow the referent; consider wrapping your `Weak` in a newtype wrapper for which you implement `Receiver` + hir_analysis_invalid_receiver_ty_no_arbitrary_self_types = invalid `self` parameter type: `{$receiver_ty}` .note = type of `self` must be `Self` or a type that dereferences to it diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 022a6d457ec..5548a6a6ef7 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -6,7 +6,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::MultiSpan; use rustc_errors::codes::*; use rustc_hir::def::{CtorKind, DefKind}; -use rustc_hir::{Node, Safety, intravisit}; +use rustc_hir::{Node, intravisit}; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::{Obligation, ObligationCauseCode}; use rustc_lint_defs::builtin::{ @@ -31,7 +31,7 @@ use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_type_ir::fold::TypeFoldable; use tracing::{debug, instrument}; use ty::TypingMode; -use {rustc_attr as attr, rustc_hir as hir}; +use {rustc_attr_parsing as attr, rustc_hir as hir}; use super::compare_impl_item::check_type_bounds; use super::*; @@ -161,7 +161,7 @@ fn check_unsafe_fields(tcx: TyCtxt<'_>, item_def_id: LocalDefId) { }; let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id); for field in def.all_fields() { - if field.safety != Safety::Unsafe { + if !field.safety.is_unsafe() { continue; } let Ok(field_ty) = tcx.try_normalize_erasing_regions(typing_env, field.ty(tcx, args)) 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 e176fc58999..a6b504de3da 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -430,12 +430,12 @@ fn compare_method_predicate_entailment<'tcx>( Ok(()) } -struct RemapLateBound<'a, 'tcx> { +struct RemapLateParam<'a, 'tcx> { tcx: TyCtxt<'tcx>, - mapping: &'a FxIndexMap<ty::BoundRegionKind, ty::BoundRegionKind>, + mapping: &'a FxIndexMap<ty::LateParamRegionKind, ty::LateParamRegionKind>, } -impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateBound<'_, 'tcx> { +impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateParam<'_, 'tcx> { fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -445,7 +445,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateBound<'_, 'tcx> { ty::Region::new_late_param( self.tcx, fr.scope, - self.mapping.get(&fr.bound_region).copied().unwrap_or(fr.bound_region), + self.mapping.get(&fr.kind).copied().unwrap_or(fr.kind), ) } else { r diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index 6eac4ac3baf..2b14594ea1b 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -289,11 +289,16 @@ fn report_mismatched_rpitit_signature<'tcx>( tcx.fn_sig(trait_m_def_id).skip_binder().bound_vars(), tcx.fn_sig(impl_m_def_id).skip_binder().bound_vars(), ) - .filter_map(|(impl_bv, trait_bv)| { + .enumerate() + .filter_map(|(idx, (impl_bv, trait_bv))| { if let ty::BoundVariableKind::Region(impl_bv) = impl_bv && let ty::BoundVariableKind::Region(trait_bv) = trait_bv { - Some((impl_bv, trait_bv)) + let var = ty::BoundVar::from_usize(idx); + Some(( + ty::LateParamRegionKind::from_bound(var, impl_bv), + ty::LateParamRegionKind::from_bound(var, trait_bv), + )) } else { None } @@ -301,7 +306,7 @@ fn report_mismatched_rpitit_signature<'tcx>( .collect(); let mut return_ty = - trait_m_sig.output().fold_with(&mut super::RemapLateBound { tcx, mapping: &mapping }); + trait_m_sig.output().fold_with(&mut super::RemapLateParam { tcx, mapping: &mapping }); if tcx.asyncness(impl_m_def_id).is_async() && tcx.asyncness(trait_m_def_id).is_async() { let ty::Alias(ty::Projection, future_ty) = return_ty.kind() else { diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index f3dd13c84b9..245085b332c 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -7,9 +7,8 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::span_bug; use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; use rustc_session::config::EntryFnType; -use rustc_span::Span; use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; -use rustc_span::symbol::sym; +use rustc_span::{Span, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 2e6b511412b..39479401910 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -8,8 +8,7 @@ use rustc_middle::bug; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; -use rustc_span::symbol::sym; -use rustc_span::{Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; use crate::check::check_function_signature; use crate::errors::{ diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 61e203a1ff6..0b0c92a726d 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -89,8 +89,7 @@ use rustc_middle::ty::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypingMode use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::symbol::{Ident, kw, sym}; -use rustc_span::{BytePos, DUMMY_SP, Span, Symbol}; +use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::infer::ObligationCauseExt as _; use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor; diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index b9cb48cafdc..ca6729a5bbd 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -129,7 +129,7 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h let mut prev_cx = visitor.cx; visitor.enter_scope(Scope { - id: blk.hir_id.local_id, + local_id: blk.hir_id.local_id, data: ScopeData::Remainder(FirstStatementIndex::new(i)), }); visitor.cx.var_parent = visitor.cx.parent; @@ -154,7 +154,7 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h // the first such subscope, which has the block itself as a // parent. visitor.enter_scope(Scope { - id: blk.hir_id.local_id, + local_id: blk.hir_id.local_id, data: ScopeData::Remainder(FirstStatementIndex::new(i)), }); visitor.cx.var_parent = visitor.cx.parent; @@ -184,7 +184,7 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h visitor .scope_tree .backwards_incompatible_scope - .insert(local_id, Scope { id: local_id, data: ScopeData::Node }); + .insert(local_id, Scope { local_id, data: ScopeData::Node }); } visitor.visit_expr(tail_expr); } @@ -221,7 +221,7 @@ fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir } fn resolve_pat<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, pat: &'tcx hir::Pat<'tcx>) { - visitor.record_child_scope(Scope { id: pat.hir_id.local_id, data: ScopeData::Node }); + visitor.record_child_scope(Scope { local_id: pat.hir_id.local_id, data: ScopeData::Node }); // If this is a binding then record the lifetime of that binding. if let PatKind::Binding(..) = pat.kind { @@ -485,7 +485,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h } else { ScopeData::IfThen }; - visitor.enter_scope(Scope { id: then.hir_id.local_id, data }); + visitor.enter_scope(Scope { local_id: then.hir_id.local_id, data }); visitor.cx.var_parent = visitor.cx.parent; visitor.visit_expr(cond); visitor.visit_expr(then); @@ -500,7 +500,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h } else { ScopeData::IfThen }; - visitor.enter_scope(Scope { id: then.hir_id.local_id, data }); + visitor.enter_scope(Scope { local_id: then.hir_id.local_id, data }); visitor.cx.var_parent = visitor.cx.parent; visitor.visit_expr(cond); visitor.visit_expr(then); @@ -516,7 +516,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h if let hir::ExprKind::Yield(_, source) = &expr.kind { // Mark this expr's scope and all parent scopes as containing `yield`. - let mut scope = Scope { id: expr.hir_id.local_id, data: ScopeData::Node }; + let mut scope = Scope { local_id: expr.hir_id.local_id, data: ScopeData::Node }; loop { let span = match expr.kind { hir::ExprKind::Yield(expr, hir::YieldSource::Await { .. }) => { @@ -803,9 +803,9 @@ impl<'tcx> RegionResolutionVisitor<'tcx> { // account for the destruction scope representing the scope of // the destructors that run immediately after it completes. if self.terminating_scopes.contains(&id) { - self.enter_scope(Scope { id, data: ScopeData::Destruction }); + self.enter_scope(Scope { local_id: id, data: ScopeData::Destruction }); } - self.enter_scope(Scope { id, data: ScopeData::Node }); + self.enter_scope(Scope { local_id: id, data: ScopeData::Node }); } fn enter_body(&mut self, hir_id: hir::HirId, f: impl FnOnce(&mut Self)) { @@ -822,8 +822,8 @@ impl<'tcx> RegionResolutionVisitor<'tcx> { let outer_pessimistic_yield = mem::replace(&mut self.pessimistic_yield, false); self.terminating_scopes.insert(hir_id.local_id); - self.enter_scope(Scope { id: hir_id.local_id, data: ScopeData::CallSite }); - self.enter_scope(Scope { id: hir_id.local_id, data: ScopeData::Arguments }); + self.enter_scope(Scope { local_id: hir_id.local_id, data: ScopeData::CallSite }); + self.enter_scope(Scope { local_id: hir_id.local_id, data: ScopeData::Arguments }); f(self); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index e6ef29de965..3cddc9642ba 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -23,8 +23,7 @@ use rustc_middle::ty::{ }; use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; -use rustc_span::symbol::{Ident, sym}; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{DUMMY_SP, Ident, Span, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::misc::{ @@ -44,6 +43,7 @@ use {rustc_ast as ast, rustc_hir as hir}; use crate::autoderef::Autoderef; use crate::collect::CollectItemTypesVisitor; use crate::constrained_generic_params::{Parameter, identify_constrained_generic_params}; +use crate::errors::InvalidReceiverTyHint; use crate::{errors, fluent_generated as fluent}; pub(super) struct WfCheckingCtxt<'a, 'tcx> { @@ -1749,7 +1749,18 @@ fn check_method_receiver<'tcx>( { match receiver_validity_err { ReceiverValidityError::DoesNotDeref if arbitrary_self_types_level.is_some() => { - tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty }) + let hint = match receiver_ty + .builtin_deref(false) + .unwrap_or(receiver_ty) + .ty_adt_def() + .and_then(|adt_def| tcx.get_diagnostic_name(adt_def.did())) + { + Some(sym::RcWeak | sym::ArcWeak) => Some(InvalidReceiverTyHint::Weak), + Some(sym::NonNull) => Some(InvalidReceiverTyHint::NonNull), + _ => None, + }; + + tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty, hint }) } ReceiverValidityError::DoesNotDeref => { tcx.dcx().emit_err(errors::InvalidReceiverTyNoArbitrarySelfTypes { @@ -2328,8 +2339,11 @@ fn lint_redundant_lifetimes<'tcx>( ); // If we are in a function, add its late-bound lifetimes too. if matches!(def_kind, DefKind::Fn | DefKind::AssocFn) { - for var in tcx.fn_sig(owner_id).instantiate_identity().bound_vars() { + for (idx, var) in + tcx.fn_sig(owner_id).instantiate_identity().bound_vars().iter().enumerate() + { let ty::BoundVariableKind::Region(kind) = var else { continue }; + let kind = ty::LateParamRegionKind::from_bound(ty::BoundVar::from_usize(idx), kind); lifetimes.push(ty::Region::new_late_param(tcx, owner_id.to_def_id(), kind)); } } diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 2eea65125b0..3b98f358b1e 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -673,37 +673,6 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err let impl_span = tcx.def_span(checker.impl_def_id); let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty(); - // If an ADT is repr(transparent)... - if let ty::Adt(def, args) = *self_ty.kind() - && def.repr().transparent() - { - // FIXME(compiler-errors): This should and could be deduplicated into a query. - // Find the nontrivial field. - let adt_typing_env = ty::TypingEnv::non_body_analysis(tcx, def.did()); - let nontrivial_field = def.all_fields().find(|field_def| { - let field_ty = tcx.type_of(field_def.did).instantiate_identity(); - !tcx.layout_of(adt_typing_env.as_query_input(field_ty)) - .is_ok_and(|layout| layout.layout.is_1zst()) - }); - - if let Some(nontrivial_field) = nontrivial_field { - // Check that the nontrivial field implements `PointerLike`. - let nontrivial_field = nontrivial_field.ty(tcx, args); - let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); - let ocx = ObligationCtxt::new(&infcx); - ocx.register_bound( - ObligationCause::misc(impl_span, checker.impl_def_id), - param_env, - nontrivial_field, - tcx.lang_items().pointer_like().unwrap(), - ); - // FIXME(dyn-star): We should regionck this implementation. - if ocx.select_all_or_error().is_empty() { - return Ok(()); - } - } - } - let is_permitted_primitive = match *self_ty.kind() { ty::Adt(def, _) => def.is_box(), ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true, @@ -717,6 +686,74 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err return Ok(()); } + let why_disqualified = match *self_ty.kind() { + // If an ADT is repr(transparent) + ty::Adt(self_ty_def, args) => { + if self_ty_def.repr().transparent() { + // FIXME(compiler-errors): This should and could be deduplicated into a query. + // Find the nontrivial field. + let adt_typing_env = ty::TypingEnv::non_body_analysis(tcx, self_ty_def.did()); + let nontrivial_field = self_ty_def.all_fields().find(|field_def| { + let field_ty = tcx.type_of(field_def.did).instantiate_identity(); + !tcx.layout_of(adt_typing_env.as_query_input(field_ty)) + .is_ok_and(|layout| layout.layout.is_1zst()) + }); + + if let Some(nontrivial_field) = nontrivial_field { + // Check that the nontrivial field implements `PointerLike`. + let nontrivial_field_ty = nontrivial_field.ty(tcx, args); + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); + let ocx = ObligationCtxt::new(&infcx); + ocx.register_bound( + ObligationCause::misc(impl_span, checker.impl_def_id), + param_env, + nontrivial_field_ty, + tcx.lang_items().pointer_like().unwrap(), + ); + // FIXME(dyn-star): We should regionck this implementation. + if ocx.select_all_or_error().is_empty() { + return Ok(()); + } else { + format!( + "the field `{field_name}` of {descr} `{self_ty}` \ + does not implement `PointerLike`", + field_name = nontrivial_field.name, + descr = self_ty_def.descr() + ) + } + } else { + format!( + "the {descr} `{self_ty}` is `repr(transparent)`, \ + but does not have a non-trivial field (it is zero-sized)", + descr = self_ty_def.descr() + ) + } + } else if self_ty_def.is_box() { + // If we got here, then the `layout.is_pointer_like()` check failed + // and this box is not a thin pointer. + + String::from("boxes of dynamically-sized types are too large to be `PointerLike`") + } else { + format!( + "the {descr} `{self_ty}` is not `repr(transparent)`", + descr = self_ty_def.descr() + ) + } + } + ty::Ref(..) => { + // If we got here, then the `layout.is_pointer_like()` check failed + // and this reference is not a thin pointer. + String::from("references to dynamically-sized types are too large to be `PointerLike`") + } + ty::Dynamic(..) | ty::Foreign(..) => { + String::from("types of dynamic or unknown size may not implement `PointerLike`") + } + _ => { + // This is a white lie; it is true everywhere outside the standard library. + format!("only user-defined sized types are eligible for `impl PointerLike`") + } + }; + Err(tcx .dcx() .struct_span_err( @@ -724,5 +761,6 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err "implementation must be applied to type that has the same ABI as a pointer, \ or is `repr(transparent)` and whose field is `PointerLike`", ) + .with_note(why_disqualified) .emit()) } diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 2afc2aec1ba..8f6f5b5f222 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -13,8 +13,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::bug; use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams, simplify_type}; use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt}; -use rustc_span::ErrorGuaranteed; -use rustc_span::symbol::sym; +use rustc_span::{ErrorGuaranteed, sym}; use crate::errors; diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index 3aad4bafeb5..1be4aa2f63a 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -206,7 +206,9 @@ fn check_object_overlap<'tcx>( // so this is valid. } else { let mut supertrait_def_ids = tcx.supertrait_def_ids(component_def_id); - if supertrait_def_ids.any(|d| d == trait_def_id) { + if supertrait_def_ids + .any(|d| d == trait_def_id && tcx.trait_def(d).implement_via_object) + { let span = tcx.def_span(impl_def_id); return Err(struct_span_code_err!( tcx.dcx(), diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 7fb024cce5a..ada70117b62 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -38,8 +38,7 @@ use rustc_middle::ty::fold::fold_regions; use rustc_middle::ty::util::{Discr, IntTypeExt}; use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypingMode}; use rustc_middle::{bug, span_bug}; -use rustc_span::symbol::{Ident, Symbol, kw, sym}; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::ObligationCtxt; @@ -1262,49 +1261,8 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { no_dups.then_some(list) }); - let mut deny_explicit_impl = false; - let mut implement_via_object = true; - if let Some(attr) = tcx.get_attr(def_id, sym::rustc_deny_explicit_impl) { - deny_explicit_impl = true; - let mut seen_attr = false; - for meta in attr.meta_item_list().iter().flatten() { - if let Some(meta) = meta.meta_item() - && meta.name_or_empty() == sym::implement_via_object - && let Some(lit) = meta.name_value_literal() - { - if seen_attr { - tcx.dcx().span_err(meta.span, "duplicated `implement_via_object` meta item"); - } - seen_attr = true; - - match lit.symbol { - kw::True => { - implement_via_object = true; - } - kw::False => { - implement_via_object = false; - } - _ => { - tcx.dcx().span_err( - meta.span, - format!( - "unknown literal passed to `implement_via_object` attribute: {}", - lit.symbol - ), - ); - } - } - } else { - tcx.dcx().span_err( - meta.span(), - format!("unknown meta item passed to `rustc_deny_explicit_impl` {meta:?}"), - ); - } - } - if !seen_attr { - tcx.dcx().span_err(attr.span, "missing `implement_via_object` meta item"); - } - } + let deny_explicit_impl = tcx.has_attr(def_id, sym::rustc_deny_explicit_impl); + let implement_via_object = !tcx.has_attr(def_id, sym::rustc_do_not_implement_via_object); ty::TraitDef { def_id: def_id.to_def_id(), @@ -1340,7 +1298,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn .. }) | Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), .. }) => { - infer_return_ty_for_fn_sig(sig, generics, def_id, &icx) + lower_fn_sig_recovering_infer_ret_ty(&icx, sig, generics, def_id) } ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => { @@ -1357,7 +1315,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn None, ) } else { - infer_return_ty_for_fn_sig(sig, generics, def_id, &icx) + lower_fn_sig_recovering_infer_ret_ty(&icx, sig, generics, def_id) } } @@ -1407,99 +1365,108 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn ty::EarlyBinder::bind(output) } -fn infer_return_ty_for_fn_sig<'tcx>( - sig: &hir::FnSig<'tcx>, - generics: &hir::Generics<'_>, +fn lower_fn_sig_recovering_infer_ret_ty<'tcx>( + icx: &ItemCtxt<'tcx>, + sig: &'tcx hir::FnSig<'tcx>, + generics: &'tcx hir::Generics<'tcx>, def_id: LocalDefId, +) -> ty::PolyFnSig<'tcx> { + if let Some(infer_ret_ty) = sig.decl.output.get_infer_ret_ty() { + return recover_infer_ret_ty(icx, infer_ret_ty, generics, def_id); + } + + icx.lowerer().lower_fn_ty( + icx.tcx().local_def_id_to_hir_id(def_id), + sig.header.safety, + sig.header.abi, + sig.decl, + Some(generics), + None, + ) +} + +fn recover_infer_ret_ty<'tcx>( icx: &ItemCtxt<'tcx>, + infer_ret_ty: &'tcx hir::Ty<'tcx>, + generics: &'tcx hir::Generics<'tcx>, + def_id: LocalDefId, ) -> ty::PolyFnSig<'tcx> { let tcx = icx.tcx; let hir_id = tcx.local_def_id_to_hir_id(def_id); - match sig.decl.output.get_infer_ret_ty() { - Some(ty) => { - let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id]; - // Typeck doesn't expect erased regions to be returned from `type_of`. - // This is a heuristic approach. If the scope has region parameters, - // we should change fn_sig's lifetime from `ReErased` to `ReError`, - // otherwise to `ReStatic`. - let has_region_params = generics.params.iter().any(|param| match param.kind { - GenericParamKind::Lifetime { .. } => true, - _ => false, - }); - let fn_sig = fold_regions(tcx, fn_sig, |r, _| match *r { - ty::ReErased => { - if has_region_params { - ty::Region::new_error_with_message( - tcx, - DUMMY_SP, - "erased region is not allowed here in return type", - ) - } else { - tcx.lifetimes.re_static - } - } - _ => r, - }); + let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id]; - let mut visitor = HirPlaceholderCollector::default(); - visitor.visit_ty(ty); - - let mut diag = bad_placeholder(icx.lowerer(), visitor.0, "return type"); - let ret_ty = fn_sig.output(); - // Don't leak types into signatures unless they're nameable! - // For example, if a function returns itself, we don't want that - // recursive function definition to leak out into the fn sig. - let mut recovered_ret_ty = None; - - if let Some(suggestable_ret_ty) = ret_ty.make_suggestable(tcx, false, None) { - diag.span_suggestion( - ty.span, - "replace with the correct return type", - suggestable_ret_ty, - Applicability::MachineApplicable, - ); - recovered_ret_ty = Some(suggestable_ret_ty); - } else if let Some(sugg) = suggest_impl_trait( - &tcx.infer_ctxt().build(TypingMode::non_body_analysis()), - tcx.param_env(def_id), - ret_ty, - ) { - diag.span_suggestion( - ty.span, - "replace with an appropriate return type", - sugg, - Applicability::MachineApplicable, - ); - } else if ret_ty.is_closure() { - diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound"); - } - // Also note how `Fn` traits work just in case! - if ret_ty.is_closure() { - diag.note( - "for more information on `Fn` traits and closure types, see \ - https://doc.rust-lang.org/book/ch13-01-closures.html", - ); + // Typeck doesn't expect erased regions to be returned from `type_of`. + // This is a heuristic approach. If the scope has region parameters, + // we should change fn_sig's lifetime from `ReErased` to `ReError`, + // otherwise to `ReStatic`. + let has_region_params = generics.params.iter().any(|param| match param.kind { + GenericParamKind::Lifetime { .. } => true, + _ => false, + }); + let fn_sig = fold_regions(tcx, fn_sig, |r, _| match *r { + ty::ReErased => { + if has_region_params { + ty::Region::new_error_with_message( + tcx, + DUMMY_SP, + "erased region is not allowed here in return type", + ) + } else { + tcx.lifetimes.re_static } - - let guar = diag.emit(); - ty::Binder::dummy(tcx.mk_fn_sig( - fn_sig.inputs().iter().copied(), - recovered_ret_ty.unwrap_or_else(|| Ty::new_error(tcx, guar)), - fn_sig.c_variadic, - fn_sig.safety, - fn_sig.abi, - )) } - None => icx.lowerer().lower_fn_ty( - hir_id, - sig.header.safety, - sig.header.abi, - sig.decl, - Some(generics), - None, - ), + _ => r, + }); + + let mut visitor = HirPlaceholderCollector::default(); + visitor.visit_ty(infer_ret_ty); + + let mut diag = bad_placeholder(icx.lowerer(), visitor.0, "return type"); + let ret_ty = fn_sig.output(); + + // Don't leak types into signatures unless they're nameable! + // For example, if a function returns itself, we don't want that + // recursive function definition to leak out into the fn sig. + let mut recovered_ret_ty = None; + if let Some(suggestable_ret_ty) = ret_ty.make_suggestable(tcx, false, None) { + diag.span_suggestion( + infer_ret_ty.span, + "replace with the correct return type", + suggestable_ret_ty, + Applicability::MachineApplicable, + ); + recovered_ret_ty = Some(suggestable_ret_ty); + } else if let Some(sugg) = suggest_impl_trait( + &tcx.infer_ctxt().build(TypingMode::non_body_analysis()), + tcx.param_env(def_id), + ret_ty, + ) { + diag.span_suggestion( + infer_ret_ty.span, + "replace with an appropriate return type", + sugg, + Applicability::MachineApplicable, + ); + } else if ret_ty.is_closure() { + diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound"); + } + + // Also note how `Fn` traits work just in case! + if ret_ty.is_closure() { + diag.note( + "for more information on `Fn` traits and closure types, see \ + https://doc.rust-lang.org/book/ch13-01-closures.html", + ); } + let guar = diag.emit(); + ty::Binder::dummy(tcx.mk_fn_sig( + fn_sig.inputs().iter().copied(), + recovered_ret_ty.unwrap_or_else(|| Ty::new_error(tcx, guar)), + fn_sig.c_variadic, + fn_sig.safety, + fn_sig.abi, + )) } pub fn suggest_impl_trait<'tcx>( diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index f52d4f42eca..075615de522 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -8,8 +8,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint; -use rustc_span::Span; -use rustc_span::symbol::{Symbol, kw}; +use rustc_span::{Span, Symbol, kw}; use tracing::{debug, instrument}; use crate::delegation::inherit_generics_for_delegation_item; diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 0b81f469371..d3ff1f7bebe 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -371,10 +371,9 @@ pub(super) fn explicit_item_bounds_with_filter( associated_type_bounds(tcx, def_id, opaque_ty.bounds, opaque_ty.span, filter); return ty::EarlyBinder::bind(bounds); } - Some(ty::ImplTraitInTraitData::Impl { .. }) => span_bug!( - tcx.def_span(def_id), - "item bounds for RPITIT in impl to be fed on def-id creation" - ), + Some(ty::ImplTraitInTraitData::Impl { .. }) => { + span_bug!(tcx.def_span(def_id), "RPITIT in impl should not have item bounds") + } None => {} } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 1a6c0a93436..8f84492146f 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -9,8 +9,7 @@ use rustc_middle::ty::{ self, GenericPredicates, ImplTraitInTraitData, Ty, TyCtxt, TypeVisitable, TypeVisitor, Upcast, }; use rustc_middle::{bug, span_bug}; -use rustc_span::symbol::Ident; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{DUMMY_SP, Ident, Span}; use tracing::{debug, instrument, trace}; use super::item_bounds::explicit_item_bounds_with_filter; @@ -957,6 +956,15 @@ pub(super) fn const_conditions<'tcx>( bug!("const_conditions invoked for item that is not conditionally const: {def_id:?}"); } + match tcx.opt_rpitit_info(def_id.to_def_id()) { + // RPITITs inherit const conditions of their parent fn + Some( + ty::ImplTraitInTraitData::Impl { fn_def_id } + | ty::ImplTraitInTraitData::Trait { fn_def_id, .. }, + ) => return tcx.const_conditions(fn_def_id), + None => {} + } + let (generics, trait_def_id_and_supertraits, has_parent) = match tcx.hir_node_by_def_id(def_id) { Node::Item(item) => match item.kind { @@ -1060,19 +1068,29 @@ pub(super) fn explicit_implied_const_bounds<'tcx>( bug!("const_conditions invoked for item that is not conditionally const: {def_id:?}"); } - let bounds = match tcx.hir_node_by_def_id(def_id) { - Node::Item(hir::Item { kind: hir::ItemKind::Trait(..), .. }) => { - implied_predicates_with_filter( - tcx, - def_id.to_def_id(), - PredicateFilter::SelfConstIfConst, - ) - } - Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. }) - | Node::OpaqueTy(_) => { + let bounds = match tcx.opt_rpitit_info(def_id.to_def_id()) { + // RPITIT's bounds are the same as opaque type bounds, but with + // a projection self type. + Some(ty::ImplTraitInTraitData::Trait { .. }) => { explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::ConstIfConst) } - _ => bug!("explicit_implied_const_bounds called on wrong item: {def_id:?}"), + Some(ty::ImplTraitInTraitData::Impl { .. }) => { + span_bug!(tcx.def_span(def_id), "RPITIT in impl should not have item bounds") + } + None => match tcx.hir_node_by_def_id(def_id) { + Node::Item(hir::Item { kind: hir::ItemKind::Trait(..), .. }) => { + implied_predicates_with_filter( + tcx, + def_id.to_def_id(), + PredicateFilter::SelfConstIfConst, + ) + } + Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. }) + | Node::OpaqueTy(_) => { + explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::ConstIfConst) + } + _ => bug!("explicit_implied_const_bounds called on wrong item: {def_id:?}"), + }, }; bounds.map_bound(|bounds| { diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 0f797bcdae4..7c65e9613b6 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -26,9 +26,8 @@ use rustc_middle::middle::resolve_bound_vars::*; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_middle::{bug, span_bug}; -use rustc_span::Span; use rustc_span::def_id::{DefId, LocalDefId, LocalDefIdMap}; -use rustc_span::symbol::{Ident, sym}; +use rustc_span::{Ident, Span, sym}; use tracing::{debug, debug_span, instrument}; use crate::errors; diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 5595504c3d9..c0526903e88 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -10,8 +10,7 @@ use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, Article, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; -use rustc_span::symbol::Ident; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{DUMMY_SP, Ident, Span}; use super::{ItemCtxt, bad_placeholder}; use crate::errors::TypeofReservedKeywordUsed; @@ -473,7 +472,7 @@ fn infer_placeholder_type<'tcx>( fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) { if !tcx.features().inherent_associated_types() { use rustc_session::parse::feature_err; - use rustc_span::symbol::sym; + use rustc_span::sym; feature_err( &tcx.sess, sym::inherent_associated_types, diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 5ab6faf3b7c..00ba1741ed7 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -6,8 +6,7 @@ use rustc_errors::{ }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; -use rustc_span::symbol::Ident; -use rustc_span::{Span, Symbol}; +use rustc_span::{Ident, Span, Symbol}; use crate::fluent_generated as fluent; mod pattern_types; @@ -1655,6 +1654,14 @@ pub(crate) struct NonConstRange { pub span: Span, } +#[derive(Subdiagnostic)] +pub(crate) enum InvalidReceiverTyHint { + #[note(hir_analysis_invalid_receiver_ty_help_weak_note)] + Weak, + #[note(hir_analysis_invalid_receiver_ty_help_nonnull_note)] + NonNull, +} + #[derive(Diagnostic)] #[diag(hir_analysis_invalid_receiver_ty_no_arbitrary_self_types, code = E0307)] #[note] @@ -1673,6 +1680,8 @@ pub(crate) struct InvalidReceiverTy<'tcx> { #[primary_span] pub span: Span, pub receiver_ty: Ty<'tcx>, + #[subdiagnostic] + pub hint: Option<InvalidReceiverTyHint>, } #[derive(Diagnostic)] diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 0404e38a293..e949d4a1126 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -9,8 +9,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::bug; use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TyCtxt}; -use rustc_span::symbol::Ident; -use rustc_span::{ErrorGuaranteed, Span, Symbol, sym}; +use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym}; use rustc_trait_selection::traits; use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; use smallvec::SmallVec; @@ -745,7 +744,7 @@ fn check_assoc_const_binding_type<'tcx>( let generics = tcx.generics_of(enclosing_item_owner_id); for index in collector.params { let param = generics.param_at(index as _, tcx); - let is_self_param = param.name == rustc_span::symbol::kw::SelfUpper; + let is_self_param = param.name == kw::SelfUpper; guar.get_or_insert(cx.dcx().emit_err(crate::errors::ParamInTyOfAssocConstBinding { span: assoc_const.span, assoc_const, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index d3c86989440..71a5727ed6c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -1,9 +1,8 @@ -use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::struct_span_code_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::DefId; use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS; use rustc_middle::span_bug; use rustc_middle::ty::fold::BottomUpFolder; @@ -11,7 +10,7 @@ use rustc_middle::ty::{ self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast, }; -use rustc_span::{ErrorGuaranteed, Span}; +use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility; use rustc_trait_selection::traits::{self, hir_ty_lowering_dyn_compatibility_violations}; use rustc_type_ir::elaborate::ClauseWithSupertraitSpan; @@ -128,8 +127,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - let mut associated_types: FxIndexMap<Span, FxIndexSet<DefId>> = FxIndexMap::default(); + let mut needed_associated_types = FxIndexSet::default(); + let principal_span = regular_traits.first().map_or(DUMMY_SP, |info| info.bottom().1); let regular_traits_refs_spans = trait_bounds .into_iter() .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id())); @@ -145,13 +145,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { - let pred = bound_predicate.rebind(pred); - associated_types.entry(original_span).or_default().extend( - tcx.associated_items(pred.def_id()) + // FIXME(negative_bounds): Handle this correctly... + let trait_ref = + tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref)); + needed_associated_types.extend( + tcx.associated_items(trait_ref.def_id()) .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Type) .filter(|item| !item.is_impl_trait_in_trait()) - .map(|item| item.def_id), + // If the associated type has a `where Self: Sized` bound, + // we do not need to constrain the associated type. + .filter(|item| !tcx.generics_require_sized_self(item.def_id)) + .map(|item| (item.def_id, trait_ref)), ); } ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => { @@ -201,26 +206,25 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // So every `Projection` clause is an `Assoc = Foo` bound. `associated_types` contains all associated // types's `DefId`, so the following loop removes all the `DefIds` of the associated types that have a // corresponding `Projection` clause - for def_ids in associated_types.values_mut() { - for (projection_bound, span) in &projection_bounds { - let def_id = projection_bound.item_def_id(); - def_ids.swap_remove(&def_id); - if tcx.generics_require_sized_self(def_id) { - tcx.emit_node_span_lint( - UNUSED_ASSOCIATED_TYPE_BOUNDS, - hir_id, - *span, - crate::errors::UnusedAssociatedTypeBounds { span: *span }, - ); - } + for (projection_bound, span) in &projection_bounds { + let def_id = projection_bound.item_def_id(); + let trait_ref = tcx.anonymize_bound_vars( + projection_bound.map_bound(|p| p.projection_term.trait_ref(tcx)), + ); + needed_associated_types.swap_remove(&(def_id, trait_ref)); + if tcx.generics_require_sized_self(def_id) { + tcx.emit_node_span_lint( + UNUSED_ASSOCIATED_TYPE_BOUNDS, + hir_id, + *span, + crate::errors::UnusedAssociatedTypeBounds { span: *span }, + ); } - // If the associated type has a `where Self: Sized` bound, we do not need to constrain the associated - // type in the `dyn Trait`. - def_ids.retain(|def_id| !tcx.generics_require_sized_self(def_id)); } if let Err(guar) = self.check_for_required_assoc_tys( - associated_types, + principal_span, + needed_associated_types, potential_assoc_types, hir_trait_bounds, ) { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 6e10450313c..0623d35853e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -16,8 +16,7 @@ use rustc_middle::ty::{ }; use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; -use rustc_span::symbol::{Ident, kw, sym}; -use rustc_span::{BytePos, DUMMY_SP, Span, Symbol}; +use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym}; use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility; use rustc_trait_selection::traits::{ FulfillmentError, TraitAliasExpansionInfo, dyn_compatibility_violations_for_assoc_item, @@ -721,51 +720,42 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// emit a generic note suggesting using a `where` clause to constraint instead. pub(crate) fn check_for_required_assoc_tys( &self, - associated_types: FxIndexMap<Span, FxIndexSet<DefId>>, + principal_span: Span, + missing_assoc_types: FxIndexSet<(DefId, ty::PolyTraitRef<'tcx>)>, potential_assoc_types: Vec<usize>, trait_bounds: &[hir::PolyTraitRef<'_>], ) -> Result<(), ErrorGuaranteed> { - if associated_types.values().all(|v| v.is_empty()) { + if missing_assoc_types.is_empty() { return Ok(()); } let tcx = self.tcx(); - // FIXME: Marked `mut` so that we can replace the spans further below with a more - // appropriate one, but this should be handled earlier in the span assignment. - let associated_types: FxIndexMap<Span, Vec<_>> = associated_types + // FIXME: This logic needs some more care w.r.t handling of conflicts + let missing_assoc_types: Vec<_> = missing_assoc_types .into_iter() - .map(|(span, def_ids)| { - (span, def_ids.into_iter().map(|did| tcx.associated_item(did)).collect()) - }) + .map(|(def_id, trait_ref)| (tcx.associated_item(def_id), trait_ref)) .collect(); - let mut names: FxIndexMap<String, Vec<Symbol>> = Default::default(); + let mut names: FxIndexMap<_, Vec<Symbol>> = Default::default(); let mut names_len = 0; // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and // `issue-22560.rs`. - let mut trait_bound_spans: Vec<Span> = vec![]; let mut dyn_compatibility_violations = Ok(()); - for (span, items) in &associated_types { - if !items.is_empty() { - trait_bound_spans.push(*span); - } - for assoc_item in items { - let trait_def_id = assoc_item.container_id(tcx); - names.entry(tcx.def_path_str(trait_def_id)).or_default().push(assoc_item.name); - names_len += 1; - - let violations = - dyn_compatibility_violations_for_assoc_item(tcx, trait_def_id, *assoc_item); - if !violations.is_empty() { - dyn_compatibility_violations = Err(report_dyn_incompatibility( - tcx, - *span, - None, - trait_def_id, - &violations, - ) - .emit()); - } + for (assoc_item, trait_ref) in &missing_assoc_types { + names.entry(trait_ref).or_default().push(assoc_item.name); + names_len += 1; + + let violations = + dyn_compatibility_violations_for_assoc_item(tcx, trait_ref.def_id(), *assoc_item); + if !violations.is_empty() { + dyn_compatibility_violations = Err(report_dyn_incompatibility( + tcx, + principal_span, + None, + trait_ref.def_id(), + &violations, + ) + .emit()); } } @@ -813,6 +803,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .into_iter() .map(|(trait_, mut assocs)| { assocs.sort(); + let trait_ = trait_.print_trait_sugared(); format!("{} in `{trait_}`", match &assocs[..] { [] => String::new(), [only] => format!("`{only}`"), @@ -826,10 +817,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { names.sort(); let names = names.join(", "); - trait_bound_spans.sort(); let mut err = struct_span_code_err!( self.dcx(), - trait_bound_spans, + principal_span, E0191, "the value of the associated type{} {} must be specified", pluralize!(names_len), @@ -839,81 +829,83 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut types_count = 0; let mut where_constraints = vec![]; let mut already_has_generics_args_suggestion = false; - for (span, assoc_items) in &associated_types { - let mut names: UnordMap<_, usize> = Default::default(); - for item in assoc_items { - types_count += 1; - *names.entry(item.name).or_insert(0) += 1; - } - let mut dupes = false; - let mut shadows = false; - for item in assoc_items { - let prefix = if names[&item.name] > 1 { - let trait_def_id = item.container_id(tcx); - dupes = true; - format!("{}::", tcx.def_path_str(trait_def_id)) - } else if bound_names.get(&item.name).is_some_and(|x| x != &item) { - let trait_def_id = item.container_id(tcx); - shadows = true; - format!("{}::", tcx.def_path_str(trait_def_id)) - } else { - String::new() - }; - let mut is_shadowed = false; - - if let Some(assoc_item) = bound_names.get(&item.name) - && assoc_item != &item - { - is_shadowed = true; + let mut names: UnordMap<_, usize> = Default::default(); + for (item, _) in &missing_assoc_types { + types_count += 1; + *names.entry(item.name).or_insert(0) += 1; + } + let mut dupes = false; + let mut shadows = false; + for (item, trait_ref) in &missing_assoc_types { + let prefix = if names[&item.name] > 1 { + let trait_def_id = trait_ref.def_id(); + dupes = true; + format!("{}::", tcx.def_path_str(trait_def_id)) + } else if bound_names.get(&item.name).is_some_and(|x| *x != item) { + let trait_def_id = trait_ref.def_id(); + shadows = true; + format!("{}::", tcx.def_path_str(trait_def_id)) + } else { + String::new() + }; - let rename_message = - if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" }; - err.span_label( - tcx.def_span(assoc_item.def_id), - format!("`{}{}` shadowed here{}", prefix, item.name, rename_message), - ); - } + let mut is_shadowed = false; - let rename_message = if is_shadowed { ", consider renaming it" } else { "" }; + if let Some(assoc_item) = bound_names.get(&item.name) + && *assoc_item != item + { + is_shadowed = true; - if let Some(sp) = tcx.hir().span_if_local(item.def_id) { - err.span_label( - sp, - format!("`{}{}` defined here{}", prefix, item.name, rename_message), - ); - } + let rename_message = + if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" }; + err.span_label( + tcx.def_span(assoc_item.def_id), + format!("`{}{}` shadowed here{}", prefix, item.name, rename_message), + ); } - if potential_assoc_types.len() == assoc_items.len() { - // When the amount of missing associated types equals the number of - // extra type arguments present. A suggesting to replace the generic args with - // associated types is already emitted. - already_has_generics_args_suggestion = true; - } else if let (Ok(snippet), false, false) = - (tcx.sess.source_map().span_to_snippet(*span), dupes, shadows) - { - let types: Vec<_> = - assoc_items.iter().map(|item| format!("{} = Type", item.name)).collect(); - let code = if snippet.ends_with('>') { - // The user wrote `Trait<'a>` or similar and we don't have a type we can - // suggest, but at least we can clue them to the correct syntax - // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the - // suggestion. - format!("{}, {}>", &snippet[..snippet.len() - 1], types.join(", ")) - } else if in_expr_or_pat { - // The user wrote `Iterator`, so we don't have a type we can suggest, but at - // least we can clue them to the correct syntax `Iterator::<Item = Type>`. - format!("{}::<{}>", snippet, types.join(", ")) - } else { - // The user wrote `Iterator`, so we don't have a type we can suggest, but at - // least we can clue them to the correct syntax `Iterator<Item = Type>`. - format!("{}<{}>", snippet, types.join(", ")) - }; - suggestions.push((*span, code)); - } else if dupes { - where_constraints.push(*span); + + let rename_message = if is_shadowed { ", consider renaming it" } else { "" }; + + if let Some(sp) = tcx.hir().span_if_local(item.def_id) { + err.span_label( + sp, + format!("`{}{}` defined here{}", prefix, item.name, rename_message), + ); } } + if potential_assoc_types.len() == missing_assoc_types.len() { + // When the amount of missing associated types equals the number of + // extra type arguments present. A suggesting to replace the generic args with + // associated types is already emitted. + already_has_generics_args_suggestion = true; + } else if let (Ok(snippet), false, false) = + (tcx.sess.source_map().span_to_snippet(principal_span), dupes, shadows) + { + let types: Vec<_> = missing_assoc_types + .iter() + .map(|(item, _)| format!("{} = Type", item.name)) + .collect(); + let code = if snippet.ends_with('>') { + // The user wrote `Trait<'a>` or similar and we don't have a type we can + // suggest, but at least we can clue them to the correct syntax + // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the + // suggestion. + format!("{}, {}>", &snippet[..snippet.len() - 1], types.join(", ")) + } else if in_expr_or_pat { + // The user wrote `Iterator`, so we don't have a type we can suggest, but at + // least we can clue them to the correct syntax `Iterator::<Item = Type>`. + format!("{}::<{}>", snippet, types.join(", ")) + } else { + // The user wrote `Iterator`, so we don't have a type we can suggest, but at + // least we can clue them to the correct syntax `Iterator<Item = Type>`. + format!("{}<{}>", snippet, types.join(", ")) + }; + suggestions.push((principal_span, code)); + } else if dupes { + where_constraints.push(principal_span); + } + let where_msg = "consider introducing a new type parameter, adding `where` constraints \ using the fully-qualified path to the associated types"; if !where_constraints.is_empty() && suggestions.is_empty() { @@ -924,32 +916,29 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } if suggestions.len() != 1 || already_has_generics_args_suggestion { // We don't need this label if there's an inline suggestion, show otherwise. - for (span, assoc_items) in &associated_types { - let mut names: FxIndexMap<_, usize> = FxIndexMap::default(); - for item in assoc_items { - types_count += 1; - *names.entry(item.name).or_insert(0) += 1; - } - let mut label = vec![]; - for item in assoc_items { - let postfix = if names[&item.name] > 1 { - let trait_def_id = item.container_id(tcx); - format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id)) - } else { - String::new() - }; - label.push(format!("`{}`{}", item.name, postfix)); - } - if !label.is_empty() { - err.span_label( - *span, - format!( - "associated type{} {} must be specified", - pluralize!(label.len()), - label.join(", "), - ), - ); - } + let mut names: FxIndexMap<_, usize> = FxIndexMap::default(); + for (item, _) in &missing_assoc_types { + types_count += 1; + *names.entry(item.name).or_insert(0) += 1; + } + let mut label = vec![]; + for (item, trait_ref) in &missing_assoc_types { + let postfix = if names[&item.name] > 1 { + format!(" (from trait `{}`)", trait_ref.print_trait_sugared()) + } else { + String::new() + }; + label.push(format!("`{}`{}", item.name, postfix)); + } + if !label.is_empty() { + err.span_label( + principal_span, + format!( + "associated type{} {} must be specified", + pluralize!(label.len()), + label.join(", "), + ), + ); } } suggestions.sort_by_key(|&(span, _)| span); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index c3f4fc8699a..df00948dd21 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::{ self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, }; use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS; -use rustc_span::symbol::{kw, sym}; +use rustc_span::{kw, sym}; use smallvec::SmallVec; use tracing::{debug, instrument}; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index a357ade0294..b56222763d0 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -45,8 +45,7 @@ use rustc_middle::ty::{ use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; use rustc_span::edit_distance::find_best_match_for_name; -use rustc_span::symbol::{Ident, Symbol, kw}; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::wf::object_region_bounds; use rustc_trait_selection::traits::{self, ObligationCtxt}; @@ -356,7 +355,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::Region::new_late_param( tcx, scope.to_def_id(), - ty::BoundRegionKind::Named(id.to_def_id(), name), + ty::LateParamRegionKind::Named(id.to_def_id(), name), ) // (*) -- not late-bound, won't change diff --git a/compiler/rustc_hir_analysis/src/variance/dump.rs b/compiler/rustc_hir_analysis/src/variance/dump.rs index a0fdf95a831..31f0adf720d 100644 --- a/compiler/rustc_hir_analysis/src/variance/dump.rs +++ b/compiler/rustc_hir_analysis/src/variance/dump.rs @@ -2,7 +2,7 @@ use std::fmt::Write; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_middle::ty::{GenericArgs, TyCtxt}; -use rustc_span::symbol::sym; +use rustc_span::sym; fn format_variances(tcx: TyCtxt<'_>, def_id: LocalDefId) -> String { let variances = tcx.variances_of(def_id); |
