diff options
Diffstat (limited to 'compiler/rustc_hir_analysis/src')
16 files changed, 670 insertions, 242 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index 6082d446979..ed4dde419c4 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -110,16 +110,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { { // The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a // valid span, so we point at the whole path segment instead. - let span = if assoc_name.span != DUMMY_SP { assoc_name.span } else { span }; + let is_dummy = assoc_name.span == DUMMY_SP; + let mut err = struct_span_err!( self.tcx().sess, - span, + if is_dummy { span } else { assoc_name.span }, E0220, "associated type `{}` not found for `{}`", assoc_name, ty_param_name ); + if is_dummy { + err.span_label(span, format!("associated type `{assoc_name}` not found")); + return err.emit(); + } + let all_candidate_names: Vec<_> = all_candidates() .flat_map(|r| self.tcx().associated_items(r.def_id()).in_definition_order()) .filter_map(|item| { @@ -131,10 +137,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }) .collect(); - if let (Some(suggested_name), true) = ( - find_best_match_for_name(&all_candidate_names, assoc_name.name, None), - assoc_name.span != DUMMY_SP, - ) { + if let Some(suggested_name) = + find_best_match_for_name(&all_candidate_names, assoc_name.name, None) + { err.span_suggestion( assoc_name.span, "there is an associated type with a similar name", @@ -172,10 +177,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }) .collect(); - if let (Some(suggested_name), true) = ( - find_best_match_for_name(&wider_candidate_names, assoc_name.name, None), - assoc_name.span != DUMMY_SP, - ) { + if let Some(suggested_name) = + find_best_match_for_name(&wider_candidate_names, assoc_name.name, None) + { if let [best_trait] = visible_traits .iter() .filter(|trait_def_id| { @@ -197,7 +201,28 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } - err.span_label(span, format!("associated type `{assoc_name}` not found")); + // If we still couldn't find any associated type, and only one associated type exists, + // suggests using it. + + if all_candidate_names.len() == 1 { + // this should still compile, except on `#![feature(associated_type_defaults)]` + // where it could suggests `type A = Self::A`, thus recursing infinitely + let applicability = if self.tcx().features().associated_type_defaults { + Applicability::Unspecified + } else { + Applicability::MaybeIncorrect + }; + + err.span_suggestion( + assoc_name.span, + format!("`{ty_param_name}` has the following associated type"), + all_candidate_names.first().unwrap().to_string(), + applicability, + ); + } else { + err.span_label(assoc_name.span, format!("associated type `{assoc_name}` not found")); + } + err.emit() } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 668763f9bf6..acfd8dcb112 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -523,7 +523,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { Ty::new_misc_error(tcx).into() } } - GenericParamDefKind::Const { has_default } => { + GenericParamDefKind::Const { has_default, .. } => { let ty = tcx .at(self.span) .type_of(param.def_id) @@ -910,19 +910,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) -> Ty<'tcx> { let tcx = self.tcx(); let args = self.ast_path_args_for_ty(span, did, item_segment); - let ty = tcx.at(span).type_of(did); - if let DefKind::TyAlias { lazy } = tcx.def_kind(did) - && (lazy || ty.skip_binder().has_opaque_types()) - { - // Type aliases referring to types that contain opaque types (but aren't just directly - // referencing a single opaque type) as well as those defined in crates that have the + if let DefKind::TyAlias { lazy: true } = tcx.def_kind(did) { + // Type aliases defined in crates that have the // feature `lazy_type_alias` enabled get encoded as a type alias that normalization will // then actually instantiate the where bounds of. let alias_ty = tcx.mk_alias_ty(did, args); Ty::new_alias(tcx, ty::Weak, alias_ty) } else { - ty.instantiate(tcx, args) + let ty = tcx.at(span).type_of(did); + if ty.skip_binder().has_opaque_types() { + // Type aliases referring to types that contain opaque types (but aren't just directly + // referencing a single opaque type) get encoded as a type alias that normalization will + // then actually instantiate the where bounds of. + let alias_ty = tcx.mk_alias_ty(did, args); + Ty::new_alias(tcx, ty::Weak, alias_ty) + } else { + ty.instantiate(tcx, args) + } } } @@ -2200,27 +2205,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.span_note(span, format!("type parameter `{name}` defined here")); } }); - - match tcx.named_bound_var(hir_id) { - Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { - let name = - tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id.expect_local())); - let br = ty::BoundTy { - var: ty::BoundVar::from_u32(index), - kind: ty::BoundTyKind::Param(def_id, name), - }; - Ty::new_bound(tcx, debruijn, br) - } - Some(rbv::ResolvedArg::EarlyBound(_)) => { - let def_id = def_id.expect_local(); - let item_def_id = tcx.hir().ty_param_owner(def_id); - let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id.to_def_id()]; - Ty::new_param(tcx, index, tcx.hir().ty_param_name(def_id)) - } - Some(rbv::ResolvedArg::Error(guar)) => Ty::new_error(tcx, guar), - arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"), - } + self.hir_id_to_bound_ty(hir_id) } Res::SelfTyParam { .. } => { // `Self` in trait or type alias. @@ -2389,6 +2374,57 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } + // Converts a hir id corresponding to a type parameter to + // a early-bound `ty::Param` or late-bound `ty::Bound`. + pub(crate) fn hir_id_to_bound_ty(&self, hir_id: hir::HirId) -> Ty<'tcx> { + let tcx = self.tcx(); + match tcx.named_bound_var(hir_id) { + Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => { + let name = tcx.item_name(def_id); + let br = ty::BoundTy { + var: ty::BoundVar::from_u32(index), + kind: ty::BoundTyKind::Param(def_id, name), + }; + Ty::new_bound(tcx, debruijn, br) + } + Some(rbv::ResolvedArg::EarlyBound(def_id)) => { + let def_id = def_id.expect_local(); + let item_def_id = tcx.hir().ty_param_owner(def_id); + let generics = tcx.generics_of(item_def_id); + let index = generics.param_def_id_to_index[&def_id.to_def_id()]; + Ty::new_param(tcx, index, tcx.hir().ty_param_name(def_id)) + } + Some(rbv::ResolvedArg::Error(guar)) => Ty::new_error(tcx, guar), + arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"), + } + } + + // Converts a hir id corresponding to a const parameter to + // a early-bound `ConstKind::Param` or late-bound `ConstKind::Bound`. + pub(crate) fn hir_id_to_bound_const( + &self, + hir_id: hir::HirId, + param_ty: Ty<'tcx>, + ) -> Const<'tcx> { + let tcx = self.tcx(); + match tcx.named_bound_var(hir_id) { + Some(rbv::ResolvedArg::EarlyBound(def_id)) => { + // Find the name and index of the const parameter by indexing the generics of + // the parent item and construct a `ParamConst`. + let item_def_id = tcx.parent(def_id); + let generics = tcx.generics_of(item_def_id); + let index = generics.param_def_id_to_index[&def_id]; + let name = tcx.item_name(def_id); + ty::Const::new_param(tcx, ty::ParamConst::new(index, name), param_ty) + } + Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { + ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index), param_ty) + } + Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar, param_ty), + arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", hir_id), + } + } + /// Parses the programmer's textual representation of a type into our /// internal notion of a type. pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> { diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 3c00a246a3d..1d381175c75 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -461,7 +461,15 @@ fn check_opaque_meets_bounds<'tcx>( } match origin { // Checked when type checking the function containing them. - hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {} + hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => { + // HACK: this should also fall through to the hidden type check below, but the original + // implementation had a bug where equivalent lifetimes are not identical. This caused us + // to reject existing stable code that is otherwise completely fine. The real fix is to + // compare the hidden types via our type equivalence/relation infra instead of doing an + // identity check. + let _ = infcx.take_opaque_types(); + return Ok(()); + } // Nested opaque types occur only in associated types: // ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; ` // They can only be referenced as `<Opaque<T> as Trait<&'static T>>::AssocTy`. @@ -823,7 +831,7 @@ fn check_impl_items_against_trait<'tcx>( }; match ty_impl_item.kind { ty::AssocKind::Const => { - let _ = tcx.compare_impl_const(( + tcx.ensure().compare_impl_const(( impl_item.expect_local(), ty_impl_item.trait_item_def_id.unwrap(), )); 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 bd0ab6463f0..92cc9759304 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -28,6 +28,8 @@ use rustc_trait_selection::traits::{ use std::borrow::Cow; use std::iter; +mod refine; + /// Checks that a method from an impl conforms to the signature of /// the same method as declared in the trait. /// @@ -53,6 +55,12 @@ pub(super) fn compare_impl_method<'tcx>( impl_trait_ref, CheckImpliedWfMode::Check, )?; + refine::check_refining_return_position_impl_trait_in_trait( + tcx, + impl_m, + trait_m, + impl_trait_ref, + ); }; } 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 new file mode 100644 index 00000000000..a8149b634ef --- /dev/null +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -0,0 +1,311 @@ +use rustc_data_structures::fx::FxIndexSet; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_infer::infer::{outlives::env::OutlivesEnvironment, TyCtxtInferExt}; +use rustc_lint_defs::builtin::REFINING_IMPL_TRAIT; +use rustc_middle::traits::{ObligationCause, Reveal}; +use rustc_middle::ty::{ + self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, +}; +use rustc_span::{Span, DUMMY_SP}; +use rustc_trait_selection::traits::{ + elaborate, normalize_param_env_or_error, outlives_bounds::InferCtxtExt, ObligationCtxt, +}; +use std::ops::ControlFlow; + +/// Check that an implementation does not refine an RPITIT from a trait method signature. +pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( + tcx: TyCtxt<'tcx>, + impl_m: ty::AssocItem, + trait_m: ty::AssocItem, + impl_trait_ref: ty::TraitRef<'tcx>, +) { + if !tcx.impl_method_has_trait_impl_trait_tys(impl_m.def_id) { + return; + } + // crate-private traits don't have any library guarantees, there's no need to do this check. + if !tcx.visibility(trait_m.container_id(tcx)).is_public() { + return; + } + + // If a type in the trait ref is private, then there's also no reason to to do this check. + let impl_def_id = impl_m.container_id(tcx); + for arg in impl_trait_ref.args { + if let Some(ty) = arg.as_type() + && let Some(self_visibility) = type_visibility(tcx, ty) + && !self_visibility.is_public() + { + return; + } + } + + let impl_m_args = ty::GenericArgs::identity_for_item(tcx, impl_m.def_id); + let trait_m_to_impl_m_args = impl_m_args.rebase_onto(tcx, impl_def_id, impl_trait_ref.args); + let bound_trait_m_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_m_to_impl_m_args); + let trait_m_sig = tcx.liberate_late_bound_regions(impl_m.def_id, bound_trait_m_sig); + // replace the self type of the trait ref with `Self` so that diagnostics render better. + let trait_m_sig_with_self_for_diag = tcx.liberate_late_bound_regions( + impl_m.def_id, + tcx.fn_sig(trait_m.def_id).instantiate( + tcx, + tcx.mk_args_from_iter( + [tcx.types.self_param.into()] + .into_iter() + .chain(trait_m_to_impl_m_args.iter().skip(1)), + ), + ), + ); + + let Ok(hidden_tys) = tcx.collect_return_position_impl_trait_in_trait_tys(impl_m.def_id) else { + // Error already emitted, no need to delay another. + return; + }; + + let mut collector = ImplTraitInTraitCollector { tcx, types: FxIndexSet::default() }; + trait_m_sig.visit_with(&mut collector); + + // Bound that we find on RPITITs in the trait signature. + let mut trait_bounds = vec![]; + // Bounds that we find on the RPITITs in the impl signature. + let mut impl_bounds = vec![]; + + for trait_projection in collector.types.into_iter().rev() { + let impl_opaque_args = trait_projection.args.rebase_onto(tcx, trait_m.def_id, impl_m_args); + let hidden_ty = hidden_tys[&trait_projection.def_id].instantiate(tcx, impl_opaque_args); + + // If the hidden type is not an opaque, then we have "refined" the trait signature. + let ty::Alias(ty::Opaque, impl_opaque) = *hidden_ty.kind() else { + report_mismatched_rpitit_signature( + tcx, + trait_m_sig_with_self_for_diag, + trait_m.def_id, + impl_m.def_id, + None, + ); + return; + }; + + // This opaque also needs to be from the impl method -- otherwise, + // it's a refinement to a TAIT. + if !tcx.hir().get_if_local(impl_opaque.def_id).map_or(false, |node| { + matches!( + node.expect_item().expect_opaque_ty().origin, + hir::OpaqueTyOrigin::AsyncFn(def_id) | hir::OpaqueTyOrigin::FnReturn(def_id) + if def_id == impl_m.def_id.expect_local() + ) + }) { + report_mismatched_rpitit_signature( + tcx, + trait_m_sig_with_self_for_diag, + trait_m.def_id, + impl_m.def_id, + None, + ); + return; + } + + trait_bounds.extend( + tcx.item_bounds(trait_projection.def_id).iter_instantiated(tcx, trait_projection.args), + ); + impl_bounds.extend(elaborate( + tcx, + tcx.explicit_item_bounds(impl_opaque.def_id) + .iter_instantiated_copied(tcx, impl_opaque.args), + )); + } + + let hybrid_preds = tcx + .predicates_of(impl_def_id) + .instantiate_identity(tcx) + .into_iter() + .chain(tcx.predicates_of(trait_m.def_id).instantiate_own(tcx, trait_m_to_impl_m_args)) + .map(|(clause, _)| clause); + let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds), Reveal::UserFacing); + let param_env = normalize_param_env_or_error(tcx, param_env, ObligationCause::dummy()); + + let ref infcx = tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(infcx); + + // Normalize the bounds. This has two purposes: + // + // 1. Project the RPITIT projections from the trait to the opaques on the impl, + // which means that they don't need to be mapped manually. + // + // 2. Project any other projections that show up in the bound. That makes sure that + // we don't consider `tests/ui/async-await/in-trait/async-associated-types.rs` + // to be refining. + let (trait_bounds, impl_bounds) = + ocx.normalize(&ObligationCause::dummy(), param_env, (trait_bounds, impl_bounds)); + + // Since we've normalized things, we need to resolve regions, since we'll + // possibly have introduced region vars during projection. We don't expect + // this resolution to have incurred any region errors -- but if we do, then + // just delay a bug. + let mut implied_wf_types = FxIndexSet::default(); + implied_wf_types.extend(trait_m_sig.inputs_and_output); + implied_wf_types.extend(ocx.normalize( + &ObligationCause::dummy(), + param_env, + trait_m_sig.inputs_and_output, + )); + if !ocx.select_all_or_error().is_empty() { + tcx.sess.delay_span_bug( + DUMMY_SP, + "encountered errors when checking RPITIT refinement (selection)", + ); + return; + } + let outlives_env = OutlivesEnvironment::with_bounds( + param_env, + infcx.implied_bounds_tys(param_env, impl_m.def_id.expect_local(), implied_wf_types), + ); + let errors = infcx.resolve_regions(&outlives_env); + if !errors.is_empty() { + tcx.sess.delay_span_bug( + DUMMY_SP, + "encountered errors when checking RPITIT refinement (regions)", + ); + return; + } + // Resolve any lifetime variables that may have been introduced during normalization. + let Ok((trait_bounds, impl_bounds)) = infcx.fully_resolve((trait_bounds, impl_bounds)) else { + tcx.sess.delay_span_bug( + DUMMY_SP, + "encountered errors when checking RPITIT refinement (resolution)", + ); + return; + }; + + // For quicker lookup, use an `IndexSet` + // (we don't use one earlier because it's not foldable..) + let trait_bounds = FxIndexSet::from_iter(trait_bounds); + + // Find any clauses that are present in the impl's RPITITs that are not + // present in the trait's RPITITs. This will trigger on trivial predicates, + // too, since we *do not* use the trait solver to prove that the RPITIT's + // bounds are not stronger -- we're doing a simple, syntactic compatibility + // check between bounds. This is strictly forwards compatible, though. + for (clause, span) in impl_bounds { + if !trait_bounds.contains(&clause) { + report_mismatched_rpitit_signature( + tcx, + trait_m_sig_with_self_for_diag, + trait_m.def_id, + impl_m.def_id, + Some(span), + ); + return; + } + } +} + +struct ImplTraitInTraitCollector<'tcx> { + tcx: TyCtxt<'tcx>, + types: FxIndexSet<ty::AliasTy<'tcx>>, +} + +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'tcx> { + type BreakTy = !; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> { + if let ty::Alias(ty::Projection, proj) = *ty.kind() + && self.tcx.is_impl_trait_in_trait(proj.def_id) + { + if self.types.insert(proj) { + for (pred, _) in self + .tcx + .explicit_item_bounds(proj.def_id) + .iter_instantiated_copied(self.tcx, proj.args) + { + pred.visit_with(self)?; + } + } + ControlFlow::Continue(()) + } else { + ty.super_visit_with(self) + } + } +} + +fn report_mismatched_rpitit_signature<'tcx>( + tcx: TyCtxt<'tcx>, + trait_m_sig: ty::FnSig<'tcx>, + trait_m_def_id: DefId, + impl_m_def_id: DefId, + unmatched_bound: Option<Span>, +) { + let mapping = std::iter::zip( + 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)| { + if let ty::BoundVariableKind::Region(impl_bv) = impl_bv + && let ty::BoundVariableKind::Region(trait_bv) = trait_bv + { + Some((impl_bv, trait_bv)) + } else { + None + } + }) + .collect(); + + let mut return_ty = + trait_m_sig.output().fold_with(&mut super::RemapLateBound { 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 { + bug!(); + }; + let Some(future_output_ty) = tcx + .explicit_item_bounds(future_ty.def_id) + .iter_instantiated_copied(tcx, future_ty.args) + .find_map(|(clause, _)| match clause.kind().no_bound_vars()? { + ty::ClauseKind::Projection(proj) => proj.term.ty(), + _ => None, + }) + else { + bug!() + }; + return_ty = future_output_ty; + } + + let (span, impl_return_span, pre, post) = + match tcx.hir().get_by_def_id(impl_m_def_id.expect_local()).fn_decl().unwrap().output { + hir::FnRetTy::DefaultReturn(span) => (tcx.def_span(impl_m_def_id), span, "-> ", " "), + hir::FnRetTy::Return(ty) => (ty.span, ty.span, "", ""), + }; + let trait_return_span = + tcx.hir().get_if_local(trait_m_def_id).map(|node| match node.fn_decl().unwrap().output { + hir::FnRetTy::DefaultReturn(_) => tcx.def_span(trait_m_def_id), + hir::FnRetTy::Return(ty) => ty.span, + }); + + let span = unmatched_bound.unwrap_or(span); + tcx.emit_spanned_lint( + REFINING_IMPL_TRAIT, + tcx.local_def_id_to_hir_id(impl_m_def_id.expect_local()), + span, + crate::errors::ReturnPositionImplTraitInTraitRefined { + impl_return_span, + trait_return_span, + pre, + post, + return_ty, + unmatched_bound, + }, + ); +} + +fn type_visibility<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<ty::Visibility<DefId>> { + match *ty.kind() { + ty::Ref(_, ty, _) => type_visibility(tcx, ty), + ty::Adt(def, args) => { + if def.is_fundamental() { + type_visibility(tcx, args.type_at(0)) + } else { + Some(tcx.visibility(def.did())) + } + } + _ => None, + } +} diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 5bd6fcb9612..463fab93e3f 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -149,7 +149,7 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h // From now on, we continue normally. visitor.cx = prev_cx; } - hir::StmtKind::Local(..) | hir::StmtKind::Item(..) => { + hir::StmtKind::Local(..) => { // Each declaration introduces a subscope for bindings // introduced by the declaration; this subscope covers a // suffix of the block. Each subscope in a block has the @@ -163,6 +163,10 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h visitor.cx.var_parent = visitor.cx.parent; visitor.visit_stmt(statement) } + hir::StmtKind::Item(..) => { + // Don't create scopes for items, since they won't be + // lowered to THIR and MIR. + } hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => visitor.visit_stmt(statement), } } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index f5beefc47f3..b97e0a80fe6 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1255,7 +1255,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id let is_our_default = |def: &ty::GenericParamDef| match def.kind { GenericParamDefKind::Type { has_default, .. } - | GenericParamDefKind::Const { has_default } => { + | GenericParamDefKind::Const { has_default, .. } => { has_default && def.index >= generics.parent_count as u32 } GenericParamDefKind::Lifetime => unreachable!(), diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index c930537d4ae..94f3e8706fc 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -157,6 +157,14 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef let infcx = tcx.infer_ctxt().build(); let cause = ObligationCause::misc(span, impl_did); + // Later parts of the compiler rely on all DispatchFromDyn types to be ABI-compatible with raw + // pointers. This is enforced here: we only allow impls for references, raw pointers, and things + // that are effectively repr(transparent) newtypes around types that already hav a + // DispatchedFromDyn impl. We cannot literally use repr(transparent) on those tpyes since some + // of them support an allocator, but we ensure that for the cases where the type implements this + // trait, they *do* satisfy the repr(transparent) rules, and then we assume that everything else + // in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent) + // even if they do not carry that attribute. use rustc_type_ir::sty::TyKind::*; match (source.kind(), target.kind()) { (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b)) @@ -195,8 +203,8 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef let ty_b = field.ty(tcx, args_b); if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) { - if layout.is_zst() && layout.align.abi.bytes() == 1 { - // ignore ZST fields with alignment of 1 byte + if layout.is_1zst() { + // ignore 1-ZST fields return false; } } diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index a94c75f918a..aa7c9e504c1 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -7,7 +7,6 @@ //! `tcx.inherent_impls(def_id)`). That value, however, //! is computed by selecting an idea from this table. -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -15,6 +14,8 @@ use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams}; use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt}; use rustc_span::symbol::sym; +use crate::errors; + /// On-demand query: yields a map containing all types mapped to their inherent impls. pub fn crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls { let mut collect = InherentCollect { tcx, impls_map: Default::default() }; @@ -45,14 +46,6 @@ struct InherentCollect<'tcx> { impls_map: CrateInherentImpls, } -const INTO_CORE: &str = "consider moving this inherent impl into `core` if possible"; -const INTO_DEFINING_CRATE: &str = - "consider moving this inherent impl into the crate defining the type if possible"; -const ADD_ATTR_TO_TY: &str = "alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type \ - and `#[rustc_allow_incoherent_impl]` to the relevant impl items"; -const ADD_ATTR: &str = - "alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items"; - impl<'tcx> InherentCollect<'tcx> { fn check_def_id(&mut self, impl_def_id: LocalDefId, self_ty: Ty<'tcx>, ty_def_id: DefId) { if let Some(ty_def_id) = ty_def_id.as_local() { @@ -69,30 +62,17 @@ impl<'tcx> InherentCollect<'tcx> { if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) { let impl_span = self.tcx.def_span(impl_def_id); - struct_span_err!( - self.tcx.sess, - impl_span, - E0390, - "cannot define inherent `impl` for a type outside of the crate where the type is defined", - ) - .help(INTO_DEFINING_CRATE) - .span_help(impl_span, ADD_ATTR_TO_TY) - .emit(); + self.tcx.sess.emit_err(errors::InherentTyOutside { span: impl_span }); return; } for &impl_item in items { if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) { let impl_span = self.tcx.def_span(impl_def_id); - struct_span_err!( - self.tcx.sess, - impl_span, - E0390, - "cannot define inherent `impl` for a type outside of the crate where the type is defined", - ) - .help(INTO_DEFINING_CRATE) - .span_help(self.tcx.def_span(impl_item), ADD_ATTR) - .emit(); + self.tcx.sess.emit_err(errors::InherentTyOutsideRelevant { + span: impl_span, + help_span: self.tcx.def_span(impl_item), + }); return; } } @@ -104,16 +84,7 @@ impl<'tcx> InherentCollect<'tcx> { } } else { let impl_span = self.tcx.def_span(impl_def_id); - struct_span_err!( - self.tcx.sess, - impl_span, - E0116, - "cannot define inherent `impl` for a type outside of the crate \ - where the type is defined" - ) - .span_label(impl_span, "impl for type defined outside of crate.") - .note("define and implement a trait or new type instead") - .emit(); + self.tcx.sess.emit_err(errors::InherentTyOutsideNew { span: impl_span }); } } @@ -124,34 +95,20 @@ impl<'tcx> InherentCollect<'tcx> { for &impl_item in items { if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) { let span = self.tcx.def_span(impl_def_id); - struct_span_err!( - self.tcx.sess, + self.tcx.sess.emit_err(errors::InherentTyOutsidePrimitive { span, - E0390, - "cannot define inherent `impl` for primitive types outside of `core`", - ) - .help(INTO_CORE) - .span_help(self.tcx.def_span(impl_item), ADD_ATTR) - .emit(); + help_span: self.tcx.def_span(impl_item), + }); return; } } } else { let span = self.tcx.def_span(impl_def_id); - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0390, - "cannot define inherent `impl` for primitive types", - ); - err.help("consider using an extension trait instead"); + let mut note = None; if let ty::Ref(_, subty, _) = ty.kind() { - err.note(format!( - "you could also try moving the reference to \ - uses of `{subty}` (such as `self`) within the implementation" - )); + note = Some(errors::InherentPrimitiveTyNote { subty: *subty }); } - err.emit(); + self.tcx.sess.emit_err(errors::InherentPrimitiveTy { span, note }); return; } } @@ -178,15 +135,7 @@ impl<'tcx> InherentCollect<'tcx> { self.check_def_id(id, self_ty, data.principal_def_id().unwrap()); } ty::Dynamic(..) => { - struct_span_err!( - self.tcx.sess, - item_span, - E0785, - "cannot define inherent `impl` for a dyn auto trait" - ) - .span_label(item_span, "impl requires at least one non-auto trait") - .note("define and implement a new trait or type instead") - .emit(); + self.tcx.sess.emit_err(errors::InherentDyn { span: item_span }); } ty::Bool | ty::Char @@ -202,17 +151,7 @@ impl<'tcx> InherentCollect<'tcx> { | ty::FnPtr(_) | ty::Tuple(..) => self.check_primitive_impl(id, self_ty), ty::Alias(..) | ty::Param(_) => { - let mut err = struct_span_err!( - self.tcx.sess, - item_span, - E0118, - "no nominal type found for inherent implementation" - ); - - err.span_label(item_span, "impl requires a nominal type") - .note("either implement a trait on it or create a newtype to wrap it instead"); - - err.emit(); + self.tcx.sess.emit_err(errors::InherentNominal { span: item_span }); } ty::FnDef(..) | ty::Closure(..) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 334e0541c76..01e40c62a8b 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -38,6 +38,7 @@ use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName; use rustc_trait_selection::traits::ObligationCtxt; use std::iter; +use std::ops::Bound; mod generics_of; mod item_bounds; @@ -1144,15 +1145,15 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig< } Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor().is_some() => { - let ty = tcx.type_of(tcx.hir().get_parent_item(hir_id)).instantiate_identity(); + let adt_def_id = tcx.hir().get_parent_item(hir_id).def_id.to_def_id(); + let ty = tcx.type_of(adt_def_id).instantiate_identity(); let inputs = data.fields().iter().map(|f| tcx.type_of(f.def_id).instantiate_identity()); - ty::Binder::dummy(tcx.mk_fn_sig( - inputs, - ty, - false, - hir::Unsafety::Normal, - abi::Abi::Rust, - )) + // constructors for structs with `layout_scalar_valid_range` are unsafe to call + let safety = match tcx.layout_scalar_valid_range(adt_def_id) { + (Bound::Unbounded, Bound::Unbounded) => hir::Unsafety::Normal, + _ => hir::Unsafety::Unsafe, + }; + ty::Binder::dummy(tcx.mk_fn_sig(inputs, ty, false, safety, abi::Abi::Rust)) } Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => { diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 4842008279a..3d60c57b9d5 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -328,7 +328,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { name: param.name.ident().name, def_id: param.def_id.to_def_id(), pure_wrt_drop: param.pure_wrt_drop, - kind: ty::GenericParamDefKind::Const { has_default: default.is_some() }, + kind: ty::GenericParamDefKind::Const { + has_default: default.is_some(), + is_host_effect: is_host_param, + }, }) } })); diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 495e663666c..1298c086087 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -162,8 +162,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen }; let generics = tcx.generics_of(def_id); - let parent_count = generics.parent_count as u32; - let has_own_self = generics.has_self && parent_count == 0; // Below we'll consider the bounds on the type parameters (including `Self`) // and the explicit where-clauses, but to get the full set of predicates @@ -189,17 +187,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen predicates.insert((trait_ref.to_predicate(tcx), tcx.def_span(def_id))); } - // Collect the region predicates that were declared inline as - // well. In the case of parameters declared on a fn or method, we - // have to be careful to only iterate over early-bound regions. - let mut index = parent_count - + has_own_self as u32 - + super::early_bound_lifetimes_from_generics(tcx, ast_generics).count() as u32; - - trace!(?predicates); - trace!(?ast_generics); - trace!(?generics); - // Collect the predicates that were written inline by the user on each // type parameter (e.g., `<T: Foo>`). Also add `ConstArgHasType` predicates // for each const parameter. @@ -208,10 +195,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // We already dealt with early bound lifetimes above. GenericParamKind::Lifetime { .. } => (), GenericParamKind::Type { .. } => { - let name = param.name.ident().name; - let param_ty = ty::ParamTy::new(index, name).to_ty(tcx); - index += 1; - + let param_ty = icx.astconv().hir_id_to_bound_ty(param.hir_id); let mut bounds = Bounds::default(); // Params are implicitly sized unless a `?Sized` bound is found icx.astconv().add_implicitly_sized( @@ -225,23 +209,16 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen predicates.extend(bounds.clauses()); trace!(?predicates); } - GenericParamKind::Const { .. } => { - let name = param.name.ident().name; - let param_const = ty::ParamConst::new(index, name); - + hir::GenericParamKind::Const { .. } => { let ct_ty = tcx .type_of(param.def_id.to_def_id()) .no_bound_vars() .expect("const parameters cannot be generic"); - - let ct = ty::Const::new_param(tcx, param_const, ct_ty); - + let ct = icx.astconv().hir_id_to_bound_const(param.hir_id, ct_ty); predicates.insert(( ty::ClauseKind::ConstArgHasType(ct, ct_ty).to_predicate(tcx), param.span, )); - - index += 1; } } } @@ -252,8 +229,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen match predicate { hir::WherePredicate::BoundPredicate(bound_pred) => { let ty = icx.to_ty(bound_pred.bounded_ty); - let bound_vars = icx.tcx.late_bound_vars(bound_pred.hir_id); - + let bound_vars = tcx.late_bound_vars(bound_pred.hir_id); // Keep the type around in a dummy predicate, in case of no bounds. // That way, `where Ty:` is not a complete noop (see #53696) and `Ty` // is still checked for WF. @@ -296,7 +272,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen _ => bug!(), }; let pred = ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)) - .to_predicate(icx.tcx); + .to_predicate(tcx); (pred, span) })) } 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 6dd0c840de6..2bee2727725 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -849,6 +849,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { let scope = Scope::TraitRefBoundary { s: self.scope }; self.with(scope, |this| { + walk_list!(this, visit_generic_param, generics.params); for param in generics.params { match param.kind { GenericParamKind::Lifetime { .. } => {} @@ -865,90 +866,86 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } } } - for predicate in generics.predicates { - match predicate { - &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { - hir_id, - bounded_ty, - bounds, - bound_generic_params, - origin, - .. - }) => { - let (bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) = - bound_generic_params - .iter() - .enumerate() - .map(|(late_bound_idx, param)| { - let pair = ResolvedArg::late(late_bound_idx as u32, param); - let r = late_arg_as_bound_arg(this.tcx, &pair.1, param); - (pair, r) - }) - .unzip(); - this.record_late_bound_vars(hir_id, binders.clone()); - // Even if there are no lifetimes defined here, we still wrap it in a binder - // scope. If there happens to be a nested poly trait ref (an error), that - // will be `Concatenating` anyways, so we don't have to worry about the depth - // being wrong. - let scope = Scope::Binder { - hir_id, - bound_vars, - s: this.scope, - scope_type: BinderScopeType::Normal, - where_bound_origin: Some(origin), - }; - this.with(scope, |this| { - this.visit_ty(&bounded_ty); - walk_list!(this, visit_param_bound, bounds); + walk_list!(this, visit_where_predicate, generics.predicates); + }) + } + + fn visit_where_predicate(&mut self, predicate: &'tcx hir::WherePredicate<'tcx>) { + match predicate { + &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { + hir_id, + bounded_ty, + bounds, + bound_generic_params, + origin, + .. + }) => { + let (bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) = + bound_generic_params + .iter() + .enumerate() + .map(|(late_bound_idx, param)| { + let pair = ResolvedArg::late(late_bound_idx as u32, param); + let r = late_arg_as_bound_arg(self.tcx, &pair.1, param); + (pair, r) }) - } - &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { - lifetime, - bounds, - .. - }) => { - this.visit_lifetime(lifetime); - walk_list!(this, visit_param_bound, bounds); - - if lifetime.res != hir::LifetimeName::Static { - for bound in bounds { - let hir::GenericBound::Outlives(lt) = bound else { - continue; - }; - if lt.res != hir::LifetimeName::Static { - continue; - } - this.insert_lifetime(lt, ResolvedArg::StaticLifetime); - this.tcx.struct_span_lint_hir( - lint::builtin::UNUSED_LIFETIMES, - lifetime.hir_id, - lifetime.ident.span, - format!( - "unnecessary lifetime parameter `{}`", - lifetime.ident - ), - |lint| { - let help = format!( - "you can use the `'static` lifetime directly, in place of `{}`", - lifetime.ident, - ); - lint.help(help) - }, - ); - } + .unzip(); + self.record_late_bound_vars(hir_id, binders.clone()); + // Even if there are no lifetimes defined here, we still wrap it in a binder + // scope. If there happens to be a nested poly trait ref (an error), that + // will be `Concatenating` anyways, so we don't have to worry about the depth + // being wrong. + let scope = Scope::Binder { + hir_id, + bound_vars, + s: self.scope, + scope_type: BinderScopeType::Normal, + where_bound_origin: Some(origin), + }; + self.with(scope, |this| { + walk_list!(this, visit_generic_param, bound_generic_params); + this.visit_ty(&bounded_ty); + walk_list!(this, visit_param_bound, bounds); + }) + } + &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { + lifetime, + bounds, + .. + }) => { + self.visit_lifetime(lifetime); + walk_list!(self, visit_param_bound, bounds); + + if lifetime.res != hir::LifetimeName::Static { + for bound in bounds { + let hir::GenericBound::Outlives(lt) = bound else { + continue; + }; + if lt.res != hir::LifetimeName::Static { + continue; } - } - &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { - lhs_ty, - rhs_ty, - .. - }) => { - this.visit_ty(lhs_ty); - this.visit_ty(rhs_ty); + self.insert_lifetime(lt, ResolvedArg::StaticLifetime); + self.tcx.struct_span_lint_hir( + lint::builtin::UNUSED_LIFETIMES, + lifetime.hir_id, + lifetime.ident.span, + format!("unnecessary lifetime parameter `{}`", lifetime.ident), + |lint| { + let help = format!( + "you can use the `'static` lifetime directly, in place of `{}`", + lifetime.ident, + ); + lint.help(help) + }, + ); } } } - }) + &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => { + self.visit_ty(lhs_ty); + self.visit_ty(rhs_ty); + } + } } fn visit_param_bound(&mut self, bound: &'tcx hir::GenericBound<'tcx>) { @@ -986,6 +983,18 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { intravisit::walk_anon_const(this, c); }); } + + fn visit_generic_param(&mut self, p: &'tcx GenericParam<'tcx>) { + match p.kind { + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { + self.resolve_type_ref(p.def_id, p.hir_id); + } + GenericParamKind::Lifetime { .. } => { + // No need to resolve lifetime params, we don't use them for things + // like implicit `?Sized` or const-param-has-ty predicates. + } + } + } } fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: LocalDefId) -> ObjectLifetimeDefault { diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 9471ad9ca90..b83ef8d07db 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -919,6 +919,22 @@ pub struct UnusedAssociatedTypeBounds { pub span: Span, } +#[derive(LintDiagnostic)] +#[diag(hir_analysis_rpitit_refined)] +#[note] +pub(crate) struct ReturnPositionImplTraitInTraitRefined<'tcx> { + #[suggestion(applicability = "maybe-incorrect", code = "{pre}{return_ty}{post}")] + pub impl_return_span: Span, + #[label] + pub trait_return_span: Option<Span>, + #[label(hir_analysis_unmatched_bound_label)] + pub unmatched_bound: Option<Span>, + + pub pre: &'static str, + pub post: &'static str, + pub return_ty: Ty<'tcx>, +} + #[derive(Diagnostic)] #[diag(hir_analysis_assoc_bound_on_const)] #[note] @@ -927,3 +943,75 @@ pub struct AssocBoundOnConst { pub span: Span, pub descr: &'static str, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_inherent_ty_outside, code = "E0390")] +#[help] +pub struct InherentTyOutside { + #[primary_span] + #[help(hir_analysis_span_help)] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_inherent_ty_outside_relevant, code = "E0390")] +#[help] +pub struct InherentTyOutsideRelevant { + #[primary_span] + pub span: Span, + #[help(hir_analysis_span_help)] + pub help_span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_inherent_ty_outside_new, code = "E0116")] +#[note] +pub struct InherentTyOutsideNew { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_inherent_ty_outside_primitive, code = "E0390")] +#[help] +pub struct InherentTyOutsidePrimitive { + #[primary_span] + pub span: Span, + #[help(hir_analysis_span_help)] + pub help_span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_inherent_primitive_ty, code = "E0390")] +#[help] +pub struct InherentPrimitiveTy<'a> { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub note: Option<InherentPrimitiveTyNote<'a>>, +} + +#[derive(Subdiagnostic)] +#[note(hir_analysis_inherent_primitive_ty_note)] +pub struct InherentPrimitiveTyNote<'a> { + pub subty: Ty<'a>, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_inherent_dyn, code = "E0785")] +#[note] +pub struct InherentDyn { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_inherent_nominal, code = "E0118")] +#[note] +pub struct InherentNominal { + #[primary_span] + #[label] + pub span: Span, +} diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 4f95174f869..ef788935efb 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -117,7 +117,7 @@ use rustc_hir::def::DefKind; fluent_messages! { "../messages.ftl" } fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) { - const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `win64`, `sysv64` or `efiapi`"; + const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `aapcs`, `win64`, `sysv64` or `efiapi`"; const CONVENTIONS_STABLE: &str = "`C` or `cdecl`"; const UNSTABLE_EXPLAIN: &str = "using calling conventions other than `C` or `cdecl` for varargs functions is unstable"; @@ -237,6 +237,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module)) }); + // Freeze definitions as we don't add new ones at this point. This improves performance by + // allowing lock-free access to them. + tcx.untracked().definitions.freeze(); + // FIXME: Remove this when we implement creating `DefId`s // for anon constants during their parents' typeck. // Typeck all body owners in parallel will produce queries diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index d91d9fcbc8e..d69d7ff904a 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -129,7 +129,15 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc // By default, RPIT are invariant wrt type and const generics, but they are bivariant wrt // lifetime generics. - let mut variances: Vec<_> = std::iter::repeat(ty::Invariant).take(generics.count()).collect(); + let variances = std::iter::repeat(ty::Invariant).take(generics.count()); + + let mut variances: Vec<_> = match tcx.opaque_type_origin(item_def_id) { + rustc_hir::OpaqueTyOrigin::FnReturn(_) | rustc_hir::OpaqueTyOrigin::AsyncFn(_) => { + variances.collect() + } + // But TAIT are invariant for all generics + rustc_hir::OpaqueTyOrigin::TyAlias { .. } => return tcx.arena.alloc_from_iter(variances), + }; // Mark all lifetimes from parent generics as unused (Bivariant). // This will be overridden later if required. |
