diff options
Diffstat (limited to 'compiler/rustc_hir_analysis/src')
48 files changed, 1787 insertions, 1589 deletions
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index 38ecd7dd082..c30a6f1eeb9 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -1,8 +1,12 @@ //! Bounds are restrictions applied to some types after they've been lowered from the HIR to the //! [`rustc_middle::ty`] form. +use rustc_data_structures::fx::FxIndexMap; +use rustc_hir::def::DefKind; use rustc_hir::LangItem; +use rustc_middle::ty::fold::FnMutDelegate; use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; +use rustc_span::def_id::DefId; use rustc_span::Span; /// Collects together a list of type bounds. These lists of bounds occur in many places @@ -24,6 +28,7 @@ use rustc_span::Span; #[derive(Default, PartialEq, Eq, Clone, Debug)] pub struct Bounds<'tcx> { clauses: Vec<(ty::Clause<'tcx>, Span)>, + effects_min_tys: FxIndexMap<Ty<'tcx>, Span>, } impl<'tcx> Bounds<'tcx> { @@ -40,12 +45,14 @@ impl<'tcx> Bounds<'tcx> { pub fn push_trait_bound( &mut self, tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + defining_def_id: DefId, + bound_trait_ref: ty::PolyTraitRef<'tcx>, span: Span, polarity: ty::PredicatePolarity, + constness: ty::BoundConstness, ) { let clause = ( - trait_ref + bound_trait_ref .map_bound(|trait_ref| { ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity }) }) @@ -53,11 +60,98 @@ impl<'tcx> Bounds<'tcx> { span, ); // FIXME(-Znext-solver): We can likely remove this hack once the new trait solver lands. - if tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) { + if tcx.is_lang_item(bound_trait_ref.def_id(), LangItem::Sized) { self.clauses.insert(0, clause); } else { self.clauses.push(clause); } + + if !tcx.features().effects { + return; + } + // For `T: ~const Tr` or `T: const Tr`, we need to add an additional bound on the + // associated type of `<T as Tr>` and make sure that the effect is compatible. + let compat_val = match (tcx.def_kind(defining_def_id), constness) { + // FIXME(effects): revisit the correctness of this + (_, ty::BoundConstness::Const) => tcx.consts.false_, + // body owners that can have trait bounds + (DefKind::Const | DefKind::Fn | DefKind::AssocFn, ty::BoundConstness::ConstIfConst) => { + tcx.expected_host_effect_param_for_body(defining_def_id) + } + + (_, ty::BoundConstness::NotConst) => { + if !tcx.is_const_trait(bound_trait_ref.def_id()) { + return; + } + tcx.consts.true_ + } + + ( + DefKind::Trait | DefKind::Impl { of_trait: true }, + ty::BoundConstness::ConstIfConst, + ) => { + // this is either a where clause on an impl/trait header or on a trait. + // push `<T as Tr>::Effects` into the set for the `Min` bound. + let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else { + tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc"); + return; + }; + + let ty = bound_trait_ref + .map_bound(|trait_ref| Ty::new_projection(tcx, assoc, trait_ref.args)); + + // When the user has written `for<'a, T> X<'a, T>: ~const Foo`, replace the + // binders to dummy ones i.e. `X<'static, ()>` so they can be referenced in + // the `Min` associated type properly (which doesn't allow using `for<>`) + // This should work for any bound variables as long as they don't have any + // bounds e.g. `for<T: Trait>`. + // FIXME(effects) reconsider this approach to allow compatibility with `for<T: Tr>` + let ty = tcx.replace_bound_vars_uncached( + ty, + FnMutDelegate { + regions: &mut |_| tcx.lifetimes.re_static, + types: &mut |_| tcx.types.unit, + consts: &mut |_| unimplemented!("`~const` does not support const binders"), + }, + ); + + self.effects_min_tys.insert(ty, span); + return; + } + // for + // ``` + // trait Foo { type Bar: ~const Trait } + // ``` + // ensure that `<Self::Bar as Trait>::Effects: TyCompat<Self::Effects>`. + // + // FIXME(effects) this is equality for now, which wouldn't be helpful for a non-const implementor + // that uses a `Bar` that implements `Trait` with `Maybe` effects. + (DefKind::AssocTy, ty::BoundConstness::ConstIfConst) => { + // FIXME(effects): implement this + return; + } + // probably illegal in this position. + (_, ty::BoundConstness::ConstIfConst) => { + tcx.dcx().span_delayed_bug(span, "invalid `~const` encountered"); + return; + } + }; + // create a new projection type `<T as Tr>::Effects` + let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else { + tcx.dcx().span_delayed_bug( + span, + "`~const` trait bound has no effect assoc yet no errors encountered?", + ); + return; + }; + let self_ty = Ty::new_projection(tcx, assoc, bound_trait_ref.skip_binder().args); + // make `<T as Tr>::Effects: Compat<runtime>` + let new_trait_ref = ty::TraitRef::new( + tcx, + tcx.require_lang_item(LangItem::EffectsCompat, Some(span)), + [ty::GenericArg::from(self_ty), compat_val.into()], + ); + self.clauses.push((bound_trait_ref.rebind(new_trait_ref).upcast(tcx), span)); } pub fn push_projection_bound( @@ -79,7 +173,15 @@ impl<'tcx> Bounds<'tcx> { self.clauses.insert(0, (trait_ref.upcast(tcx), span)); } - pub fn clauses(&self) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ { + pub fn clauses( + &self, + // FIXME(effects): remove tcx + _tcx: TyCtxt<'tcx>, + ) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ { self.clauses.iter().cloned() } + + pub fn effects_min_tys(&self) -> impl Iterator<Item = Ty<'tcx>> + '_ { + self.effects_min_tys.keys().copied() + } } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index b5c06751405..bf8ef18c04f 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -15,6 +15,7 @@ use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; use rustc_middle::middle::resolve_bound_vars::ResolvedArg; use rustc_middle::middle::stability::EvalResult; use rustc_middle::span_bug; +use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt}; @@ -24,9 +25,9 @@ use rustc_middle::ty::{ }; use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS}; use rustc_target::abi::FieldIdx; +use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedDirective; +use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _; use rustc_trait_selection::traits; -use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective; -use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_type_ir::fold::TypeFoldable; @@ -46,13 +47,9 @@ pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) { .emit(); } None => { - tcx.node_span_lint( - UNSUPPORTED_CALLING_CONVENTIONS, - hir_id, - span, - "use of calling convention not supported on this target", - |_| {}, - ); + tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| { + lint.primary_message("use of calling convention not supported on this target"); + }); } } @@ -243,8 +240,8 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { UNINHABITED_STATIC, tcx.local_def_id_to_hir_id(def_id), span, - "static of uninhabited type", |lint| { + lint.primary_message("static of uninhabited type"); lint .note("uninhabited statics cannot be initialized, and any access would be an immediate error"); }, @@ -346,7 +343,7 @@ fn check_opaque_meets_bounds<'tcx>( let param_env = tcx.param_env(defining_use_anchor); let infcx = tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let args = match *origin { hir::OpaqueTyOrigin::FnReturn(parent) @@ -484,9 +481,12 @@ fn sanity_check_found_hidden_type<'tcx>( /// 2. Checking that all lifetimes that are implicitly captured are mentioned. /// 3. Asserting that all parameters mentioned in the captures list are invariant. fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDefId) { - let hir::OpaqueTy { precise_capturing_args, .. } = + let hir::OpaqueTy { bounds, .. } = *tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); - let Some((precise_capturing_args, _)) = precise_capturing_args else { + let Some(precise_capturing_args) = bounds.iter().find_map(|bound| match *bound { + hir::GenericBound::Use(bounds, ..) => Some(bounds), + _ => None, + }) else { // No precise capturing args; nothing to validate return; }; @@ -538,11 +538,9 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe // the cases that were stabilized with the `impl_trait_projection` // feature -- see <https://github.com/rust-lang/rust/pull/115659>. if let DefKind::LifetimeParam = tcx.def_kind(def_id) - && let ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. }) - | ty::ReLateParam(ty::LateParamRegion { - bound_region: ty::BoundRegionKind::BrNamed(def_id, _), - .. - }) = *tcx.map_opaque_lifetime_to_parent_lifetime(def_id.expect_local()) + && let Some(def_id) = tcx + .map_opaque_lifetime_to_parent_lifetime(def_id.expect_local()) + .opt_param_def_id(tcx, tcx.parent(opaque_def_id.to_def_id())) { shadowed_captures.insert(def_id); } @@ -585,12 +583,9 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe // Check if the lifetime param was captured but isn't named in the precise captures list. if variances[param.index as usize] == ty::Invariant { if let DefKind::OpaqueTy = tcx.def_kind(tcx.parent(param.def_id)) - && let ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. }) - | ty::ReLateParam(ty::LateParamRegion { - bound_region: ty::BoundRegionKind::BrNamed(def_id, _), - .. - }) = *tcx + && let Some(def_id) = tcx .map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()) + .opt_param_def_id(tcx, tcx.parent(opaque_def_id.to_def_id())) { tcx.dcx().emit_err(errors::LifetimeNotCaptured { opaque_span, @@ -724,7 +719,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { tcx, assoc_item, assoc_item, - ty::TraitRef::new(tcx, def_id.to_def_id(), trait_args), + ty::TraitRef::new_from_args(tcx, def_id.to_def_id(), trait_args), ); } _ => {} @@ -810,7 +805,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { let item = tcx.hir().foreign_item(item.id); match &item.kind { - hir::ForeignItemKind::Fn(fn_decl, _, _) => { + hir::ForeignItemKind::Fn(fn_decl, _, _, _) => { require_c_abi_if_c_variadic(tcx, fn_decl, abi, item.span); } hir::ForeignItemKind::Static(..) => { @@ -884,7 +879,8 @@ pub(super) fn check_specialization_validity<'tcx>( let result = opt_result.unwrap_or(Ok(())); if let Err(parent_impl) = result { - if !tcx.is_impl_trait_in_trait(impl_item) { + // FIXME(effects) the associated type from effects could be specialized + if !tcx.is_impl_trait_in_trait(impl_item) && !tcx.is_effects_desugared_assoc_ty(impl_item) { report_forbidden_specialization(tcx, impl_item, parent_impl); } else { tcx.dcx().delayed_bug(format!("parent item: {parent_impl:?} not marked as default")); @@ -1315,9 +1311,11 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, tcx.local_def_id_to_hir_id(adt.did().expect_local()), span, - "zero-sized fields in `repr(transparent)` cannot \ - contain external non-exhaustive types", |lint| { + lint.primary_message( + "zero-sized fields in `repr(transparent)` cannot \ + contain external non-exhaustive types", + ); let note = if non_exhaustive { "is marked with `#[non_exhaustive]`" } else { @@ -1734,7 +1732,7 @@ pub(super) fn check_coroutine_obligations( .with_opaque_type_inference(def_id) .build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); for (predicate, cause) in &typeck_results.coroutine_stalled_predicates { ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, *predicate)); } 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 44bf8fd2d93..6c53625b590 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -10,7 +10,7 @@ use rustc_hir::intravisit; use rustc_hir::{GenericParamKind, ImplItemKind}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::{util, FulfillmentError}; +use rustc_infer::traits::util; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::util::ExplicitSelf; @@ -21,11 +21,12 @@ use rustc_middle::ty::{ use rustc_middle::ty::{GenericParamDefKind, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_span::Span; +use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; +use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::regions::InferCtxtRegionExt; -use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{ - self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal, + self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal, }; use std::borrow::Cow; use std::iter; @@ -225,7 +226,7 @@ fn compare_method_predicate_entailment<'tcx>( let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); let infcx = &tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds()); @@ -397,7 +398,7 @@ struct RemapLateBound<'a, 'tcx> { } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateBound<'_, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -449,7 +450,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateBound<'_, 'tcx> { pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( tcx: TyCtxt<'tcx>, impl_m_def_id: LocalDefId, -) -> Result<&'tcx DefIdMap<ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed> { +) -> Result<&'tcx DefIdMap<ty::EarlyBinder<'tcx, Ty<'tcx>>>, ErrorGuaranteed> { let impl_m = tcx.opt_associated_item(impl_m_def_id.to_def_id()).unwrap(); let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap(); let impl_trait_ref = @@ -493,7 +494,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( ); let infcx = &tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); // Normalize the impl signature with fresh variables for lifetime inference. let misc_cause = ObligationCause::misc(return_span, impl_m_def_id); @@ -764,17 +765,20 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( Ok(&*tcx.arena.alloc(remapped_types)) } -struct ImplTraitInTraitCollector<'a, 'tcx> { - ocx: &'a ObligationCtxt<'a, 'tcx>, +struct ImplTraitInTraitCollector<'a, 'tcx, E> { + ocx: &'a ObligationCtxt<'a, 'tcx, E>, types: FxIndexMap<DefId, (Ty<'tcx>, ty::GenericArgsRef<'tcx>)>, span: Span, param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, } -impl<'a, 'tcx> ImplTraitInTraitCollector<'a, 'tcx> { +impl<'a, 'tcx, E> ImplTraitInTraitCollector<'a, 'tcx, E> +where + E: 'tcx, +{ fn new( - ocx: &'a ObligationCtxt<'a, 'tcx>, + ocx: &'a ObligationCtxt<'a, 'tcx, E>, span: Span, param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, @@ -783,14 +787,17 @@ impl<'a, 'tcx> ImplTraitInTraitCollector<'a, 'tcx> { } } -impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { +impl<'tcx, E> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx, E> +where + E: 'tcx, +{ + fn cx(&self) -> TyCtxt<'tcx> { self.ocx.infcx.tcx } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { if let ty::Alias(ty::Projection, proj) = ty.kind() - && self.interner().is_impl_trait_in_trait(proj.def_id) + && self.cx().is_impl_trait_in_trait(proj.def_id) { if let Some((ty, _)) = self.types.get(&proj.def_id) { return *ty; @@ -804,9 +811,9 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> { self.types.insert(proj.def_id, (infer_ty, proj.args)); // Recurse into bounds for (pred, pred_span) in self - .interner() + .cx() .explicit_item_bounds(proj.def_id) - .iter_instantiated_copied(self.interner(), proj.args) + .iter_instantiated_copied(self.cx(), proj.args) { let pred = pred.fold_with(self); let pred = self.ocx.normalize( @@ -816,7 +823,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> { ); self.ocx.register_obligation(traits::Obligation::new( - self.interner(), + self.cx(), ObligationCause::new( self.span, self.body_id, @@ -847,7 +854,7 @@ struct RemapHiddenTyRegions<'tcx> { impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> { type Error = ErrorGuaranteed; - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -876,7 +883,8 @@ impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> { ty::ReLateParam(_) => {} // Remap early-bound regions as long as they don't come from the `impl` itself, // in which case we don't really need to renumber them. - ty::ReEarlyParam(ebr) if self.tcx.parent(ebr.def_id) != self.impl_def_id => {} + ty::ReEarlyParam(ebr) + if ebr.index >= self.tcx.generics_of(self.impl_def_id).count() as u32 => {} _ => return Ok(region), } @@ -889,12 +897,8 @@ impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> { ); } } else { - let guar = match region.kind() { - ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. }) - | ty::ReLateParam(ty::LateParamRegion { - bound_region: ty::BoundRegionKind::BrNamed(def_id, _), - .. - }) => { + let guar = match region.opt_param_def_id(self.tcx, self.tcx.parent(self.def_id)) { + Some(def_id) => { let return_span = if let ty::Alias(ty::Opaque, opaque_ty) = self.ty.kind() { self.tcx.def_span(opaque_ty.def_id) } else { @@ -914,7 +918,7 @@ impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> { .with_note(format!("hidden type inferred to be `{}`", self.ty)) .emit() } - _ => { + None => { // This code path is not reached in any tests, but may be // reachable. If this is triggered, it should be converted // to `delayed_bug` and the triggering case turned into a @@ -928,7 +932,6 @@ impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> { Ok(ty::Region::new_early_param( self.tcx, ty::EarlyParamRegion { - def_id: e.def_id, name: e.name, index: (e.index as usize - self.num_trait_args + self.num_impl_args) as u32, }, @@ -979,7 +982,7 @@ fn report_trait_method_mismatch<'tcx>( .next() .unwrap_or(impl_err_span); - diag.span_suggestion( + diag.span_suggestion_verbose( span, "change the self-receiver type to match the trait", sugg, @@ -1003,12 +1006,12 @@ fn report_trait_method_mismatch<'tcx>( } hir::FnRetTy::Return(hir_ty) => { let sugg = trait_sig.output(); - diag.span_suggestion(hir_ty.span, msg, sugg, ap); + diag.span_suggestion_verbose(hir_ty.span, msg, sugg, ap); } }; }; } else if let Some(trait_ty) = trait_sig.inputs().get(*i) { - diag.span_suggestion( + diag.span_suggestion_verbose( impl_err_span, "change the parameter type to match the trait", trait_ty, @@ -1781,7 +1784,7 @@ fn compare_const_predicate_entailment<'tcx>( ); let infcx = tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let impl_ct_own_bounds = impl_ct_predicates.instantiate_own(tcx, impl_args); for (predicate, span) in impl_ct_own_bounds { @@ -1914,7 +1917,7 @@ fn compare_type_predicate_entailment<'tcx>( let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); let infcx = tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds()); @@ -1981,12 +1984,12 @@ pub(super) fn check_type_bounds<'tcx>( let rebased_args = impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args); let infcx = tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); - // A synthetic impl Trait for RPITIT desugaring has no HIR, which we currently use to get the - // span for an impl's associated type. Instead, for these, use the def_span for the synthesized - // associated type. - let impl_ty_span = if impl_ty.is_impl_trait_in_trait() { + // A synthetic impl Trait for RPITIT desugaring or assoc type for effects desugaring has no HIR, + // which we currently use to get the span for an impl's associated type. Instead, for these, + // use the def_span for the synthesized associated type. + let impl_ty_span = if impl_ty.is_impl_trait_in_trait() || impl_ty.is_effects_desugaring { tcx.def_span(impl_ty_def_id) } else { match tcx.hir_node_by_def_id(impl_ty_def_id) { @@ -2030,10 +2033,19 @@ pub(super) fn check_type_bounds<'tcx>( // to its definition type. This should be the param-env we use to *prove* the // predicate too, but we don't do that because of performance issues. // See <https://github.com/rust-lang/rust/pull/117542#issue-1976337685>. + let trait_projection_ty = Ty::new_projection_from_args(tcx, trait_ty.def_id, rebased_args); + let impl_identity_ty = tcx.type_of(impl_ty.def_id).instantiate_identity(); let normalize_param_env = param_env_with_gat_bounds(tcx, impl_ty, impl_trait_ref); for mut obligation in util::elaborate(tcx, obligations) { - let normalized_predicate = - ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate); + let normalized_predicate = if infcx.next_trait_solver() { + obligation.predicate.fold_with(&mut ReplaceTy { + tcx, + from: trait_projection_ty, + to: impl_identity_ty, + }) + } else { + ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate) + }; debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate); obligation.predicate = normalized_predicate; @@ -2054,6 +2066,22 @@ pub(super) fn check_type_bounds<'tcx>( ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env) } +struct ReplaceTy<'tcx> { + tcx: TyCtxt<'tcx>, + from: Ty<'tcx>, + to: Ty<'tcx>, +} + +impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceTy<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if self.from == ty { self.to } else { ty.super_fold_with(self) } + } +} + /// Install projection predicates that allow GATs to project to their own /// definition types. This is not allowed in general in cases of default /// associated types in trait definitions, or when specialization is involved, @@ -2171,9 +2199,6 @@ fn param_env_with_gat_bounds<'tcx>( tcx, ty::INNERMOST, ty::BoundVar::from_usize(bound_vars.len() - 1), - tcx.type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), ) .into() } @@ -2206,7 +2231,11 @@ fn param_env_with_gat_bounds<'tcx>( _ => predicates.push( ty::Binder::bind_with_vars( ty::ProjectionPredicate { - projection_term: ty::AliasTerm::new(tcx, trait_ty.def_id, rebased_args), + projection_term: ty::AliasTerm::new_from_args( + tcx, + trait_ty.def_id, + rebased_args, + ), term: normalize_impl_ty.into(), }, bound_vars, @@ -2254,7 +2283,7 @@ fn try_report_async_mismatch<'tcx>( && let Some(proj) = proj.no_bound_vars() && infcx.can_eq( error.root_obligation.param_env, - proj.term.ty().unwrap(), + proj.term.expect_type(), impl_sig.output(), ) { 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 ca08eeea227..ad3324f79e2 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 @@ -171,10 +171,10 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( } // 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 { - // This code path is not reached in any tests, but may be reachable. If - // this is triggered, it should be converted to `delayed_bug` and the - // triggering case turned into a test. - tcx.dcx().bug("encountered errors when checking RPITIT refinement (resolution)"); + // If resolution didn't fully complete, we cannot continue checking RPITIT refinement, and + // delay a bug as the original code contains load-bearing errors. + tcx.dcx().delayed_bug("encountered errors when checking RPITIT refinement (resolution)"); + return; }; // For quicker lookup, use an `IndexSet` (we don't use one earlier because @@ -267,7 +267,7 @@ fn report_mismatched_rpitit_signature<'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(), + ty::ClauseKind::Projection(proj) => proj.term.as_type(), _ => None, }) else { @@ -322,7 +322,7 @@ struct Anonymize<'tcx> { } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Anonymize<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index be412dde968..19371448025 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -1,6 +1,7 @@ // FIXME(@lcnr): Move this module out of `rustc_hir_analysis`. // // We don't do any drop checking during hir typeck. + use rustc_data_structures::fx::FxHashSet; use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; @@ -123,7 +124,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( adt_to_impl_args: GenericArgsRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { let infcx = tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); // Take the param-env of the adt and instantiate the args that show up in // the implementation's self type. This gives us the assumptions that the diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index 25ac31c16c7..ce921f64481 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -7,7 +7,7 @@ use rustc_session::config::EntryFnType; use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_span::{symbol::sym, Span}; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; +use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; use std::ops::Not; @@ -133,7 +133,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { main_diagnostics_def_id, ObligationCauseCode::MainFunctionType, ); - let ocx = traits::ObligationCtxt::new(&infcx); + let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx); let norm_return_ty = ocx.normalize(&cause, param_env, return_ty); ocx.register_bound(cause, param_env, norm_return_ty, term_did); let errors = ocx.select_all_or_error(); diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs index a49626eed35..17cb20df754 100644 --- a/compiler/rustc_hir_analysis/src/check/errs.rs +++ b/compiler/rustc_hir_analysis/src/check/errs.rs @@ -41,7 +41,8 @@ fn path_if_static_mut(tcx: TyCtxt<'_>, expr: &hir::Expr<'_>) -> Option<String> { if let hir::ExprKind::Path(qpath) = expr.kind && let hir::QPath::Resolved(_, path) = qpath && let hir::def::Res::Def(def_kind, _) = path.res - && let hir::def::DefKind::Static { mutability: Mutability::Mut, nested: false } = def_kind + && let hir::def::DefKind::Static { safety: _, mutability: Mutability::Mut, nested: false } = + def_kind { return Some(qpath_to_string(&tcx, &qpath)); } @@ -62,7 +63,7 @@ fn handle_static_mut_ref( } else { (errors::StaticMutRefSugg::Shared { span, var }, "shared") }; - tcx.sess.psess.dcx.emit_err(errors::StaticMutRef { span, sugg, shared }); + tcx.dcx().emit_err(errors::StaticMutRef { span, sugg, shared }); } else { let (sugg, shared) = if mutable == Mutability::Mut { (errors::RefOfMutStaticSugg::Mut { span, var }, "mutable") diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 50fe20346cf..6282499883b 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -26,15 +26,12 @@ fn equate_intrinsic_type<'tcx>( n_cts: usize, sig: ty::PolyFnSig<'tcx>, ) { - let (own_counts, span) = match tcx.hir_node_by_def_id(def_id) { + let (generics, span) = match tcx.hir_node_by_def_id(def_id) { hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. }) | hir::Node::ForeignItem(hir::ForeignItem { - kind: hir::ForeignItemKind::Fn(.., generics), + kind: hir::ForeignItemKind::Fn(.., generics, _), .. - }) => { - let own_counts = tcx.generics_of(def_id).own_counts(); - (own_counts, generics.span) - } + }) => (tcx.generics_of(def_id), generics.span), _ => { struct_span_code_err!(tcx.dcx(), span, E0622, "intrinsic must be a function") .with_span_label(span, "expected a function") @@ -42,6 +39,7 @@ fn equate_intrinsic_type<'tcx>( return; } }; + let own_counts = generics.own_counts(); let gen_count_ok = |found: usize, expected: usize, descr: &str| -> bool { if found != expected { @@ -57,9 +55,17 @@ fn equate_intrinsic_type<'tcx>( } }; + // the host effect param should be invisible as it shouldn't matter + // whether effects is enabled for the intrinsic provider crate. + let consts_count = if generics.host_effect_index.is_some() { + own_counts.consts - 1 + } else { + own_counts.consts + }; + if gen_count_ok(own_counts.lifetimes, n_lts, "lifetime") && gen_count_ok(own_counts.types, n_tps, "type") - && gen_count_ok(own_counts.consts, n_cts, "const") + && gen_count_ok(consts_count, n_cts, "const") { let _ = check_function_signature( tcx, @@ -130,6 +136,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) - | sym::is_val_statically_known | sym::ptr_mask | sym::aggregate_raw_ptr + | sym::ptr_metadata | sym::ub_checks | sym::fadd_algebraic | sym::fsub_algebraic @@ -164,9 +171,8 @@ pub fn check_intrinsic_type( ) { let generics = tcx.generics_of(intrinsic_id); let param = |n| { - if let Some(&ty::GenericParamDef { - name, kind: ty::GenericParamDefKind::Type { .. }, .. - }) = generics.opt_param_at(n as usize, tcx) + if let &ty::GenericParamDef { name, kind: ty::GenericParamDefKind::Type { .. }, .. } = + generics.param_at(n as usize, tcx) { Ty::new_param(tcx, n, name) } else { @@ -429,17 +435,17 @@ pub fn check_intrinsic_type( sym::ptr_guaranteed_cmp => ( 1, - 1, + 0, vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))], tcx.types.u8, ), sym::const_allocate => { - (0, 1, vec![tcx.types.usize, tcx.types.usize], Ty::new_mut_ptr(tcx, tcx.types.u8)) + (0, 0, vec![tcx.types.usize, tcx.types.usize], Ty::new_mut_ptr(tcx, tcx.types.u8)) } sym::const_deallocate => ( 0, - 1, + 0, vec![Ty::new_mut_ptr(tcx, tcx.types.u8), tcx.types.usize, tcx.types.usize], tcx.types.unit, ), @@ -478,16 +484,16 @@ pub fn check_intrinsic_type( | sym::frem_algebraic => (1, 0, vec![param(0), param(0)], param(0)), sym::float_to_int_unchecked => (2, 0, vec![param(0)], param(1)), - sym::assume => (0, 1, vec![tcx.types.bool], tcx.types.unit), - sym::likely => (0, 1, vec![tcx.types.bool], tcx.types.bool), - sym::unlikely => (0, 1, vec![tcx.types.bool], tcx.types.bool), + sym::assume => (0, 0, vec![tcx.types.bool], tcx.types.unit), + sym::likely => (0, 0, vec![tcx.types.bool], tcx.types.bool), + sym::unlikely => (0, 0, vec![tcx.types.bool], tcx.types.bool), sym::read_via_copy => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)), sym::write_via_move => { (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit) } - sym::typed_swap => (1, 1, vec![Ty::new_mut_ptr(tcx, param(0)); 2], tcx.types.unit), + sym::typed_swap => (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)); 2], tcx.types.unit), sym::discriminant_value => { let assoc_items = tcx.associated_item_def_ids( @@ -504,7 +510,11 @@ pub fn check_intrinsic_type( ty::Region::new_bound(tcx, ty::INNERMOST, br), param(0), )], - Ty::new_projection(tcx, discriminant_def_id, tcx.mk_args(&[param(0).into()])), + Ty::new_projection_from_args( + tcx, + discriminant_def_id, + tcx.mk_args(&[param(0).into()]), + ), ) } @@ -566,9 +576,9 @@ pub fn check_intrinsic_type( sym::black_box => (1, 0, vec![param(0)], param(0)), - sym::is_val_statically_known => (1, 1, vec![param(0)], tcx.types.bool), + sym::is_val_statically_known => (1, 0, vec![param(0)], tcx.types.bool), - sym::const_eval_select => (4, 1, vec![param(0), param(1), param(2)], param(3)), + sym::const_eval_select => (4, 0, vec![param(0), param(1), param(2)], param(3)), sym::vtable_size | sym::vtable_align => { (0, 0, vec![Ty::new_imm_ptr(tcx, tcx.types.unit)], tcx.types.usize) @@ -576,9 +586,10 @@ pub fn check_intrinsic_type( // This type check is not particularly useful, but the `where` bounds // on the definition in `core` do the heavy lifting for checking it. - sym::aggregate_raw_ptr => (3, 1, vec![param(1), param(2)], param(0)), + sym::aggregate_raw_ptr => (3, 0, vec![param(1), param(2)], param(0)), + sym::ptr_metadata => (2, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(1)), - sym::ub_checks => (0, 1, Vec::new(), tcx.types.bool), + sym::ub_checks => (0, 0, Vec::new(), tcx.types.bool), sym::simd_eq | sym::simd_ne diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index b09de1a4a09..2e965c59ebb 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -1,6 +1,6 @@ use rustc_ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxIndexSet; -use rustc_hir as hir; +use rustc_hir::{self as hir, LangItem}; use rustc_middle::bug; use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy}; use rustc_session::lint; @@ -62,8 +62,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { ty::Int(IntTy::I64) | ty::Uint(UintTy::U64) => Some(InlineAsmType::I64), ty::Int(IntTy::I128) | ty::Uint(UintTy::U128) => Some(InlineAsmType::I128), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(asm_ty_isize), + ty::Float(FloatTy::F16) => Some(InlineAsmType::F16), ty::Float(FloatTy::F32) => Some(InlineAsmType::F32), ty::Float(FloatTy::F64) => Some(InlineAsmType::F64), + ty::Float(FloatTy::F128) => Some(InlineAsmType::F128), ty::FnPtr(_) => Some(asm_ty_isize), ty::RawPtr(ty, _) if self.is_thin_ptr_ty(ty) => Some(asm_ty_isize), ty::Adt(adt, args) if adt.repr().simd() => { @@ -105,8 +107,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { width => bug!("unsupported pointer width: {width}"), }) } + ty::Float(FloatTy::F16) => Some(InlineAsmType::VecF16(size)), ty::Float(FloatTy::F32) => Some(InlineAsmType::VecF32(size)), ty::Float(FloatTy::F64) => Some(InlineAsmType::VecF64(size)), + ty::Float(FloatTy::F128) => Some(InlineAsmType::VecF128(size)), _ => None, } } @@ -134,7 +138,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { // `!` is allowed for input but not for output (issue #87802) ty::Never if is_input => return None, _ if ty.references_error() => return None, - ty::Adt(adt, args) if Some(adt.did()) == self.tcx.lang_items().maybe_uninit() => { + ty::Adt(adt, args) if self.tcx.is_lang_item(adt.did(), LangItem::MaybeUninit) => { let fields = &adt.non_enum_variant().fields; let ty = fields[FieldIdx::from_u32(1)].ty(self.tcx, args); // FIXME: Are we just trying to map to the `T` in `MaybeUninit<T>`? @@ -281,8 +285,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { lint::builtin::ASM_SUB_REGISTER, expr.hir_id, spans, - "formatting may not be suitable for sub-register argument", |lint| { + lint.primary_message("formatting may not be suitable for sub-register argument"); lint.span_label(expr.span, "for this argument"); lint.help(format!( "use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}` (for {suggested_size}-bit values)", diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 0083da2a1e4..9fef31acef8 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -82,7 +82,7 @@ use rustc_errors::{pluralize, struct_span_code_err, Diag}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_index::bit_set::BitSet; -use rustc_infer::infer::error_reporting::ObligationCauseExt as _; +use rustc_infer::error_reporting::infer::ObligationCauseExt as _; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, TyCtxtInferExt as _}; use rustc_infer::traits::ObligationCause; @@ -96,10 +96,10 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::traits::error_reporting::suggestions::{ +use rustc_trait_selection::error_reporting::traits::suggestions::{ ReturnsVisitor, TypeErrCtxtExt as _, }; -use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; +use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _; use rustc_trait_selection::traits::ObligationCtxt; use crate::errors; @@ -112,6 +112,7 @@ pub fn provide(providers: &mut Providers) { wfcheck::provide(providers); *providers = Providers { adt_destructor, + adt_async_destructor, region_scope_tree, collect_return_position_impl_trait_in_trait_tys, compare_impl_const: compare_impl_item::compare_impl_const_raw, @@ -124,6 +125,10 @@ fn adt_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Destructor> tcx.calculate_dtor(def_id.to_def_id(), dropck::check_drop_impl) } +fn adt_async_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::AsyncDestructor> { + tcx.calculate_async_dtor(def_id.to_def_id(), dropck::check_drop_impl) +} + /// Given a `DefId` for an opaque type in return position, find its parent item's return /// expressions. fn get_owner_return_paths( @@ -206,11 +211,18 @@ fn missing_items_err( .collect::<Vec<_>>() .join("`, `"); - // `Span` before impl block closing brace. - let hi = full_impl_span.hi() - BytePos(1); - // Point at the place right before the closing brace of the relevant `impl` to suggest - // adding the associated item at the end of its body. - let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi); + let sugg_sp = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(full_impl_span) + && snippet.ends_with("}") + { + // `Span` before impl block closing brace. + let hi = full_impl_span.hi() - BytePos(1); + // Point at the place right before the closing brace of the relevant `impl` to suggest + // adding the associated item at the end of its body. + full_impl_span.with_lo(hi).with_hi(hi) + } else { + full_impl_span.shrink_to_hi() + }; + // Obtain the level of indentation ending in `sugg_sp`. let padding = tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new()); @@ -436,7 +448,9 @@ fn fn_sig_suggestion<'tcx>( output = if let ty::Alias(_, alias_ty) = *output.kind() { tcx.explicit_item_super_predicates(alias_ty.def_id) .iter_instantiated_copied(tcx, alias_ty.args) - .find_map(|(bound, _)| bound.as_projection_clause()?.no_bound_vars()?.term.ty()) + .find_map(|(bound, _)| { + bound.as_projection_clause()?.no_bound_vars()?.term.as_type() + }) .unwrap_or_else(|| { span_bug!( ident.span, @@ -594,7 +608,7 @@ pub fn check_function_signature<'tcx>( let param_env = ty::ParamEnv::empty(); let infcx = &tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); let actual_sig = tcx.fn_sig(fn_id).instantiate_identity(); diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index e51f95eed02..2b5efd3b2f6 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -6,7 +6,6 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html -use rustc_ast::visit::visit_opt; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -168,7 +167,14 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => visitor.visit_stmt(statement), } } - visit_opt!(visitor, visit_expr, &blk.expr); + if let Some(tail_expr) = blk.expr { + if visitor.tcx.features().shorter_tail_lifetimes + && blk.span.edition().at_least_rust_2024() + { + visitor.terminating_scopes.insert(tail_expr.hir_id.local_id); + } + visitor.visit_expr(tail_expr); + } } visitor.cx = prev_cx; @@ -782,25 +788,8 @@ impl<'tcx> RegionResolutionVisitor<'tcx> { } self.enter_scope(Scope { id, data: ScopeData::Node }); } -} - -impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { - fn visit_block(&mut self, b: &'tcx Block<'tcx>) { - resolve_block(self, b); - } - - fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) { - let body_id = body.id(); - let owner_id = self.tcx.hir().body_owner_def_id(body_id); - - debug!( - "visit_body(id={:?}, span={:?}, body.id={:?}, cx.parent={:?})", - owner_id, - self.tcx.sess.source_map().span_to_diagnostic_string(body.value.span), - body_id, - self.cx.parent - ); + fn enter_body(&mut self, hir_id: hir::HirId, f: impl FnOnce(&mut Self)) { // Save all state that is specific to the outer function // body. These will be restored once down below, once we've // visited the body. @@ -812,43 +801,12 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { // control flow assumptions. This doesn't apply to nested // bodies within the `+=` statements. See #69307. let outer_pessimistic_yield = mem::replace(&mut self.pessimistic_yield, false); - self.terminating_scopes.insert(body.value.hir_id.local_id); + self.terminating_scopes.insert(hir_id.local_id); - self.enter_scope(Scope { id: body.value.hir_id.local_id, data: ScopeData::CallSite }); - self.enter_scope(Scope { id: body.value.hir_id.local_id, data: ScopeData::Arguments }); + self.enter_scope(Scope { id: hir_id.local_id, data: ScopeData::CallSite }); + self.enter_scope(Scope { id: hir_id.local_id, data: ScopeData::Arguments }); - // The arguments and `self` are parented to the fn. - self.cx.var_parent = self.cx.parent.take(); - for param in body.params { - self.visit_pat(param.pat); - } - - // The body of the every fn is a root scope. - self.cx.parent = self.cx.var_parent; - if self.tcx.hir().body_owner_kind(owner_id).is_fn_or_closure() { - self.visit_expr(body.value) - } else { - // Only functions have an outer terminating (drop) scope, while - // temporaries in constant initializers may be 'static, but only - // according to rvalue lifetime semantics, using the same - // syntactical rules used for let initializers. - // - // e.g., in `let x = &f();`, the temporary holding the result from - // the `f()` call lives for the entirety of the surrounding block. - // - // Similarly, `const X: ... = &f();` would have the result of `f()` - // live for `'static`, implying (if Drop restrictions on constants - // ever get lifted) that the value *could* have a destructor, but - // it'd get leaked instead of the destructor running during the - // evaluation of `X` (if at all allowed by CTFE). - // - // However, `const Y: ... = g(&f());`, like `let y = g(&f());`, - // would *not* let the `f()` temporary escape into an outer scope - // (i.e., `'static`), which means that after `g` returns, it drops, - // and all the associated destruction scope rules apply. - self.cx.var_parent = None; - resolve_local(self, None, Some(body.value)); - } + f(self); // Restore context we had at the start. self.expr_and_pat_count = outer_ec; @@ -856,6 +814,60 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { self.terminating_scopes = outer_ts; self.pessimistic_yield = outer_pessimistic_yield; } +} + +impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { + fn visit_block(&mut self, b: &'tcx Block<'tcx>) { + resolve_block(self, b); + } + + fn visit_body(&mut self, body: &hir::Body<'tcx>) { + let body_id = body.id(); + let owner_id = self.tcx.hir().body_owner_def_id(body_id); + + debug!( + "visit_body(id={:?}, span={:?}, body.id={:?}, cx.parent={:?})", + owner_id, + self.tcx.sess.source_map().span_to_diagnostic_string(body.value.span), + body_id, + self.cx.parent + ); + + self.enter_body(body.value.hir_id, |this| { + if this.tcx.hir().body_owner_kind(owner_id).is_fn_or_closure() { + // The arguments and `self` are parented to the fn. + this.cx.var_parent = this.cx.parent.take(); + for param in body.params { + this.visit_pat(param.pat); + } + + // The body of the every fn is a root scope. + this.cx.parent = this.cx.var_parent; + this.visit_expr(body.value) + } else { + // Only functions have an outer terminating (drop) scope, while + // temporaries in constant initializers may be 'static, but only + // according to rvalue lifetime semantics, using the same + // syntactical rules used for let initializers. + // + // e.g., in `let x = &f();`, the temporary holding the result from + // the `f()` call lives for the entirety of the surrounding block. + // + // Similarly, `const X: ... = &f();` would have the result of `f()` + // live for `'static`, implying (if Drop restrictions on constants + // ever get lifted) that the value *could* have a destructor, but + // it'd get leaked instead of the destructor running during the + // evaluation of `X` (if at all allowed by CTFE). + // + // However, `const Y: ... = g(&f());`, like `let y = g(&f());`, + // would *not* let the `f()` temporary escape into an outer scope + // (i.e., `'static`), which means that after `g` returns, it drops, + // and all the associated destruction scope rules apply. + this.cx.var_parent = None; + resolve_local(this, None, Some(body.value)); + } + }) + } fn visit_arm(&mut self, a: &'tcx Arm<'tcx>) { resolve_arm(self, a); @@ -887,7 +899,7 @@ pub fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree { return tcx.region_scope_tree(typeck_root_def_id); } - let scope_tree = if let Some(body_id) = tcx.hir().maybe_body_owned_by(def_id.expect_local()) { + let scope_tree = if let Some(body) = tcx.hir().maybe_body_owned_by(def_id.expect_local()) { let mut visitor = RegionResolutionVisitor { tcx, scope_tree: ScopeTree::default(), @@ -898,9 +910,8 @@ pub fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree { fixup_scopes: vec![], }; - let body = tcx.hir().body(body_id); visitor.scope_tree.root_body = Some(body.value.hir_id); - visitor.visit_body(body); + visitor.visit_body(&body); visitor.scope_tree } else { ScopeTree::default() diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index e8ede804c3f..b2ef07d65c5 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -29,29 +29,30 @@ use rustc_session::parse::feature_err; use rustc_span::symbol::{sym, Ident}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; +use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; use rustc_trait_selection::regions::InferCtxtRegionExt; -use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::misc::{ type_allowed_to_implement_const_param_ty, ConstParamTyImplementationError, }; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{ - self, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc, + self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc, }; +use rustc_type_ir::solve::NoSolution; use rustc_type_ir::TypeFlags; use std::cell::LazyCell; use std::ops::{ControlFlow, Deref}; pub(super) struct WfCheckingCtxt<'a, 'tcx> { - pub(super) ocx: ObligationCtxt<'a, 'tcx>, + pub(super) ocx: ObligationCtxt<'a, 'tcx, FulfillmentError<'tcx>>, span: Span, body_def_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, } impl<'a, 'tcx> Deref for WfCheckingCtxt<'a, 'tcx> { - type Target = ObligationCtxt<'a, 'tcx>; + type Target = ObligationCtxt<'a, 'tcx, FulfillmentError<'tcx>>; fn deref(&self) -> &Self::Target { &self.ocx } @@ -106,7 +107,7 @@ where { let param_env = tcx.param_env(body_def_id); let infcx = &tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); let mut wfcx = WfCheckingCtxt { ocx, span, body_def_id, param_env }; @@ -119,16 +120,7 @@ where let errors = wfcx.select_all_or_error(); if !errors.is_empty() { - let err = infcx.err_ctxt().report_fulfillment_errors(errors); - if tcx.dcx().has_errors().is_some() { - return Err(err); - } else { - // HACK(oli-obk): tests/ui/specialization/min_specialization/specialize_on_type_error.rs - // causes an delayed bug during normalization, without reporting an error, so we need - // to act as if no error happened, in order to let our callers continue and report an - // error later in check_impl_items_against_trait. - return Ok(()); - } + return Err(infcx.err_ctxt().report_fulfillment_errors(errors)); } debug!(?assumed_wf_types); @@ -486,7 +478,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { param_env, item_def_id, tcx.explicit_item_bounds(item_def_id) - .instantiate_identity_iter_copied() + .iter_identity_copied() .collect::<Vec<_>>(), &FxIndexSet::default(), gat_def_id, @@ -675,11 +667,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( let region_param = gat_generics.param_at(*region_a_idx, tcx); let region_param = ty::Region::new_early_param( tcx, - ty::EarlyParamRegion { - def_id: region_param.def_id, - index: region_param.index, - name: region_param.name, - }, + ty::EarlyParamRegion { index: region_param.index, name: region_param.name }, ); // The predicate we expect to see. (In our example, // `Self: 'me`.) @@ -708,21 +696,13 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( let region_a_param = gat_generics.param_at(*region_a_idx, tcx); let region_a_param = ty::Region::new_early_param( tcx, - ty::EarlyParamRegion { - def_id: region_a_param.def_id, - index: region_a_param.index, - name: region_a_param.name, - }, + ty::EarlyParamRegion { index: region_a_param.index, name: region_a_param.name }, ); // Same for the region. let region_b_param = gat_generics.param_at(*region_b_idx, tcx); let region_b_param = ty::Region::new_early_param( tcx, - ty::EarlyParamRegion { - def_id: region_b_param.def_id, - index: region_b_param.index, - name: region_b_param.name, - }, + ty::EarlyParamRegion { index: region_b_param.index, name: region_b_param.name }, ); // The predicate we expect to see. bounds.insert( @@ -893,7 +873,7 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem _ => {} } if !trait_should_be_self.is_empty() { - if tcx.check_is_object_safe(trait_def_id) { + if tcx.is_object_safe(trait_def_id) { return; } let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect(); @@ -934,7 +914,12 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => Ok(()), // Const parameters are well formed if their type is structural match. - hir::GenericParamKind::Const { ty: hir_ty, default: _, is_host_effect: _ } => { + hir::GenericParamKind::Const { + ty: hir_ty, + default: _, + is_host_effect: _, + synthetic: _, + } => { let ty = tcx.type_of(param.def_id).instantiate_identity(); if tcx.features().adt_const_params { @@ -1220,17 +1205,16 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocIt let bounds = wfcx.tcx().explicit_item_bounds(item.def_id); debug!("check_associated_type_bounds: bounds={:?}", bounds); - let wf_obligations = - bounds.instantiate_identity_iter_copied().flat_map(|(bound, bound_span)| { - let normalized_bound = wfcx.normalize(span, None, bound); - traits::wf::clause_obligations( - wfcx.infcx, - wfcx.param_env, - wfcx.body_def_id, - normalized_bound, - bound_span, - ) - }); + let wf_obligations = bounds.iter_identity_copied().flat_map(|(bound, bound_span)| { + let normalized_bound = wfcx.normalize(span, None, bound); + traits::wf::clause_obligations( + wfcx.infcx, + wfcx.param_env, + wfcx.body_def_id, + normalized_bound, + bound_span, + ) + }); wfcx.register_obligations(wf_obligations); } @@ -1728,13 +1712,12 @@ fn receiver_is_valid<'tcx>( let cause = ObligationCause::new(span, wfcx.body_def_id, traits::ObligationCauseCode::MethodReceiver); - let can_eq_self = |ty| infcx.can_eq(wfcx.param_env, self_ty, ty); - - // `self: Self` is always valid. - if can_eq_self(receiver_ty) { - if let Err(err) = wfcx.eq(&cause, wfcx.param_env, self_ty, receiver_ty) { - infcx.err_ctxt().report_mismatched_types(&cause, self_ty, receiver_ty, err).emit(); - } + // Special case `receiver == self_ty`, which doesn't necessarily require the `Receiver` lang item. + if let Ok(()) = wfcx.infcx.commit_if_ok(|_| { + let ocx = ObligationCtxt::new(wfcx.infcx); + ocx.eq(&cause, wfcx.param_env, self_ty, receiver_ty)?; + if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) } + }) { return true; } @@ -1745,58 +1728,51 @@ fn receiver_is_valid<'tcx>( autoderef = autoderef.include_raw_pointers(); } - // The first type is `receiver_ty`, which we know its not equal to `self_ty`; skip it. - autoderef.next(); - let receiver_trait_def_id = tcx.require_lang_item(LangItem::Receiver, Some(span)); // Keep dereferencing `receiver_ty` until we get to `self_ty`. - loop { - if let Some((potential_self_ty, _)) = autoderef.next() { - debug!( - "receiver_is_valid: potential self type `{:?}` to match `{:?}`", - potential_self_ty, self_ty - ); - - if can_eq_self(potential_self_ty) { - wfcx.register_obligations(autoderef.into_obligations()); + while let Some((potential_self_ty, _)) = autoderef.next() { + debug!( + "receiver_is_valid: potential self type `{:?}` to match `{:?}`", + potential_self_ty, self_ty + ); - if let Err(err) = wfcx.eq(&cause, wfcx.param_env, self_ty, potential_self_ty) { - infcx - .err_ctxt() - .report_mismatched_types(&cause, self_ty, potential_self_ty, err) - .emit(); - } + // Check if the self type unifies. If it does, then commit the result + // since it may have region side-effects. + if let Ok(()) = wfcx.infcx.commit_if_ok(|_| { + let ocx = ObligationCtxt::new(wfcx.infcx); + ocx.eq(&cause, wfcx.param_env, self_ty, potential_self_ty)?; + if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) } + }) { + wfcx.register_obligations(autoderef.into_obligations()); + return true; + } + // Without `feature(arbitrary_self_types)`, we require that each step in the + // deref chain implement `receiver`. + if !arbitrary_self_types_enabled { + if !receiver_is_implemented( + wfcx, + receiver_trait_def_id, + cause.clone(), + potential_self_ty, + ) { + // We cannot proceed. break; - } else { - // Without `feature(arbitrary_self_types)`, we require that each step in the - // deref chain implement `receiver` - if !arbitrary_self_types_enabled - && !receiver_is_implemented( - wfcx, - receiver_trait_def_id, - cause.clone(), - potential_self_ty, - ) - { - return false; - } } - } else { - debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty); - return false; - } - } - // Without `feature(arbitrary_self_types)`, we require that `receiver_ty` implements `Receiver`. - if !arbitrary_self_types_enabled - && !receiver_is_implemented(wfcx, receiver_trait_def_id, cause.clone(), receiver_ty) - { - return false; + // Register the bound, in case it has any region side-effects. + wfcx.register_bound( + cause.clone(), + wfcx.param_env, + potential_self_ty, + receiver_trait_def_id, + ); + } } - true + debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty); + false } fn receiver_is_implemented<'tcx>( @@ -2101,16 +2077,14 @@ fn lint_redundant_lifetimes<'tcx>( } for &victim in &lifetimes[(idx + 1)..] { - // We should only have late-bound lifetimes of the `BrNamed` variety, - // since we get these signatures straight from `hir_lowering`. And any - // other regions (ReError/ReStatic/etc.) shouldn't matter, since we + // All region parameters should have a `DefId` available as: + // - Late-bound parameters should be of the`BrNamed` variety, + // since we get these signatures straight from `hir_lowering`. + // - Early-bound parameters unconditionally have a `DefId` available. + // + // Any other regions (ReError/ReStatic/etc.) shouldn't matter, since we // can't really suggest to remove them. - let (ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. }) - | ty::ReLateParam(ty::LateParamRegion { - bound_region: ty::BoundRegionKind::BrNamed(def_id, _), - .. - })) = victim.kind() - else { + let Some(def_id) = victim.opt_param_def_id(tcx, owner_id.to_def_id()) else { continue; }; diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs index aa5db4f6aa7..ed23dc2a827 100644 --- a/compiler/rustc_hir_analysis/src/check_unused.rs +++ b/compiler/rustc_hir_analysis/src/check_unused.rs @@ -35,11 +35,12 @@ fn check_unused_traits(tcx: TyCtxt<'_>, (): ()) { continue; } let (path, _) = item.expect_use(); - let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) { - format!("unused import: `{snippet}`") - } else { - "unused import".to_owned() - }; - tcx.node_span_lint(lint::builtin::UNUSED_IMPORTS, item.hir_id(), path.span, msg, |_| {}); + tcx.node_span_lint(lint::builtin::UNUSED_IMPORTS, item.hir_id(), path.span, |lint| { + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) { + lint.primary_message(format!("unused import: `{snippet}`")); + } else { + lint.primary_message("unused import"); + } + }); } } diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 8f0aba1c38c..2ecb170ec89 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::adjustment::CoerceUnsizedInfo; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::{Span, DUMMY_SP}; -use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; use rustc_trait_selection::traits::misc::{ type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy, ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason, @@ -267,7 +267,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() .join(", "), })); } else { - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); for field in coerced_fields { ocx.register_obligation(Obligation::new( tcx, @@ -480,7 +480,7 @@ pub fn coerce_unsized_info<'tcx>( }; // Register an obligation for `A: Trait<B>`. - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let cause = traits::ObligationCause::misc(span, impl_did); let obligation = Obligation::new( tcx, @@ -554,7 +554,7 @@ fn infringing_fields_error( if let ty::Param(_) = ty.kind() { bounds.push(( format!("{ty}"), - trait_ref.print_only_trait_path().to_string(), + trait_ref.print_trait_sugared().to_string(), Some(trait_ref.def_id), )); } diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index 054a3af212a..e9961d3ad08 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -8,11 +8,11 @@ use crate::errors; use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::LangItem; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_session::parse::feature_err; use rustc_span::{sym, ErrorGuaranteed}; -use rustc_trait_selection::traits; mod builtin; mod inherent_impls; @@ -50,7 +50,7 @@ fn enforce_trait_manually_implementable( ) -> Result<(), ErrorGuaranteed> { let impl_header_span = tcx.def_span(impl_def_id); - if tcx.lang_items().freeze_trait() == Some(trait_def_id) { + if tcx.is_lang_item(trait_def_id, LangItem::Freeze) { if !tcx.features().freeze_impls { feature_err( &tcx.sess, @@ -76,7 +76,7 @@ fn enforce_trait_manually_implementable( // Maintain explicit error code for `Unsize`, since it has a useful // explanation about using `CoerceUnsized` instead. - if Some(trait_def_id) == tcx.lang_items().unsize_trait() { + if tcx.is_lang_item(trait_def_id, LangItem::Unsize) { err.code(E0328); } @@ -192,14 +192,14 @@ fn check_object_overlap<'tcx>( }); for component_def_id in component_def_ids { - if !tcx.check_is_object_safe(component_def_id) { + if !tcx.is_object_safe(component_def_id) { // Without the 'object_safe_for_dispatch' feature this is an error // which will be reported by wfcheck. Ignore it here. // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`. // With the feature enabled, the trait is not implemented automatically, // so this is valid. } else { - let mut supertrait_def_ids = traits::supertrait_def_ids(tcx, component_def_id); + let mut supertrait_def_ids = tcx.supertrait_def_ids(component_def_id); if supertrait_def_ids.any(|d| d == trait_def_id) { let span = tcx.def_span(impl_def_id); return Err(struct_span_code_err!( diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index bdac0d9b0b4..16f72f38d60 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -14,7 +14,6 @@ use rustc_middle::{bug, span_bug}; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_trait_selection::traits::{self, IsFirstInputType, UncoveredTyParams}; use rustc_trait_selection::traits::{OrphanCheckErr, OrphanCheckMode}; -use rustc_trait_selection::traits::{StructurallyNormalizeExt, TraitEngineExt}; #[instrument(level = "debug", skip(tcx))] pub(crate) fn orphan_check_impl( @@ -287,7 +286,7 @@ fn orphan_check<'tcx>( tcx: TyCtxt<'tcx>, impl_def_id: LocalDefId, mode: OrphanCheckMode, -) -> Result<(), OrphanCheckErr<'tcx, FxIndexSet<DefId>>> { +) -> Result<(), OrphanCheckErr<TyCtxt<'tcx>, FxIndexSet<DefId>>> { // We only accept this routine to be invoked on implementations // of a trait, not inherent implementations. let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); @@ -317,27 +316,26 @@ fn orphan_check<'tcx>( } let ty = if infcx.next_trait_solver() { - let mut fulfill_cx = <dyn traits::TraitEngine<'_>>::new(&infcx); - infcx - .at(&cause, ty::ParamEnv::empty()) - .structurally_normalize(ty, &mut *fulfill_cx) - .map(|ty| infcx.resolve_vars_if_possible(ty)) - .unwrap_or(ty) + ocx.structurally_normalize( + &cause, + ty::ParamEnv::empty(), + infcx.resolve_vars_if_possible(ty), + ) + .unwrap_or(ty) } else { ty }; - Ok(ty) + Ok::<_, !>(ty) }; - let Ok(result) = traits::orphan_check_trait_ref::<!>( + let result = traits::orphan_check_trait_ref( &infcx, trait_ref, traits::InCrate::Local { mode }, lazily_normalize_ty, - ) else { - unreachable!() - }; + ) + .into_ok(); // (2) Try to map the remaining inference vars back to generic params. result.map_err(|err| match err { @@ -370,7 +368,7 @@ fn emit_orphan_check_error<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::TraitRef<'tcx>, impl_def_id: LocalDefId, - err: traits::OrphanCheckErr<'tcx, FxIndexSet<DefId>>, + err: traits::OrphanCheckErr<TyCtxt<'tcx>, FxIndexSet<DefId>>, ) -> ErrorGuaranteed { match err { traits::OrphanCheckErr::NonLocalInputType(tys) => { @@ -404,74 +402,56 @@ fn emit_orphan_check_error<'tcx>( match *ty.kind() { ty::Slice(_) => { if is_foreign { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsForeign { span }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span }); } else { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsName { span, name: "slices" }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsName { + span, + name: "slices", + }); } } ty::Array(..) => { if is_foreign { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsForeign { span }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span }); } else { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsName { span, name: "arrays" }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsName { + span, + name: "arrays", + }); } } ty::Tuple(..) => { if is_foreign { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsForeign { span }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span }); } else { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsName { span, name: "tuples" }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsName { + span, + name: "tuples", + }); } } ty::Alias(ty::Opaque, ..) => { - diag.subdiagnostic(tcx.dcx(), errors::OnlyCurrentTraitsOpaque { span }); + diag.subdiagnostic(errors::OnlyCurrentTraitsOpaque { span }); } ty::RawPtr(ptr_ty, mutbl) => { if !trait_ref.self_ty().has_param() { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsPointerSugg { - wrapper_span: impl_.self_ty.span, - struct_span: item.span.shrink_to_lo(), - mut_key: mutbl.prefix_str(), - ptr_ty, - }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsPointerSugg { + wrapper_span: impl_.self_ty.span, + struct_span: item.span.shrink_to_lo(), + mut_key: mutbl.prefix_str(), + ptr_ty, + }); } - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsPointer { span, pointer: ty }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsPointer { span, pointer: ty }); } ty::Adt(adt_def, _) => { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsAdt { - span, - name: tcx.def_path_str(adt_def.did()), - }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsAdt { + span, + name: tcx.def_path_str(adt_def.did()), + }); } _ => { - diag.subdiagnostic(tcx.dcx(), errors::OnlyCurrentTraitsTy { span, ty }); + diag.subdiagnostic(errors::OnlyCurrentTraitsTy { span, ty }); } } } @@ -501,7 +481,7 @@ fn emit_orphan_check_error<'tcx>( fn lint_uncovered_ty_params<'tcx>( tcx: TyCtxt<'tcx>, - UncoveredTyParams { uncovered, local_ty }: UncoveredTyParams<'tcx, FxIndexSet<DefId>>, + UncoveredTyParams { uncovered, local_ty }: UncoveredTyParams<TyCtxt<'tcx>, FxIndexSet<DefId>>, impl_def_id: LocalDefId, ) { let hir_id = tcx.local_def_id_to_hir_id(impl_def_id); @@ -558,7 +538,7 @@ struct TyVarReplacer<'cx, 'tcx> { } impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for TyVarReplacer<'cx, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index b760b86a7bf..e0aad299163 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -18,11 +18,13 @@ use rustc_ast::Recovered; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::unord::UnordMap; -use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey}; -use rustc_hir as hir; +use rustc_errors::{ + struct_span_code_err, Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, StashKey, E0228, +}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::intravisit::{self, walk_generics, Visitor}; +use rustc_hir::{self as hir}; use rustc_hir::{GenericParamKind, Node}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; @@ -33,10 +35,9 @@ use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, Upcast}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; -use rustc_target::abi::FieldIdx; use rustc_target::spec::abi; +use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName; use rustc_trait_selection::infer::InferCtxtExt; -use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName; use rustc_trait_selection::traits::ObligationCtxt; use std::cell::Cell; use std::iter; @@ -44,9 +45,9 @@ use std::ops::Bound; use crate::check::intrinsic::intrinsic_operation_unsafety; use crate::errors; -use crate::hir_ty_lowering::HirTyLowerer; -pub use type_of::test_opaque_hidden_types; +use crate::hir_ty_lowering::{HirTyLowerer, RegionInferReason}; +pub(crate) mod dump; mod generics_of; mod item_bounds; mod predicates_of; @@ -70,10 +71,10 @@ pub fn provide(providers: &mut Providers) { predicates_of: predicates_of::predicates_of, predicates_defined_on, explicit_predicates_of: predicates_of::explicit_predicates_of, - super_predicates_of: predicates_of::super_predicates_of, - implied_predicates_of: predicates_of::implied_predicates_of, - super_predicates_that_define_assoc_item: - predicates_of::super_predicates_that_define_assoc_item, + explicit_super_predicates_of: predicates_of::explicit_super_predicates_of, + explicit_implied_predicates_of: predicates_of::explicit_implied_predicates_of, + explicit_supertraits_containing_assoc_item: + predicates_of::explicit_supertraits_containing_assoc_item, trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds, type_param_predicates: predicates_of::type_param_predicates, trait_def, @@ -83,7 +84,6 @@ pub fn provide(providers: &mut Providers) { coroutine_kind, coroutine_for_closure, is_type_alias_impl_trait, - find_field, ..*providers }; } @@ -161,7 +161,7 @@ pub struct CollectItemTypesVisitor<'tcx> { /// and suggest adding type parameters in the appropriate place, taking into consideration any and /// all already existing generic type parameters to avoid suggesting a name that is already in use. pub(crate) fn placeholder_type_error<'tcx>( - tcx: TyCtxt<'tcx>, + cx: &dyn HirTyLowerer<'tcx>, generics: Option<&hir::Generics<'_>>, placeholder_types: Vec<Span>, suggest: bool, @@ -172,21 +172,21 @@ pub(crate) fn placeholder_type_error<'tcx>( return; } - placeholder_type_error_diag(tcx, generics, placeholder_types, vec![], suggest, hir_ty, kind) + placeholder_type_error_diag(cx, generics, placeholder_types, vec![], suggest, hir_ty, kind) .emit(); } -pub(crate) fn placeholder_type_error_diag<'tcx>( - tcx: TyCtxt<'tcx>, +pub(crate) fn placeholder_type_error_diag<'cx, 'tcx>( + cx: &'cx dyn HirTyLowerer<'tcx>, generics: Option<&hir::Generics<'_>>, placeholder_types: Vec<Span>, additional_spans: Vec<Span>, suggest: bool, hir_ty: Option<&hir::Ty<'_>>, kind: &'static str, -) -> Diag<'tcx> { +) -> Diag<'cx> { if placeholder_types.is_empty() { - return bad_placeholder(tcx, additional_spans, kind); + return bad_placeholder(cx, additional_spans, kind); } let params = generics.map(|g| g.params).unwrap_or_default(); @@ -210,7 +210,7 @@ pub(crate) fn placeholder_type_error_diag<'tcx>( } let mut err = - bad_placeholder(tcx, placeholder_types.into_iter().chain(additional_spans).collect(), kind); + bad_placeholder(cx, placeholder_types.into_iter().chain(additional_spans).collect(), kind); // Suggest, but only if it is not a function in const or static if suggest { @@ -224,7 +224,7 @@ pub(crate) fn placeholder_type_error_diag<'tcx>( // Check if parent is const or static is_const_or_static = matches!( - tcx.parent_hir_node(hir_ty.hir_id), + cx.tcx().parent_hir_node(hir_ty.hir_id), Node::Item(&hir::Item { kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..), .. @@ -267,7 +267,16 @@ fn reject_placeholder_type_signatures_in_item<'tcx>( let mut visitor = HirPlaceholderCollector::default(); visitor.visit_item(item); - placeholder_type_error(tcx, Some(generics), visitor.0, suggest, None, item.kind.descr()); + let icx = ItemCtxt::new(tcx, item.owner_id.def_id); + + placeholder_type_error( + icx.lowerer(), + Some(generics), + visitor.0, + suggest, + None, + item.kind.descr(), + ); } impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { @@ -329,15 +338,15 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { /////////////////////////////////////////////////////////////////////////// // Utility types and common code for the above passes. -fn bad_placeholder<'tcx>( - tcx: TyCtxt<'tcx>, +fn bad_placeholder<'cx, 'tcx>( + cx: &'cx dyn HirTyLowerer<'tcx>, mut spans: Vec<Span>, kind: &'static str, -) -> Diag<'tcx> { +) -> Diag<'cx> { let kind = if kind.ends_with('s') { format!("{kind}es") } else { format!("{kind}s") }; spans.sort(); - tcx.dcx().create_err(errors::PlaceholderNotAllowedItemSignatures { spans, kind }) + cx.dcx().create_err(errors::PlaceholderNotAllowedItemSignatures { spans, kind }) } impl<'tcx> ItemCtxt<'tcx> { @@ -370,32 +379,37 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { self.tcx } - fn item_def_id(&self) -> DefId { - self.item_def_id.to_def_id() + fn dcx(&self) -> DiagCtxtHandle<'_> { + self.tcx.dcx().taintable_handle(&self.tainted_by_errors) } - fn allow_infer(&self) -> bool { - false + fn item_def_id(&self) -> LocalDefId { + self.item_def_id } - fn re_infer(&self, _: Option<&ty::GenericParamDef>, _: Span) -> Option<ty::Region<'tcx>> { - None + fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> { + if let RegionInferReason::BorrowedObjectLifetimeDefault = reason { + let e = struct_span_code_err!( + self.dcx(), + span, + E0228, + "the lifetime bound for this object type cannot be deduced \ + from context; please supply an explicit bound" + ) + .emit(); + ty::Region::new_error(self.tcx(), e) + } else { + // This indicates an illegal lifetime in a non-assoc-trait position + ty::Region::new_error_with_message(self.tcx(), span, "unelided lifetime in signature") + } } fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { Ty::new_error_with_message(self.tcx(), span, "bad placeholder type") } - fn ct_infer(&self, ty: Ty<'tcx>, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> { - let ty = self.tcx.fold_regions(ty, |r, _| match *r { - rustc_type_ir::RegionKind::ReStatic => r, - - // This is never reached in practice. If it ever is reached, - // `ReErased` should be changed to `ReStatic`, and any other region - // left alone. - r => bug!("unexpected region: {r:?}"), - }); - ty::Const::new_error_with_message(self.tcx(), ty, span, "bad placeholder constant") + fn ct_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> { + ty::Const::new_error_with_message(self.tcx(), span, "bad placeholder constant") } fn probe_ty_param_bounds( @@ -421,7 +435,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { item_segment, trait_ref.args, ); - Ty::new_projection(self.tcx(), item_def_id, item_args) + Ty::new_projection_from_args(self.tcx(), item_def_id, item_args) } else { // There are no late-bound regions; we can just ignore the binder. let (mut mpart_sugg, mut inferred_sugg) = (None, None); @@ -453,7 +467,6 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { poly_trait_ref, |_| { ty::Region::new_early_param(self.tcx, ty::EarlyParamRegion { - def_id: item_def_id, index: 0, name: Symbol::intern(<_name), }) @@ -508,8 +521,87 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { None } - fn set_tainted_by_errors(&self, err: ErrorGuaranteed) { - self.tainted_by_errors.set(Some(err)); + fn lower_fn_sig( + &self, + decl: &hir::FnDecl<'tcx>, + generics: Option<&hir::Generics<'_>>, + hir_id: rustc_hir::HirId, + hir_ty: Option<&hir::Ty<'_>>, + ) -> (Vec<Ty<'tcx>>, Ty<'tcx>) { + let tcx = self.tcx(); + // We proactively collect all the inferred type params to emit a single error per fn def. + let mut visitor = HirPlaceholderCollector::default(); + let mut infer_replacements = vec![]; + + if let Some(generics) = generics { + walk_generics(&mut visitor, generics); + } + + let input_tys = decl + .inputs + .iter() + .enumerate() + .map(|(i, a)| { + if let hir::TyKind::Infer = a.kind { + if let Some(suggested_ty) = + self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i)) + { + infer_replacements.push((a.span, suggested_ty.to_string())); + return Ty::new_error_with_message(tcx, a.span, suggested_ty.to_string()); + } + } + + // Only visit the type looking for `_` if we didn't fix the type above + visitor.visit_ty(a); + self.lowerer().lower_arg_ty(a, None) + }) + .collect(); + + let output_ty = match decl.output { + hir::FnRetTy::Return(output) => { + if let hir::TyKind::Infer = output.kind + && let Some(suggested_ty) = + self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None) + { + infer_replacements.push((output.span, suggested_ty.to_string())); + Ty::new_error_with_message(tcx, output.span, suggested_ty.to_string()) + } else { + visitor.visit_ty(output); + self.lower_ty(output) + } + } + hir::FnRetTy::DefaultReturn(..) => tcx.types.unit, + }; + + if !(visitor.0.is_empty() && infer_replacements.is_empty()) { + // We check for the presence of + // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`. + + let mut diag = crate::collect::placeholder_type_error_diag( + self, + generics, + visitor.0, + infer_replacements.iter().map(|(s, _)| *s).collect(), + true, + hir_ty, + "function", + ); + + if !infer_replacements.is_empty() { + diag.multipart_suggestion( + format!( + "try replacing `_` with the type{} in the corresponding trait method signature", + rustc_errors::pluralize!(infer_replacements.len()), + ), + infer_replacements, + Applicability::MachineApplicable, + ); + } + + diag.emit(); + } + + (input_tys, output_ty) } } @@ -555,6 +647,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { let it = tcx.hir().item(item_id); debug!(item = %it.ident, id = %it.hir_id()); let def_id = item_id.owner_id.def_id; + let icx = ItemCtxt::new(tcx, def_id); match &it.kind { // These don't define types. @@ -579,7 +672,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { let mut visitor = HirPlaceholderCollector::default(); visitor.visit_foreign_item(item); placeholder_type_error( - tcx, + icx.lowerer(), None, visitor.0, false, @@ -607,14 +700,14 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { hir::ItemKind::Trait(..) => { tcx.ensure().generics_of(def_id); tcx.ensure().trait_def(def_id); - tcx.at(it.span).super_predicates_of(def_id); + tcx.at(it.span).explicit_super_predicates_of(def_id); tcx.ensure().predicates_of(def_id); tcx.ensure().associated_items(def_id); } hir::ItemKind::TraitAlias(..) => { tcx.ensure().generics_of(def_id); - tcx.at(it.span).implied_predicates_of(def_id); - tcx.at(it.span).super_predicates_of(def_id); + tcx.at(it.span).explicit_implied_predicates_of(def_id); + tcx.at(it.span).explicit_super_predicates_of(def_id); tcx.ensure().predicates_of(def_id); } hir::ItemKind::Struct(struct_def, _) | hir::ItemKind::Union(struct_def, _) => { @@ -658,7 +751,14 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { if !ty.is_suggestable_infer_ty() { let mut visitor = HirPlaceholderCollector::default(); visitor.visit_item(it); - placeholder_type_error(tcx, None, visitor.0, false, None, it.kind.descr()); + placeholder_type_error( + icx.lowerer(), + None, + visitor.0, + false, + None, + it.kind.descr(), + ); } } @@ -676,6 +776,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { let trait_item = tcx.hir().trait_item(trait_item_id); let def_id = trait_item_id.owner_id; tcx.ensure().generics_of(def_id); + let icx = ItemCtxt::new(tcx, def_id.def_id); match trait_item.kind { hir::TraitItemKind::Fn(..) => { @@ -692,7 +793,14 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { // Account for `const C: _;`. let mut visitor = HirPlaceholderCollector::default(); visitor.visit_trait_item(trait_item); - placeholder_type_error(tcx, None, visitor.0, false, None, "associated constant"); + placeholder_type_error( + icx.lowerer(), + None, + visitor.0, + false, + None, + "associated constant", + ); } } @@ -703,7 +811,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { // Account for `type T = _;`. let mut visitor = HirPlaceholderCollector::default(); visitor.visit_trait_item(trait_item); - placeholder_type_error(tcx, None, visitor.0, false, None, "associated type"); + placeholder_type_error(icx.lowerer(), None, visitor.0, false, None, "associated type"); } hir::TraitItemKind::Type(_, None) => { @@ -714,7 +822,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { let mut visitor = HirPlaceholderCollector::default(); visitor.visit_trait_item(trait_item); - placeholder_type_error(tcx, None, visitor.0, false, None, "associated type"); + placeholder_type_error(icx.lowerer(), None, visitor.0, false, None, "associated type"); } }; @@ -727,6 +835,7 @@ fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) { tcx.ensure().type_of(def_id); tcx.ensure().predicates_of(def_id); let impl_item = tcx.hir().impl_item(impl_item_id); + let icx = ItemCtxt::new(tcx, def_id.def_id); match impl_item.kind { hir::ImplItemKind::Fn(..) => { tcx.ensure().codegen_fn_attrs(def_id); @@ -737,14 +846,21 @@ fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) { let mut visitor = HirPlaceholderCollector::default(); visitor.visit_impl_item(impl_item); - placeholder_type_error(tcx, None, visitor.0, false, None, "associated type"); + placeholder_type_error(icx.lowerer(), None, visitor.0, false, None, "associated type"); } hir::ImplItemKind::Const(ty, _) => { // Account for `const T: _ = ..;` if !ty.is_suggestable_infer_ty() { let mut visitor = HirPlaceholderCollector::default(); visitor.visit_impl_item(impl_item); - placeholder_type_error(tcx, None, visitor.0, false, None, "associated constant"); + placeholder_type_error( + icx.lowerer(), + None, + visitor.0, + false, + None, + "associated constant", + ); } } } @@ -796,23 +912,6 @@ fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) { } } -fn find_field(tcx: TyCtxt<'_>, (def_id, ident): (DefId, Ident)) -> Option<FieldIdx> { - let adt = tcx.adt_def(def_id); - if adt.is_enum() { - return None; - } - - adt.non_enum_variant().fields.iter_enumerated().find_map(|(idx, field)| { - if field.is_unnamed() { - let field_ty = tcx.type_of(field.did).instantiate_identity(); - let adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field"); - tcx.find_field((adt_def.did(), ident)).map(|_| idx) - } else { - (field.ident(tcx).normalize_to_macros_2_0() == ident).then_some(idx) - } - }) -} - #[derive(Clone, Copy)] struct NestedSpan { span: Span, @@ -1007,7 +1106,10 @@ fn lower_variant( vis: tcx.visibility(f.def_id), }) .collect(); - let recovered = matches!(def, hir::VariantData::Struct { recovered: Recovered::Yes(_), .. }); + let recovered = match def { + hir::VariantData::Struct { recovered: Recovered::Yes(guar), .. } => Some(*guar), + _ => None, + }; ty::VariantDef::new( ident.name, variant_did.map(LocalDefId::to_def_id), @@ -1110,6 +1212,11 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"), }; + let constness = if tcx.has_attr(def_id, sym::const_trait) { + hir::Constness::Const + } else { + hir::Constness::NotConst + }; let paren_sugar = tcx.has_attr(def_id, sym::rustc_paren_sugar); if paren_sugar && !tcx.features().unboxed_closures { tcx.dcx().emit_err(errors::ParenSugarAttribute { span: item.span }); @@ -1117,6 +1224,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { let is_marker = tcx.has_attr(def_id, sym::marker); let rustc_coinductive = tcx.has_attr(def_id, sym::rustc_coinductive); + let is_fundamental = tcx.has_attr(def_id, sym::fundamental); // FIXME: We could probably do way better attribute validation here. let mut skip_array_during_method_dispatch = false; @@ -1264,10 +1372,12 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { ty::TraitDef { def_id: def_id.to_def_id(), safety, + constness, paren_sugar, has_auto_impl: is_auto, is_marker, is_coinductive: rustc_coinductive || is_auto, + is_fundamental, skip_array_during_method_dispatch, skip_boxed_slice_during_method_dispatch, specialization_kind, @@ -1278,7 +1388,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { } #[instrument(level = "debug", skip(tcx))] -fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<'_>> { +fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFnSig<'_>> { use rustc_hir::Node::*; use rustc_hir::*; @@ -1293,7 +1403,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig< .. }) | Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), .. }) => { - infer_return_ty_for_fn_sig(tcx, sig, generics, def_id, &icx) + infer_return_ty_for_fn_sig(sig, generics, def_id, &icx) } ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => { @@ -1310,7 +1420,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig< None, ) } else { - infer_return_ty_for_fn_sig(tcx, sig, generics, def_id, &icx) + infer_return_ty_for_fn_sig(sig, generics, def_id, &icx) } } @@ -1322,9 +1432,11 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig< icx.lowerer().lower_fn_ty(hir_id, header.safety, header.abi, decl, Some(generics), None) } - ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => { + ForeignItem(&hir::ForeignItem { + kind: ForeignItemKind::Fn(fn_decl, _, _, safety), .. + }) => { let abi = tcx.hir().get_foreign_abi(hir_id); - compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi) + compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi, safety) } Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor().is_some() => { @@ -1361,27 +1473,44 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig< } fn infer_return_ty_for_fn_sig<'tcx>( - tcx: TyCtxt<'tcx>, sig: &hir::FnSig<'tcx>, generics: &hir::Generics<'_>, def_id: LocalDefId, icx: &ItemCtxt<'tcx>, ) -> 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 paramters, + // 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 = tcx.fold_regions(fn_sig, |r, _| match *r { - ty::ReErased => tcx.lifetimes.re_static, + 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 mut visitor = HirPlaceholderCollector::default(); visitor.visit_ty(ty); - let mut diag = bad_placeholder(tcx, visitor.0, "return type"); + 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 @@ -1479,7 +1608,7 @@ pub fn suggest_impl_trait<'tcx>( ), ( infcx.tcx.lang_items().future_trait(), - infcx.tcx.get_diagnostic_item(sym::FutureOutput), + infcx.tcx.lang_items().future_output(), format_as_assoc, ), ( @@ -1521,7 +1650,7 @@ pub fn suggest_impl_trait<'tcx>( let item_ty = ocx.normalize( &ObligationCause::dummy(), param_env, - Ty::new_projection(infcx.tcx, assoc_item_def_id, args), + Ty::new_projection_from_args(infcx.tcx, assoc_item_def_id, args), ); // FIXME(compiler-errors): We may benefit from resolving regions here. if ocx.select_where_possible().is_empty() @@ -1552,44 +1681,19 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai let icx = ItemCtxt::new(tcx, def_id); let item = tcx.hir().expect_item(def_id); let impl_ = item.expect_impl(); - impl_ - .of_trait - .as_ref() - .map(|hir_trait_ref| { - let self_ty = tcx.type_of(def_id).instantiate_identity(); + impl_.of_trait.as_ref().map(|ast_trait_ref| { + let selfty = tcx.type_of(def_id).instantiate_identity(); - let trait_ref = if let Some(ErrorGuaranteed { .. }) = check_impl_constness( - tcx, - tcx.is_const_trait_impl_raw(def_id.to_def_id()), - hir_trait_ref, - ) { - // we have a const impl, but for a trait without `#[const_trait]`, so - // without the host param. If we continue with the HIR trait ref, we get - // ICEs for generic arg count mismatch. We do a little HIR editing to - // make HIR ty lowering happy. - let mut path_segments = hir_trait_ref.path.segments.to_vec(); - let last_segment = path_segments.len() - 1; - let mut args = *path_segments[last_segment].args(); - let last_arg = args.args.len() - 1; - assert!(matches!(args.args[last_arg], hir::GenericArg::Const(anon_const) if anon_const.is_desugared_from_effects)); - args.args = &args.args[..args.args.len() - 1]; - path_segments[last_segment].args = Some(tcx.hir_arena.alloc(args)); - let path = hir::Path { - span: hir_trait_ref.path.span, - res: hir_trait_ref.path.res, - segments: tcx.hir_arena.alloc_slice(&path_segments), - }; - let trait_ref = tcx.hir_arena.alloc(hir::TraitRef { path: tcx.hir_arena.alloc(path), hir_ref_id: hir_trait_ref.hir_ref_id }); - icx.lowerer().lower_impl_trait_ref(trait_ref, self_ty) - } else { - icx.lowerer().lower_impl_trait_ref(hir_trait_ref, self_ty) - }; - ty::ImplTraitHeader { - trait_ref: ty::EarlyBinder::bind(trait_ref), - safety: impl_.safety, - polarity: polarity_of_impl(tcx, def_id, impl_, item.span) - } - }) + check_impl_constness(tcx, tcx.is_const_trait_impl_raw(def_id.to_def_id()), ast_trait_ref); + + let trait_ref = icx.lowerer().lower_impl_trait_ref(ast_trait_ref, selfty); + + ty::ImplTraitHeader { + trait_ref: ty::EarlyBinder::bind(trait_ref), + safety: impl_.safety, + polarity: polarity_of_impl(tcx, def_id, impl_, item.span), + } + }) } fn check_impl_constness( @@ -1602,7 +1706,7 @@ fn check_impl_constness( } let trait_def_id = hir_trait_ref.trait_def_id()?; - if tcx.has_attr(trait_def_id, sym::const_trait) { + if tcx.is_const_trait(trait_def_id) { return None; } @@ -1696,11 +1800,12 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( def_id: LocalDefId, decl: &'tcx hir::FnDecl<'tcx>, abi: abi::Abi, + safety: hir::Safety, ) -> ty::PolyFnSig<'tcx> { let safety = if abi == abi::Abi::RustIntrinsic { intrinsic_operation_unsafety(tcx, def_id) } else { - hir::Safety::Unsafe + safety }; let hir_id = tcx.local_def_id_to_hir_id(def_id); let fty = diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs new file mode 100644 index 00000000000..c73d3a5390d --- /dev/null +++ b/compiler/rustc_hir_analysis/src/collect/dump.rs @@ -0,0 +1,91 @@ +use rustc_hir::def::DefKind; +use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; +use rustc_hir::intravisit; +use rustc_middle::hir::nested_filter::OnlyBodies; +use rustc_middle::ty::TyCtxt; +use rustc_span::sym; + +pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) { + if !tcx.has_attr(CRATE_DEF_ID, sym::rustc_hidden_type_of_opaques) { + return; + } + + for id in tcx.hir().items() { + let DefKind::OpaqueTy = tcx.def_kind(id.owner_id) else { continue }; + + let ty = tcx.type_of(id.owner_id).instantiate_identity(); + + tcx.dcx().emit_err(crate::errors::TypeOf { span: tcx.def_span(id.owner_id), ty }); + } +} + +pub(crate) fn predicates_and_item_bounds(tcx: TyCtxt<'_>) { + for id in tcx.hir_crate_items(()).owners() { + if tcx.has_attr(id, sym::rustc_dump_predicates) { + let preds = tcx.predicates_of(id).instantiate_identity(tcx).predicates; + let span = tcx.def_span(id); + + let mut diag = tcx.dcx().struct_span_err(span, sym::rustc_dump_predicates.as_str()); + for pred in preds { + diag.note(format!("{pred:?}")); + } + diag.emit(); + } + if tcx.has_attr(id, sym::rustc_dump_item_bounds) { + let bounds = tcx.item_bounds(id).instantiate_identity(); + let span = tcx.def_span(id); + + let mut diag = tcx.dcx().struct_span_err(span, sym::rustc_dump_item_bounds.as_str()); + for bound in bounds { + diag.note(format!("{bound:?}")); + } + diag.emit(); + } + } +} + +pub(crate) fn def_parents(tcx: TyCtxt<'_>) { + for did in tcx.hir().body_owners() { + if tcx.has_attr(did, sym::rustc_dump_def_parents) { + struct AnonConstFinder<'tcx> { + tcx: TyCtxt<'tcx>, + anon_consts: Vec<LocalDefId>, + } + + impl<'tcx> intravisit::Visitor<'tcx> for AnonConstFinder<'tcx> { + type NestedFilter = OnlyBodies; + + fn nested_visit_map(&mut self) -> Self::Map { + self.tcx.hir() + } + + fn visit_anon_const(&mut self, c: &'tcx rustc_hir::AnonConst) { + self.anon_consts.push(c.def_id); + intravisit::walk_anon_const(self, c) + } + } + + // Look for any anon consts inside of this body owner as there is no way to apply + // the `rustc_dump_def_parents` attribute to the anon const so it would not be possible + // to see what its def parent is. + let mut anon_ct_finder = AnonConstFinder { tcx, anon_consts: vec![] }; + intravisit::walk_expr(&mut anon_ct_finder, tcx.hir().body_owned_by(did).value); + + for did in [did].into_iter().chain(anon_ct_finder.anon_consts) { + let span = tcx.def_span(did); + + let mut diag = tcx.dcx().struct_span_err( + span, + format!("{}: {did:?}", sym::rustc_dump_def_parents.as_str()), + ); + + let mut current_did = did.to_def_id(); + while let Some(parent_did) = tcx.opt_parent(current_did) { + current_did = parent_did; + diag.span_note(tcx.def_span(parent_did), format!("{parent_did:?}")); + } + diag.emit(); + } + } + } +} diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 6b41f79cf1e..22d465c8e62 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -1,3 +1,5 @@ +use std::ops::ControlFlow; + use crate::middle::resolve_bound_vars as rbv; use hir::{ intravisit::{self, Visitor}, @@ -11,6 +13,7 @@ use rustc_session::lint; use rustc_span::symbol::{kw, Symbol}; use rustc_span::Span; +#[instrument(level = "debug", skip(tcx))] pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { use rustc_hir::*; @@ -66,19 +69,29 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // FIXME(#43408) always enable this once `lazy_normalization` is // stable enough and does not need a feature gate anymore. Node::AnonConst(_) => { - let parent_def_id = tcx.hir().get_parent_item(hir_id); + let parent_did = tcx.parent(def_id.to_def_id()); + + // We don't do this unconditionally because the `DefId` parent of an anon const + // might be an implicitly created closure during `async fn` desugaring. This would + // have the wrong generics. + // + // i.e. `async fn foo<'a>() { let a = [(); { 1 + 2 }]; bar().await() }` + // would implicitly have a closure in its body that would be the parent of + // the `{ 1 + 2 }` anon const. This closure's generics is simply a witness + // instead of `['a]`. + let parent_did = if let DefKind::AnonConst = tcx.def_kind(parent_did) { + parent_did + } else { + tcx.hir().get_parent_item(hir_id).to_def_id() + }; + debug!(?parent_did); let mut in_param_ty = false; for (_parent, node) in tcx.hir().parent_iter(hir_id) { if let Some(generics) = node.generics() { - let mut visitor = AnonConstInParamTyDetector { - in_param_ty: false, - found_anon_const_in_param_ty: false, - ct: hir_id, - }; + let mut visitor = AnonConstInParamTyDetector { in_param_ty: false, ct: hir_id }; - visitor.visit_generics(generics); - in_param_ty = visitor.found_anon_const_in_param_ty; + in_param_ty = visitor.visit_generics(generics).is_break(); break; } } @@ -121,7 +134,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // // This has some implications for how we get the predicates available to the anon const // see `explicit_predicates_of` for more information on this - let generics = tcx.generics_of(parent_def_id.to_def_id()); + let generics = tcx.generics_of(parent_did); let param_def_idx = generics.param_def_id_to_index[¶m_id.to_def_id()]; // In the above example this would be .params[..N#0] let own_params = generics.params_to(param_def_idx as usize, tcx).to_owned(); @@ -147,7 +160,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // // Note that we do not supply the parent generics when using // `min_const_generics`. - Some(parent_def_id.to_def_id()) + Some(parent_did) } } else { let parent_node = tcx.parent_hir_node(hir_id); @@ -159,7 +172,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. }) if constant.hir_id() == hir_id => { - Some(parent_def_id.to_def_id()) + Some(parent_did) } // Exclude `GlobalAsm` here which cannot have generics. Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) @@ -171,7 +184,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { _ => false, }) => { - Some(parent_def_id.to_def_id()) + Some(parent_did) } _ => None, } @@ -317,8 +330,9 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { lint::builtin::INVALID_TYPE_PARAM_DEFAULT, param.hir_id, param.span, - TYPE_DEFAULT_NOT_ALLOWED, - |_| {}, + |lint| { + lint.primary_message(TYPE_DEFAULT_NOT_ALLOWED); + }, ); } Defaults::Deny => { @@ -337,7 +351,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { kind, }) } - GenericParamKind::Const { ty: _, default, is_host_effect } => { + GenericParamKind::Const { ty: _, default, is_host_effect, synthetic } => { if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() // `host` effect params are allowed to have defaults. @@ -371,6 +385,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { kind: ty::GenericParamDefKind::Const { has_default: default.is_some(), is_host_effect, + synthetic, }, }) } @@ -442,50 +457,45 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S struct LateBoundRegionsDetector<'tcx> { tcx: TyCtxt<'tcx>, outer_index: ty::DebruijnIndex, - has_late_bound_regions: Option<Span>, } impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> { - fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { - if self.has_late_bound_regions.is_some() { - return; - } + type Result = ControlFlow<Span>; + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) -> ControlFlow<Span> { match ty.kind { hir::TyKind::BareFn(..) => { self.outer_index.shift_in(1); - intravisit::walk_ty(self, ty); + let res = intravisit::walk_ty(self, ty); self.outer_index.shift_out(1); + res } _ => intravisit::walk_ty(self, ty), } } - fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) { - if self.has_late_bound_regions.is_some() { - return; - } + fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) -> ControlFlow<Span> { self.outer_index.shift_in(1); - intravisit::walk_poly_trait_ref(self, tr); + let res = intravisit::walk_poly_trait_ref(self, tr); self.outer_index.shift_out(1); + res } - fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) { - if self.has_late_bound_regions.is_some() { - return; - } - + fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) -> ControlFlow<Span> { match self.tcx.named_bound_var(lt.hir_id) { - Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => {} + Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => { + ControlFlow::Continue(()) + } Some(rbv::ResolvedArg::LateBound(debruijn, _, _)) - if debruijn < self.outer_index => {} + if debruijn < self.outer_index => + { + ControlFlow::Continue(()) + } Some( rbv::ResolvedArg::LateBound(..) | rbv::ResolvedArg::Free(..) | rbv::ResolvedArg::Error(_), ) - | None => { - self.has_late_bound_regions = Some(lt.ident.span); - } + | None => ControlFlow::Break(lt.ident.span), } } } @@ -495,11 +505,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S generics: &'tcx hir::Generics<'tcx>, decl: &'tcx hir::FnDecl<'tcx>, ) -> Option<Span> { - let mut visitor = LateBoundRegionsDetector { - tcx, - outer_index: ty::INNERMOST, - has_late_bound_regions: None, - }; + let mut visitor = LateBoundRegionsDetector { tcx, outer_index: ty::INNERMOST }; for param in generics.params { if let GenericParamKind::Lifetime { .. } = param.kind { if tcx.is_late_bound(param.hir_id) { @@ -507,8 +513,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S } } } - visitor.visit_fn_decl(decl); - visitor.has_late_bound_regions + visitor.visit_fn_decl(decl).break_value() } let decl = node.fn_decl()?; @@ -518,25 +523,29 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S struct AnonConstInParamTyDetector { in_param_ty: bool, - found_anon_const_in_param_ty: bool, ct: HirId, } impl<'v> Visitor<'v> for AnonConstInParamTyDetector { - fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) { - if let GenericParamKind::Const { ty, default: _, is_host_effect: _ } = p.kind { + type Result = ControlFlow<()>; + + fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) -> Self::Result { + if let GenericParamKind::Const { ty, default: _, is_host_effect: _, synthetic: _ } = p.kind + { let prev = self.in_param_ty; self.in_param_ty = true; - self.visit_ty(ty); + let res = self.visit_ty(ty); self.in_param_ty = prev; + res + } else { + ControlFlow::Continue(()) } } - fn visit_anon_const(&mut self, c: &'v hir::AnonConst) { + fn visit_anon_const(&mut self, c: &'v hir::AnonConst) -> Self::Result { if self.in_param_ty && self.ct == c.hir_id { - self.found_anon_const_in_param_ty = true; - } else { - intravisit::walk_anon_const(self, c) + return ControlFlow::Break(()); } + intravisit::walk_anon_const(self, c) } } diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index dd1d209389d..c03e074c80b 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -8,6 +8,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFold use rustc_middle::{bug, span_bug}; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; +use rustc_type_ir::Upcast; /// For associated types we include both bounds written on the type /// (`type X: Trait`) and predicates from the trait: `where Self::X: Trait`. @@ -23,7 +24,7 @@ fn associated_type_bounds<'tcx>( span: Span, filter: PredicateFilter, ) -> &'tcx [(ty::Clause<'tcx>, Span)] { - let item_ty = Ty::new_projection( + let item_ty = Ty::new_projection_from_args( tcx, assoc_item_def_id.to_def_id(), GenericArgs::identity_for_item(tcx, assoc_item_def_id), @@ -46,7 +47,7 @@ fn associated_type_bounds<'tcx>( } }); - let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent)); + let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(bounds_from_parent)); debug!( "associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id.to_def_id()), @@ -59,7 +60,7 @@ fn associated_type_bounds<'tcx>( /// impl trait it isn't possible to write a suitable predicate on the /// containing function and for type-alias impl trait we don't have a backwards /// compatibility issue. -#[instrument(level = "trace", skip(tcx), ret)] +#[instrument(level = "trace", skip(tcx, item_ty))] fn opaque_type_bounds<'tcx>( tcx: TyCtxt<'tcx>, opaque_def_id: LocalDefId, @@ -75,21 +76,21 @@ fn opaque_type_bounds<'tcx>( icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span); debug!(?bounds); - tcx.arena.alloc_from_iter(bounds.clauses()) + tcx.arena.alloc_from_iter(bounds.clauses(tcx)) }) } pub(super) fn explicit_item_bounds( tcx: TyCtxt<'_>, def_id: LocalDefId, -) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> { +) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, Span)]> { explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::All) } pub(super) fn explicit_item_super_predicates( tcx: TyCtxt<'_>, def_id: LocalDefId, -) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> { +) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, Span)]> { explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::SelfOnly) } @@ -97,7 +98,7 @@ pub(super) fn explicit_item_bounds_with_filter( tcx: TyCtxt<'_>, def_id: LocalDefId, filter: PredicateFilter, -) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> { +) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, Span)]> { 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. @@ -108,7 +109,7 @@ pub(super) fn explicit_item_bounds_with_filter( tcx, opaque_def_id.expect_local(), opaque_ty.bounds, - Ty::new_projection( + Ty::new_projection_from_args( tcx, def_id.to_def_id(), ty::GenericArgs::identity_for_item(tcx, def_id), @@ -124,6 +125,32 @@ pub(super) fn explicit_item_bounds_with_filter( None => {} } + if tcx.is_effects_desugared_assoc_ty(def_id.to_def_id()) { + let mut predicates = Vec::new(); + + let parent = tcx.local_parent(def_id); + + let preds = tcx.explicit_predicates_of(parent); + + if let ty::AssocItemContainer::TraitContainer = tcx.associated_item(def_id).container { + // for traits, emit `type Effects: TyCompat<<(T1::Effects, ..) as Min>::Output>` + let tup = Ty::new(tcx, ty::Tuple(preds.effects_min_tys)); + // FIXME(effects) span + let span = tcx.def_span(def_id); + let assoc = tcx.require_lang_item(hir::LangItem::EffectsIntersectionOutput, Some(span)); + let proj = Ty::new_projection(tcx, assoc, [tup]); + let self_proj = Ty::new_projection( + tcx, + def_id.to_def_id(), + ty::GenericArgs::identity_for_item(tcx, def_id), + ); + let trait_ = tcx.require_lang_item(hir::LangItem::EffectsTyCompat, Some(span)); + let trait_ref = ty::TraitRef::new(tcx, trait_, [self_proj, proj]); + predicates.push((ty::Binder::dummy(trait_ref).upcast(tcx), span)); + } + return ty::EarlyBinder::bind(tcx.arena.alloc_from_iter(predicates)); + } + let bounds = match tcx.hir_node_by_def_id(def_id) { hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(bounds, _), @@ -166,7 +193,7 @@ pub(super) fn explicit_item_bounds_with_filter( ty::EarlyBinder::bind(bounds) } -pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<ty::Clauses<'_>> { +pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<'_, ty::Clauses<'_>> { tcx.explicit_item_bounds(def_id).map_bound(|bounds| { tcx.mk_clauses_from_iter(util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound))) }) @@ -175,7 +202,7 @@ pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<ty: pub(super) fn item_super_predicates( tcx: TyCtxt<'_>, def_id: DefId, -) -> ty::EarlyBinder<ty::Clauses<'_>> { +) -> ty::EarlyBinder<'_, ty::Clauses<'_>> { tcx.explicit_item_super_predicates(def_id).map_bound(|bounds| { tcx.mk_clauses_from_iter( util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)).filter_only_self(), @@ -186,7 +213,7 @@ pub(super) fn item_super_predicates( pub(super) fn item_non_self_assumptions( tcx: TyCtxt<'_>, def_id: DefId, -) -> ty::EarlyBinder<ty::Clauses<'_>> { +) -> ty::EarlyBinder<'_, ty::Clauses<'_>> { let all_bounds: FxIndexSet<_> = tcx.item_bounds(def_id).skip_binder().iter().collect(); let own_bounds: FxIndexSet<_> = tcx.item_super_predicates(def_id).skip_binder().iter().collect(); @@ -203,7 +230,7 @@ struct AssocTyToOpaque<'tcx> { } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTyToOpaque<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 606f1653767..b89d034fc2e 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -1,7 +1,7 @@ use crate::bounds::Bounds; use crate::collect::ItemCtxt; use crate::constrained_generic_params as cgp; -use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter}; +use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter, RegionInferReason}; use hir::{HirId, Node}; use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; @@ -57,6 +57,7 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic #[instrument(level = "trace", skip(tcx), ret)] fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::GenericPredicates<'_> { use rustc_hir::*; + use rustc_middle::ty::Ty; match tcx.opt_rpitit_info(def_id.to_def_id()) { Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) => { @@ -84,6 +85,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen return ty::GenericPredicates { parent: Some(tcx.parent(def_id.to_def_id())), predicates: tcx.arena.alloc_from_iter(predicates), + effects_min_tys: ty::List::empty(), }; } @@ -105,6 +107,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen return ty::GenericPredicates { parent: Some(impl_def_id), predicates: tcx.arena.alloc_from_iter(impl_predicates), + effects_min_tys: ty::List::empty(), }; } @@ -117,7 +120,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen let mut is_trait = None; let mut is_default_impl_trait = None; - // FIXME: Should ItemCtxt take a LocalDefId? let icx = ItemCtxt::new(tcx, def_id); const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty(); @@ -125,6 +127,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // We use an `IndexSet` to preserve order of insertion. // Preserving the order of insertion is important here so as not to break UI tests. let mut predicates: FxIndexSet<(ty::Clause<'_>, Span)> = FxIndexSet::default(); + let mut effects_min_tys = Vec::new(); let hir_generics = node.generics().unwrap_or(NO_GENERICS); if let Node::Item(item) = node { @@ -151,11 +154,13 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // on a trait we must also consider the bounds that follow the trait's name, // like `trait Foo: A + B + C`. if let Some(self_bounds) = is_trait { - predicates.extend( - icx.lowerer() - .lower_mono_bounds(tcx.types.self_param, self_bounds, PredicateFilter::All) - .clauses(), + let bounds = icx.lowerer().lower_mono_bounds( + tcx.types.self_param, + self_bounds, + PredicateFilter::All, ); + predicates.extend(bounds.clauses(tcx)); + effects_min_tys.extend(bounds.effects_min_tys()); } // In default impls, we can assume that the self type implements @@ -170,12 +175,11 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen predicates.insert((trait_ref.upcast(tcx), tcx.def_span(def_id))); } - // 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. + // Add implicit predicates that should be treated as if the user has written them, + // including the implicit `T: Sized` for all generic parameters, and `ConstArgHasType` + // for const params. for param in hir_generics.params { match param.kind { - // We already dealt with early bound lifetimes above. GenericParamKind::Lifetime { .. } => (), GenericParamKind::Type { .. } => { let param_ty = icx.lowerer().lower_ty_param(param.hir_id); @@ -189,7 +193,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen param.span, ); trace!(?bounds); - predicates.extend(bounds.clauses()); + predicates.extend(bounds.clauses(tcx)); trace!(?predicates); } hir::GenericParamKind::Const { .. } => { @@ -197,7 +201,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen .type_of(param.def_id.to_def_id()) .no_bound_vars() .expect("const parameters cannot be generic"); - let ct = icx.lowerer().lower_const_param(param.hir_id, ct_ty); + let ct = icx.lowerer().lower_const_param(param.hir_id); predicates .insert((ty::ClauseKind::ConstArgHasType(ct, ct_ty).upcast(tcx), param.span)); } @@ -205,7 +209,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } trace!(?predicates); - // Add in the bounds that appear in the where-clause. + // Add inline `<T: Foo>` bounds and bounds in the where clause. for predicate in hir_generics.predicates { match predicate { hir::WherePredicate::BoundPredicate(bound_pred) => { @@ -240,16 +244,20 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen bound_vars, OnlySelfBounds(false), ); - predicates.extend(bounds.clauses()); + predicates.extend(bounds.clauses(tcx)); + effects_min_tys.extend(bounds.effects_min_tys()); } hir::WherePredicate::RegionPredicate(region_pred) => { - let r1 = icx.lowerer().lower_lifetime(region_pred.lifetime, None); + let r1 = icx + .lowerer() + .lower_lifetime(region_pred.lifetime, RegionInferReason::RegionPredicate); predicates.extend(region_pred.bounds.iter().map(|bound| { let (r2, span) = match bound { - hir::GenericBound::Outlives(lt) => { - (icx.lowerer().lower_lifetime(lt, None), lt.ident.span) - } + hir::GenericBound::Outlives(lt) => ( + icx.lowerer().lower_lifetime(lt, RegionInferReason::RegionPredicate), + lt.ident.span, + ), bound => { span_bug!( bound.span(), @@ -296,7 +304,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // and the duplicated parameter, to ensure that they do not get out of sync. if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node { let opaque_ty_node = tcx.parent_hir_node(hir_id); - let Node::Ty(&Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node else { + let Node::Ty(&hir::Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node + else { bug!("unexpected {opaque_ty_node:?}") }; debug!(?lifetimes); @@ -305,9 +314,30 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen debug!(?predicates); } + // add `Self::Effects: Compat<HOST>` to ensure non-const impls don't get called + // in const contexts. + if let Node::TraitItem(&TraitItem { kind: TraitItemKind::Fn(..), .. }) = node + && let Some(host_effect_index) = generics.host_effect_index + { + let parent = generics.parent.unwrap(); + let Some(assoc_def_id) = tcx.associated_type_for_effects(parent) else { + bug!("associated_type_for_effects returned None when there is host effect in generics"); + }; + let effects = + Ty::new_projection(tcx, assoc_def_id, ty::GenericArgs::identity_for_item(tcx, parent)); + let param = generics.param_at(host_effect_index, tcx); + let span = tcx.def_span(param.def_id); + let host = ty::Const::new_param(tcx, ty::ParamConst::for_def(param)); + let compat = tcx.require_lang_item(LangItem::EffectsCompat, Some(span)); + let trait_ref = + ty::TraitRef::new(tcx, compat, [ty::GenericArg::from(effects), host.into()]); + predicates.push((ty::Binder::dummy(trait_ref).upcast(tcx), span)); + } + ty::GenericPredicates { parent: generics.parent, predicates: tcx.arena.alloc_from_iter(predicates), + effects_min_tys: tcx.mk_type_list(&effects_min_tys), } } @@ -323,7 +353,7 @@ fn compute_bidirectional_outlives_predicates<'tcx>( if let ty::ReEarlyParam(..) = *orig_lifetime { let dup_lifetime = ty::Region::new_early_param( tcx, - ty::EarlyParamRegion { def_id: param.def_id, index: param.index, name: param.name }, + ty::EarlyParamRegion { index: param.index, name: param.name }, ); let span = tcx.def_span(param.def_id); predicates.push(( @@ -458,6 +488,7 @@ pub(super) fn explicit_predicates_of<'tcx>( ty::GenericPredicates { parent: predicates_and_bounds.parent, predicates: tcx.arena.alloc_slice(&predicates), + effects_min_tys: predicates_and_bounds.effects_min_tys, } } } else { @@ -509,6 +540,7 @@ pub(super) fn explicit_predicates_of<'tcx>( return GenericPredicates { parent: parent_preds.parent, predicates: { tcx.arena.alloc_from_iter(filtered_predicates) }, + effects_min_tys: parent_preds.effects_min_tys, }; } gather_explicit_predicates_of(tcx, def_id) @@ -518,21 +550,21 @@ pub(super) fn explicit_predicates_of<'tcx>( /// Ensures that the super-predicates of the trait with a `DefId` /// of `trait_def_id` are lowered and stored. This also ensures that /// the transitive super-predicates are lowered. -pub(super) fn super_predicates_of( +pub(super) fn explicit_super_predicates_of( tcx: TyCtxt<'_>, trait_def_id: LocalDefId, ) -> ty::GenericPredicates<'_> { implied_predicates_with_filter(tcx, trait_def_id.to_def_id(), PredicateFilter::SelfOnly) } -pub(super) fn super_predicates_that_define_assoc_item( +pub(super) fn explicit_supertraits_containing_assoc_item( tcx: TyCtxt<'_>, (trait_def_id, assoc_name): (DefId, Ident), ) -> ty::GenericPredicates<'_> { implied_predicates_with_filter(tcx, trait_def_id, PredicateFilter::SelfThatDefines(assoc_name)) } -pub(super) fn implied_predicates_of( +pub(super) fn explicit_implied_predicates_of( tcx: TyCtxt<'_>, trait_def_id: LocalDefId, ) -> ty::GenericPredicates<'_> { @@ -559,7 +591,7 @@ pub(super) fn implied_predicates_with_filter( // if `assoc_name` is None, then the query should've been redirected to an // external provider assert!(matches!(filter, PredicateFilter::SelfThatDefines(_))); - return tcx.super_predicates_of(trait_def_id); + return tcx.explicit_super_predicates_of(trait_def_id); }; let Node::Item(item) = tcx.hir_node_by_def_id(trait_def_id) else { @@ -586,7 +618,7 @@ pub(super) fn implied_predicates_with_filter( // Combine the two lists to form the complete set of superbounds: let implied_bounds = - &*tcx.arena.alloc_from_iter(superbounds.clauses().chain(where_bounds_that_match)); + &*tcx.arena.alloc_from_iter(superbounds.clauses(tcx).chain(where_bounds_that_match)); debug!(?implied_bounds); // Now require that immediate supertraits are lowered, which will, in @@ -600,7 +632,7 @@ pub(super) fn implied_predicates_with_filter( if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder() && bound.polarity == ty::PredicatePolarity::Positive { - tcx.at(span).super_predicates_of(bound.def_id()); + tcx.at(span).explicit_super_predicates_of(bound.def_id()); } } } @@ -610,14 +642,18 @@ pub(super) fn implied_predicates_with_filter( if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder() && bound.polarity == ty::PredicatePolarity::Positive { - tcx.at(span).implied_predicates_of(bound.def_id()); + tcx.at(span).explicit_implied_predicates_of(bound.def_id()); } } } _ => {} } - ty::GenericPredicates { parent: None, predicates: implied_bounds } + ty::GenericPredicates { + parent: None, + predicates: implied_bounds, + effects_min_tys: ty::List::empty(), + } } /// Returns the predicates defined on `item_def_id` of the form @@ -743,7 +779,7 @@ impl<'tcx> ItemCtxt<'tcx> { ); } - bounds.clauses().collect() + bounds.clauses(self.tcx).collect() } #[instrument(level = "trace", skip(self))] 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 5c7733065c6..cad7870a0a1 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -603,7 +603,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { match item.kind { - hir::ForeignItemKind::Fn(_, _, generics) => { + hir::ForeignItemKind::Fn(_, _, generics, _) => { self.visit_early_late(item.hir_id(), generics, |this| { intravisit::walk_foreign_item(this, item); }) @@ -951,7 +951,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { self.visit_ty(ty); } } - GenericParamKind::Const { ty, default, is_host_effect: _ } => { + GenericParamKind::Const { ty, default, .. } => { self.visit_ty(ty); if let Some(default) = default { self.visit_body(self.tcx.hir().body(default.body)); @@ -1468,12 +1468,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { depth: usize, generic_args: &'tcx hir::GenericArgs<'tcx>, ) { - if generic_args.parenthesized == hir::GenericArgsParentheses::ParenSugar { - self.visit_fn_like_elision( - generic_args.inputs(), - Some(generic_args.bindings[0].ty()), - false, - ); + if let Some((inputs, output)) = generic_args.paren_sugar_inputs_output() { + self.visit_fn_like_elision(inputs, Some(output), false); return; } @@ -1608,8 +1604,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { } } - // Hack: when resolving the type `XX` in binding like `dyn - // Foo<'b, Item = XX>`, the current object-lifetime default + // Hack: When resolving the type `XX` in an assoc ty binding like + // `dyn Foo<'b, Item = XX>`, the current object-lifetime default // would be to examine the trait `Foo` to check whether it has // a lifetime bound declared on `Item`. e.g., if `Foo` is // declared like so, then the default object lifetime bound in @@ -1637,7 +1633,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // Resolve lifetimes found in the bindings, so either in the type `XX` in `Item = XX` or // in the trait ref `YY<...>` in `Item: YY<...>`. - for binding in generic_args.bindings { + for constraint in generic_args.constraints { let scope = Scope::ObjectLifetimeDefault { lifetime: if has_lifetime_parameter { None @@ -1646,7 +1642,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { }, s: self.scope, }; - // If the binding is parenthesized, then this must be `feature(return_type_notation)`. + // If the args are parenthesized, then this must be `feature(return_type_notation)`. // In that case, introduce a binder over all of the function's early and late bound vars. // // For example, given @@ -1659,13 +1655,14 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // `for<'a> T::Trait<'a, x(): for<'b> Other<'b>>` // this is going to expand to something like: // `for<'a> for<'r, T> <T as Trait<'a>>::x::<'r, T>::{opaque#0}: for<'b> Other<'b>`. - if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation { + if constraint.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation + { let bound_vars = if let Some(type_def_id) = type_def_id && self.tcx.def_kind(type_def_id) == DefKind::Trait && let Some((mut bound_vars, assoc_fn)) = BoundVarContext::supertrait_hrtb_vars( self.tcx, type_def_id, - binding.ident, + constraint.ident, ty::AssocKind::Fn, ) { bound_vars.extend(self.tcx.generics_of(assoc_fn.def_id).own_params.iter().map( @@ -1686,22 +1683,22 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { } else { self.tcx .dcx() - .span_delayed_bug(binding.ident.span, "bad return type notation here"); + .span_delayed_bug(constraint.ident.span, "bad return type notation here"); vec![] }; self.with(scope, |this| { let scope = Scope::Supertrait { bound_vars, s: this.scope }; this.with(scope, |this| { let (bound_vars, _) = this.poly_trait_ref_binder_info(); - this.record_late_bound_vars(binding.hir_id, bound_vars); - this.visit_assoc_type_binding(binding) + this.record_late_bound_vars(constraint.hir_id, bound_vars); + this.visit_assoc_item_constraint(constraint) }); }); } else if let Some(type_def_id) = type_def_id { let bound_vars = BoundVarContext::supertrait_hrtb_vars( self.tcx, type_def_id, - binding.ident, + constraint.ident, ty::AssocKind::Type, ) .map(|(bound_vars, _)| bound_vars); @@ -1710,10 +1707,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { bound_vars: bound_vars.unwrap_or_default(), s: this.scope, }; - this.with(scope, |this| this.visit_assoc_type_binding(binding)); + this.with(scope, |this| this.visit_assoc_item_constraint(constraint)); }); } else { - self.with(scope, |this| this.visit_assoc_type_binding(binding)); + self.with(scope, |this| this.visit_assoc_item_constraint(constraint)); } } } @@ -1763,7 +1760,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { if let Some(assoc_item) = trait_defines_associated_item_named(def_id) { break Some((bound_vars.into_iter().collect(), assoc_item)); } - let predicates = tcx.super_predicates_that_define_assoc_item((def_id, assoc_name)); + let predicates = tcx.explicit_supertraits_containing_assoc_item((def_id, assoc_name)); let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| { let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 1475e53c47c..974dd415f46 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -12,10 +12,10 @@ use rustc_span::symbol::Ident; use rustc_span::{Span, DUMMY_SP}; use crate::errors::TypeofReservedKeywordUsed; +use crate::hir_ty_lowering::HirTyLowerer; use super::bad_placeholder; use super::ItemCtxt; -pub use opaque::test_opaque_hidden_types; mod opaque; @@ -220,9 +220,10 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { .position(|arg| arg.hir_id() == hir_id) .map(|index| (index, seg)) .or_else(|| { - args.bindings + args.constraints .iter() - .filter_map(TypeBinding::opt_const) + .copied() + .filter_map(AssocItemConstraint::ct) .position(|ct| ct.hir_id == hir_id) .map(|idx| (idx, seg)) }) @@ -309,7 +310,7 @@ fn get_path_containing_arg_in_pat<'hir>( arg_path } -pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty<'_>> { +pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, Ty<'_>> { use rustc_hir::*; use rustc_middle::ty::Ty; @@ -357,7 +358,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty .and_then(|body_id| { ty.is_suggestable_infer_ty().then(|| { infer_placeholder_type( - tcx, + icx.lowerer(), def_id, body_id, ty.span, @@ -381,7 +382,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty ImplItemKind::Const(ty, body_id) => { if ty.is_suggestable_infer_ty() { infer_placeholder_type( - tcx, + icx.lowerer(), def_id, body_id, ty.span, @@ -405,7 +406,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty ItemKind::Static(ty, .., body_id) => { if ty.is_suggestable_infer_ty() { infer_placeholder_type( - tcx, + icx.lowerer(), def_id, body_id, ty.span, @@ -418,7 +419,14 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty } ItemKind::Const(ty, _, body_id) => { if ty.is_suggestable_infer_ty() { - infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant") + infer_placeholder_type( + icx.lowerer(), + def_id, + body_id, + ty.span, + item.ident, + "constant", + ) } else { icx.lower_ty(ty) } @@ -463,7 +471,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty let args = ty::GenericArgs::identity_for_item(tcx, def_id); Ty::new_fn_def(tcx, def_id.to_def_id(), args) } - ForeignItemKind::Static(t, _) => icx.lower_ty(t), + ForeignItemKind::Static(t, _, _) => icx.lower_ty(t), ForeignItemKind::Type => Ty::new_foreign(tcx, def_id.to_def_id()), }, @@ -502,7 +510,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty bug!("unexpected sort of node in type_of(): {:?}", x); } }; - if let Err(e) = icx.check_tainted_by_errors() { + if let Err(e) = icx.check_tainted_by_errors() + && !output.references_error() + { ty::EarlyBinder::bind(Ty::new_error(tcx, e)) } else { ty::EarlyBinder::bind(output) @@ -512,7 +522,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty pub(super) fn type_of_opaque( tcx: TyCtxt<'_>, def_id: DefId, -) -> Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> { +) -> Result<ty::EarlyBinder<'_, Ty<'_>>, CyclePlaceholder> { if let Some(def_id) = def_id.as_local() { use rustc_hir::*; @@ -557,21 +567,22 @@ pub(super) fn type_of_opaque( } } -fn infer_placeholder_type<'a>( - tcx: TyCtxt<'a>, +fn infer_placeholder_type<'tcx>( + cx: &dyn HirTyLowerer<'tcx>, def_id: LocalDefId, body_id: hir::BodyId, span: Span, item_ident: Ident, kind: &'static str, -) -> Ty<'a> { +) -> Ty<'tcx> { + let tcx = cx.tcx(); let ty = tcx.diagnostic_only_typeck(def_id).node_type(body_id.hir_id); // If this came from a free `const` or `static mut?` item, // then the user may have written e.g. `const A = 42;`. // In this case, the parser has stashed a diagnostic for // us to improve in typeck so we do that now. - let guar = tcx + let guar = cx .dcx() .try_steal_modify_and_emit_err(span, StashKey::ItemNoType, |err| { if !ty.references_error() { @@ -600,7 +611,7 @@ fn infer_placeholder_type<'a>( } }) .unwrap_or_else(|| { - let mut diag = bad_placeholder(tcx, vec![span], kind); + let mut diag = bad_placeholder(cx, vec![span], kind); if !ty.references_error() { if let Some(ty) = ty.make_suggestable(tcx, false, None) { diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 1bec8c496ad..d1048b742a0 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -1,28 +1,14 @@ use rustc_errors::StashKey; use rustc_hir::def::DefKind; -use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir, def, Expr, ImplItem, Item, Node, TraitItem}; use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP}; +use rustc_span::DUMMY_SP; -use crate::errors::{TaitForwardCompat, TypeOf, UnconstrainedOpaqueType}; - -pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { - let mut res = Ok(()); - if tcx.has_attr(CRATE_DEF_ID, sym::rustc_hidden_type_of_opaques) { - for id in tcx.hir().items() { - if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) { - let type_of = tcx.type_of(id.owner_id).instantiate_identity(); - - res = Err(tcx.dcx().emit_err(TypeOf { span: tcx.def_span(id.owner_id), type_of })); - } - } - } - res -} +use crate::errors::{TaitForwardCompat, TaitForwardCompat2, UnconstrainedOpaqueType}; /// Checks "defining uses" of opaque `impl Trait` in associated types. /// These can only be defined by associated items of the same trait. @@ -229,13 +215,14 @@ impl TaitConstraintLocator<'_> { return; } + let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id); + let mut constrained = false; for (&opaque_type_key, &hidden_type) in &tables.concrete_opaque_types { if opaque_type_key.def_id != self.def_id { continue; } constrained = true; - let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id); if !opaque_types_defined_by.contains(&self.def_id) { self.tcx.dcx().emit_err(TaitForwardCompat { @@ -259,6 +246,16 @@ impl TaitConstraintLocator<'_> { if !constrained { debug!("no constraints in typeck results"); + if opaque_types_defined_by.contains(&self.def_id) { + self.tcx.dcx().emit_err(TaitForwardCompat2 { + span: self + .tcx + .def_ident_span(item_def_id) + .unwrap_or_else(|| self.tcx.def_span(item_def_id)), + opaque_type_span: self.tcx.def_span(self.def_id), + opaque_type: self.tcx.def_path_str(self.def_id), + }); + } return; }; diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 1c99713b3ae..0ee87a13e9e 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -2,13 +2,14 @@ use crate::fluent_generated as fluent; use rustc_errors::{ - codes::*, Applicability, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level, MultiSpan, + codes::*, Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; use rustc_span::{symbol::Ident, Span, Symbol}; mod pattern_types; pub use pattern_types::*; +pub mod wrong_number_of_generic_args; mod precise_captures; pub(crate) use precise_captures::*; @@ -56,6 +57,18 @@ pub struct AssocKindMismatchWrapInBracesSugg { } #[derive(Diagnostic)] +#[diag(hir_analysis_assoc_item_is_private, code = E0624)] +pub struct AssocItemIsPrivate { + #[primary_span] + #[label] + pub span: Span, + pub kind: &'static str, + pub name: Ident, + #[label(hir_analysis_defined_here_label)] + pub defined_here_label: Span, +} + +#[derive(Diagnostic)] #[diag(hir_analysis_assoc_item_not_found, code = E0220)] pub struct AssocItemNotFound<'a> { #[primary_span] @@ -290,8 +303,8 @@ pub struct AmbiguousLifetimeBound { } #[derive(Diagnostic)] -#[diag(hir_analysis_assoc_type_binding_not_allowed, code = E0229)] -pub struct AssocTypeBindingNotAllowed { +#[diag(hir_analysis_assoc_item_constraints_not_allowed_here, code = E0229)] +pub struct AssocItemConstraintsNotAllowedHere { #[primary_span] #[label] pub span: Span, @@ -390,6 +403,17 @@ pub struct TaitForwardCompat { pub item_span: Span, } +#[derive(Diagnostic)] +#[diag(hir_analysis_tait_forward_compat2)] +#[note] +pub struct TaitForwardCompat2 { + #[primary_span] + pub span: Span, + #[note(hir_analysis_opaque)] + pub opaque_type_span: Span, + pub opaque_type: String, +} + pub struct MissingTypeParams { pub span: Span, pub def_span: Span, @@ -401,7 +425,7 @@ pub struct MissingTypeParams { // Manual implementation of `Diagnostic` to be able to call `span_to_snippet`. impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingTypeParams { #[track_caller] - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let mut err = Diag::new(dcx, level, fluent::hir_analysis_missing_type_params); err.span(self.span); err.code(E0393); @@ -430,12 +454,11 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingTypeParams { } 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<Type>`. - err.span_suggestion( - self.span, + err.span_suggestion_verbose( + self.span.shrink_to_hi(), fluent::hir_analysis_suggestion, format!( - "{}<{}>", - snippet, + "<{}>", self.missing_type_params .iter() .map(|n| n.to_string()) @@ -659,7 +682,7 @@ pub(crate) enum CannotCaptureLateBound { pub(crate) struct VariancesOf { #[primary_span] pub span: Span, - pub variances_of: String, + pub variances: String, } #[derive(Diagnostic)] @@ -667,30 +690,7 @@ pub(crate) struct VariancesOf { pub(crate) struct TypeOf<'tcx> { #[primary_span] pub span: Span, - pub type_of: Ty<'tcx>, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis_pass_to_variadic_function, code = E0617)] -pub(crate) struct PassToVariadicFunction<'tcx, 'a> { - #[primary_span] - pub span: Span, pub ty: Ty<'tcx>, - pub cast_ty: &'a str, - #[suggestion(code = "{replace}", applicability = "machine-applicable")] - pub sugg_span: Option<Span>, - pub replace: String, - #[help] - pub help: Option<()>, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis_cast_thin_pointer_to_fat_pointer, code = E0607)] -pub(crate) struct CastThinPointerToFatPointer<'tcx> { - #[primary_span] - pub span: Span, - pub expr_ty: Ty<'tcx>, - pub cast_ty: String, } #[derive(Diagnostic)] @@ -1676,3 +1676,9 @@ pub struct InvalidReceiverTy<'tcx> { pub span: Span, pub receiver_ty: Ty<'tcx>, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_effects_without_next_solver)] +#[note] +#[help] +pub struct EffectsWithoutNextSolver; diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs index 9ddba7a6e7a..6426ad9dc18 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs @@ -1,8 +1,8 @@ -use crate::structured_errors::StructuredDiag; -use rustc_errors::{codes::*, pluralize, Applicability, Diag, MultiSpan}; +use rustc_errors::{ + codes::*, pluralize, Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan, +}; use rustc_hir as hir; use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt}; -use rustc_session::Session; use rustc_span::def_id::DefId; use std::iter; @@ -489,7 +489,11 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { .in_definition_order() .filter(|item| item.kind == AssocKind::Type) .filter(|item| { - !self.gen_args.bindings.iter().any(|binding| binding.ident.name == item.name) + !self + .gen_args + .constraints + .iter() + .any(|constraint| constraint.ident.name == item.name) }) .map(|item| item.name.to_ident_string()) .collect() @@ -537,14 +541,8 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn start_diagnostics(&self) -> Diag<'tcx> { - let span = self.path_segment.ident.span; - let msg = self.create_error_message(); - self.tcx.dcx().struct_span_err(span, msg).with_code(self.code()) - } - /// Builds the `expected 1 type argument / supplied 2 type arguments` message. - fn notify(&self, err: &mut Diag<'_>) { + fn notify(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { let (quantifier, bound) = self.get_quantifier_and_bound(); let provided_args = self.num_provided_args(); @@ -596,7 +594,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn suggest(&self, err: &mut Diag<'_>) { + fn suggest(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { debug!( "suggest(self.provided {:?}, self.gen_args.span(): {:?})", self.num_provided_args(), @@ -624,7 +622,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { /// ```text /// type Map = HashMap<String>; /// ``` - fn suggest_adding_args(&self, err: &mut Diag<'_>) { + fn suggest_adding_args(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { if self.gen_args.parenthesized != hir::GenericArgsParentheses::No { return; } @@ -643,7 +641,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn suggest_adding_lifetime_args(&self, err: &mut Diag<'_>) { + fn suggest_adding_lifetime_args(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { debug!("suggest_adding_lifetime_args(path_segment: {:?})", self.path_segment); let num_missing_args = self.num_missing_lifetime_args(); let num_params_to_take = num_missing_args; @@ -679,11 +677,11 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { (last_lt.span().shrink_to_hi(), false) }; let has_non_lt_args = self.num_provided_type_or_const_args() != 0; - let has_bindings = !self.gen_args.bindings.is_empty(); + let has_constraints = !self.gen_args.constraints.is_empty(); let sugg_prefix = if is_first { "" } else { ", " }; let sugg_suffix = - if is_first && (has_non_lt_args || has_bindings) { ", " } else { "" }; + if is_first && (has_non_lt_args || has_constraints) { ", " } else { "" }; let sugg = format!("{sugg_prefix}{suggested_args}{sugg_suffix}"); debug!("sugg: {:?}", sugg); @@ -697,7 +695,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn suggest_adding_type_and_const_args(&self, err: &mut Diag<'_>) { + fn suggest_adding_type_and_const_args(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { let num_missing_args = self.num_missing_type_or_const_args(); let msg = format!("add missing {} argument{}", self.kind(), pluralize!(num_missing_args)); @@ -741,7 +739,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { let sugg_prefix = if is_first { "" } else { ", " }; let sugg_suffix = - if is_first && !self.gen_args.bindings.is_empty() { ", " } else { "" }; + if is_first && !self.gen_args.constraints.is_empty() { ", " } else { "" }; let sugg = format!("{sugg_prefix}{suggested_args}{sugg_suffix}"); debug!("sugg: {:?}", sugg); @@ -757,7 +755,10 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { /// ```compile_fail /// Into::into::<Option<_>>(42) // suggests considering `Into::<Option<_>>::into(42)` /// ``` - fn suggest_moving_args_from_assoc_fn_to_trait(&self, err: &mut Diag<'_>) { + fn suggest_moving_args_from_assoc_fn_to_trait( + &self, + err: &mut Diag<'_, impl EmissionGuarantee>, + ) { let trait_ = match self.tcx.trait_of_item(self.def_id) { Some(def_id) => def_id, None => return, @@ -813,7 +814,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { fn suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path( &self, - err: &mut Diag<'_>, + err: &mut Diag<'_, impl EmissionGuarantee>, qpath: &'tcx hir::QPath<'tcx>, msg: String, num_assoc_fn_excess_args: usize, @@ -846,7 +847,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { fn suggest_moving_args_from_assoc_fn_to_trait_for_method_call( &self, - err: &mut Diag<'_>, + err: &mut Diag<'_, impl EmissionGuarantee>, trait_def_id: DefId, expr: &'tcx hir::Expr<'tcx>, msg: String, @@ -900,7 +901,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { /// ```text /// type Map = HashMap<String, String, String, String>; /// ``` - fn suggest_removing_args_or_generics(&self, err: &mut Diag<'_>) { + fn suggest_removing_args_or_generics(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { let num_provided_lt_args = self.num_provided_lifetime_args(); let num_provided_type_const_args = self.num_provided_type_or_const_args(); let unbound_types = self.get_unbound_associated_types(); @@ -918,7 +919,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { let provided_args_matches_unbound_traits = unbound_types.len() == num_redundant_type_or_const_args; - let remove_lifetime_args = |err: &mut Diag<'_>| { + let remove_lifetime_args = |err: &mut Diag<'_, _>| { let mut lt_arg_spans = Vec::new(); let mut found_redundant = false; for arg in self.gen_args.args { @@ -959,7 +960,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { ); }; - let remove_type_or_const_args = |err: &mut Diag<'_>| { + let remove_type_or_const_args = |err: &mut Diag<'_, _>| { let mut gen_arg_spans = Vec::new(); let mut found_redundant = false; for arg in self.gen_args.args { @@ -1056,7 +1057,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } /// Builds the `type defined here` message. - fn show_definition(&self, err: &mut Diag<'_>) { + fn show_definition(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) { if self.tcx.sess.source_map().is_span_accessible(def_span) { def_span.into() @@ -1107,7 +1108,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } /// Add note if `impl Trait` is explicitly specified. - fn note_synth_provided(&self, err: &mut Diag<'_>) { + fn note_synth_provided(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { if !self.is_synth_provided() { return; } @@ -1116,17 +1117,16 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } -impl<'tcx> StructuredDiag<'tcx> for WrongNumberOfGenericArgs<'_, 'tcx> { - fn session(&self) -> &Session { - self.tcx.sess - } - - fn code(&self) -> ErrCode { - E0107 - } - - fn diagnostic_common(&self) -> Diag<'tcx> { - let mut err = self.start_diagnostics(); +impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for WrongNumberOfGenericArgs<'_, '_> { + fn into_diag( + self, + dcx: rustc_errors::DiagCtxtHandle<'a>, + level: rustc_errors::Level, + ) -> Diag<'a, G> { + let msg = self.create_error_message(); + let mut err = Diag::new(dcx, level, msg); + err.code(E0107); + err.span(self.path_segment.ident.span); self.notify(&mut err); self.suggest(&mut err); 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 b0ae73fcc4b..a1feef9e15b 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -18,6 +18,8 @@ use crate::bounds::Bounds; use crate::errors; use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter}; +use super::RegionInferReason; + impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Add a `Sized` bound to the `bounds` if appropriate. /// @@ -74,7 +76,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } if unbounds.len() > 1 { - tcx.dcx().emit_err(errors::MultipleRelaxedDefaultBounds { + self.dcx().emit_err(errors::MultipleRelaxedDefaultBounds { spans: unbounds.iter().map(|ptr| ptr.span).collect(), }); } @@ -88,7 +90,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { continue; } // There was a `?Trait` bound, but it was not `?Sized`; warn. - tcx.dcx().span_warn( + self.dcx().span_warn( unbound.span, "relaxing a default bound only does something for `?Sized`; \ all other traits are not bound by default", @@ -166,7 +168,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); } hir::GenericBound::Outlives(lifetime) => { - let region = self.lower_lifetime(lifetime, None); + let region = self.lower_lifetime(lifetime, RegionInferReason::OutlivesBound); bounds.push_region_bound( self.tcx(), ty::Binder::bind_with_vars( @@ -176,6 +178,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { lifetime.ident.span, ); } + hir::GenericBound::Use(..) => { + // We don't actually lower `use` into the type layer. + } } } } @@ -230,32 +235,34 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bounds } - /// Lower an associated item binding from HIR into `bounds`. + /// Lower an associated item constraint from the HIR into `bounds`. /// /// ### A Note on Binders /// /// Given something like `T: for<'a> Iterator<Item = &'a u32>`, /// the `trait_ref` here will be `for<'a> T: Iterator`. - /// The `binding` data however is from *inside* the binder + /// The `constraint` data however is from *inside* the binder /// (e.g., `&'a u32`) and hence may reference bound regions. - #[instrument(level = "debug", skip(self, bounds, dup_bindings, path_span))] - pub(super) fn lower_assoc_item_binding( + #[instrument(level = "debug", skip(self, bounds, duplicates, path_span))] + pub(super) fn lower_assoc_item_constraint( &self, hir_ref_id: hir::HirId, trait_ref: ty::PolyTraitRef<'tcx>, - binding: &hir::TypeBinding<'tcx>, + constraint: &hir::AssocItemConstraint<'tcx>, bounds: &mut Bounds<'tcx>, - dup_bindings: &mut FxIndexMap<DefId, Span>, + duplicates: &mut FxIndexMap<DefId, Span>, path_span: Span, only_self_bounds: OnlySelfBounds, ) -> Result<(), ErrorGuaranteed> { let tcx = self.tcx(); - let assoc_kind = if binding.gen_args.parenthesized + let assoc_kind = if constraint.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation { ty::AssocKind::Fn - } else if let hir::TypeBindingKind::Equality { term: hir::Term::Const(_) } = binding.kind { + } else if let hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(_) } = + constraint.kind + { ty::AssocKind::Const } else { ty::AssocKind::Type @@ -272,7 +279,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let candidate = if self.probe_trait_that_defines_assoc_item( trait_ref.def_id(), assoc_kind, - binding.ident, + constraint.ident, ) { // Simple case: The assoc item is defined in the current trait. trait_ref @@ -284,48 +291,33 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { trait_ref.skip_binder().print_only_trait_name(), None, assoc_kind, - binding.ident, + constraint.ident, path_span, - Some(binding), + Some(constraint), )? }; - let (assoc_ident, def_scope) = - tcx.adjust_ident_and_get_scope(binding.ident, candidate.def_id(), hir_ref_id); - - // We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()` - // instead of calling `filter_by_name_and_kind` which would needlessly normalize the - // `assoc_ident` again and again. - let assoc_item = tcx - .associated_items(candidate.def_id()) - .filter_by_name_unhygienic(assoc_ident.name) - .find(|i| i.kind == assoc_kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident) - .expect("missing associated item"); - - if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) { - let reported = tcx - .dcx() - .struct_span_err( - binding.span, - format!("{} `{}` is private", assoc_item.kind, binding.ident), - ) - .with_span_label(binding.span, format!("private {}", assoc_item.kind)) - .emit(); - self.set_tainted_by_errors(reported); - } - tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), binding.span, None); + let assoc_item = self + .probe_assoc_item( + constraint.ident, + assoc_kind, + hir_ref_id, + constraint.span, + candidate.def_id(), + ) + .expect("failed to find associated item"); - dup_bindings + duplicates .entry(assoc_item.def_id) .and_modify(|prev_span| { - tcx.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified { - span: binding.span, + self.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified { + span: constraint.span, prev_span: *prev_span, - item_name: binding.ident, + item_name: constraint.ident, def_path: tcx.def_path_str(assoc_item.container_id(tcx)), }); }) - .or_insert(binding.span); + .or_insert(constraint.span); let projection_term = if let ty::AssocKind::Fn = assoc_kind { let mut emitted_bad_param_err = None; @@ -346,7 +338,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .into(), ty::GenericParamDefKind::Type { .. } => { let guar = *emitted_bad_param_err.get_or_insert_with(|| { - tcx.dcx().emit_err( + self.dcx().emit_err( crate::errors::ReturnTypeNotationIllegalParam::Type { span: path_span, param_span: tcx.def_span(param.def_id), @@ -357,18 +349,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } ty::GenericParamDefKind::Const { .. } => { let guar = *emitted_bad_param_err.get_or_insert_with(|| { - tcx.dcx().emit_err( + self.dcx().emit_err( crate::errors::ReturnTypeNotationIllegalParam::Const { span: path_span, param_span: tcx.def_span(param.def_id), }, ) }); - let ty = tcx - .type_of(param.def_id) - .no_bound_vars() - .expect("ct params cannot have early bound vars"); - ty::Const::new_error(tcx, guar, ty).into() + ty::Const::new_error(tcx, guar).into() } }; num_bound_vars += 1; @@ -383,8 +371,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { { alias_ty.into() } else { - return Err(tcx.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit { - span: binding.span, + return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit { + span: constraint.span, ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output), fn_span: tcx.hir().span_if_local(assoc_item.def_id), note: (), @@ -398,19 +386,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output); let instantiation_output = ty::EarlyBinder::bind(shifted_output).instantiate(tcx, args); - let bound_vars = tcx.late_bound_vars(binding.hir_id); + let bound_vars = tcx.late_bound_vars(constraint.hir_id); ty::Binder::bind_with_vars(instantiation_output, bound_vars) } else { // Create the generic arguments for the associated type or constant by joining the // parent arguments (the arguments of the trait) and the own arguments (the ones of // the associated item itself) and construct an alias type using them. - let alias_ty = candidate.map_bound(|trait_ref| { - let ident = Ident::new(assoc_item.name, binding.ident.span); + let alias_term = candidate.map_bound(|trait_ref| { let item_segment = hir::PathSegment { - ident, - hir_id: binding.hir_id, + ident: constraint.ident, + hir_id: constraint.hir_id, res: Res::Err, - args: Some(binding.gen_args), + args: Some(constraint.gen_args), infer_args: false, }; @@ -422,30 +409,30 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); debug!(?alias_args); - ty::AliasTerm::new(tcx, assoc_item.def_id, alias_args) + ty::AliasTerm::new_from_args(tcx, assoc_item.def_id, alias_args) }); // Provide the resolved type of the associated constant to `type_of(AnonConst)`. - if let hir::TypeBindingKind::Equality { term: hir::Term::Const(anon_const) } = - binding.kind - { - let ty = alias_ty.map_bound(|ty| tcx.type_of(ty.def_id).instantiate(tcx, ty.args)); - let ty = check_assoc_const_binding_type(tcx, assoc_ident, ty, binding.hir_id); + if let Some(anon_const) = constraint.ct() { + let ty = alias_term + .map_bound(|alias| tcx.type_of(alias.def_id).instantiate(tcx, alias.args)); + let ty = + check_assoc_const_binding_type(self, constraint.ident, ty, constraint.hir_id); tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty)); } - alias_ty + alias_term }; - match binding.kind { - hir::TypeBindingKind::Equality { .. } if let ty::AssocKind::Fn = assoc_kind => { - return Err(tcx.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound { - span: binding.span, + match constraint.kind { + hir::AssocItemConstraintKind::Equality { .. } if let ty::AssocKind::Fn = assoc_kind => { + return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound { + span: constraint.span, })); } // Lower an equality constraint like `Item = u32` as found in HIR bound `T: Iterator<Item = u32>` // to a projection predicate: `<T as Iterator>::Item = u32`. - hir::TypeBindingKind::Equality { term } => { + hir::AssocItemConstraintKind::Equality { term } => { let term = match term { hir::Term::Ty(ty) => self.lower_ty(ty).into(), hir::Term::Const(ct) => ty::Const::from_anon_const(tcx, ct.def_id).into(), @@ -469,18 +456,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F); // ---- ---- ^^^^^^^ // NOTE(associated_const_equality): This error should be impossible to trigger - // with associated const equality bounds. + // with associated const equality constraints. self.validate_late_bound_regions( late_bound_in_projection_ty, late_bound_in_term, |br_name| { struct_span_code_err!( - tcx.dcx(), - binding.span, + self.dcx(), + constraint.span, E0582, "binding for associated type `{}` references {}, \ - which does not appear in the trait input types", - binding.ident, + which does not appear in the trait input types", + constraint.ident, br_name ) }, @@ -492,12 +479,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { projection_term, term, }), - binding.span, + constraint.span, ); } // Lower a constraint like `Item: Debug` as found in HIR bound `T: Iterator<Item: Debug>` // to a bound involving a projection: `<T as Iterator>::Item: Debug`. - hir::TypeBindingKind::Constraint { bounds: hir_bounds } => { + hir::AssocItemConstraintKind::Bound { bounds: hir_bounds } => { // NOTE: If `only_self_bounds` is true, do NOT expand this associated type bound into // a trait predicate, since we only want to add predicates for the `Self` type. if !only_self_bounds.0 { @@ -532,7 +519,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// /// [^1]: <https://github.com/rust-lang/project-const-generics/issues/28>. fn check_assoc_const_binding_type<'tcx>( - tcx: TyCtxt<'tcx>, + cx: &dyn HirTyLowerer<'tcx>, assoc_const: Ident, ty: ty::Binder<'tcx, Ty<'tcx>>, hir_id: hir::HirId, @@ -549,13 +536,14 @@ fn check_assoc_const_binding_type<'tcx>( } let mut collector = GenericParamAndBoundVarCollector { - tcx, + cx, params: Default::default(), vars: Default::default(), depth: ty::INNERMOST, }; let mut guar = ty.visit_with(&mut collector).break_value(); + let tcx = cx.tcx(); let ty_note = ty .make_suggestable(tcx, false, None) .map(|ty| crate::errors::TyOfAssocConstBindingNote { assoc_const, ty }); @@ -569,7 +557,7 @@ fn check_assoc_const_binding_type<'tcx>( for index in collector.params { let param = generics.param_at(index as _, tcx); let is_self_param = param.name == rustc_span::symbol::kw::SelfUpper; - guar.get_or_insert(tcx.dcx().emit_err(crate::errors::ParamInTyOfAssocConstBinding { + guar.get_or_insert(cx.dcx().emit_err(crate::errors::ParamInTyOfAssocConstBinding { span: assoc_const.span, assoc_const, param_name: param.name, @@ -587,7 +575,7 @@ fn check_assoc_const_binding_type<'tcx>( })); } for (var_def_id, var_name) in collector.vars { - guar.get_or_insert(tcx.dcx().emit_err( + guar.get_or_insert(cx.dcx().emit_err( crate::errors::EscapingBoundVarInTyOfAssocConstBinding { span: assoc_const.span, assoc_const, @@ -603,14 +591,14 @@ fn check_assoc_const_binding_type<'tcx>( Ty::new_error(tcx, guar) } -struct GenericParamAndBoundVarCollector<'tcx> { - tcx: TyCtxt<'tcx>, +struct GenericParamAndBoundVarCollector<'a, 'tcx> { + cx: &'a dyn HirTyLowerer<'tcx>, params: FxIndexSet<u32>, vars: FxIndexSet<(DefId, Symbol)>, depth: ty::DebruijnIndex, } -impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'tcx> { +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 'tcx> { type Result = ControlFlow<ErrorGuaranteed>; fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>( @@ -633,7 +621,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'tcx> ty::BoundTyKind::Param(def_id, name) => (def_id, name), ty::BoundTyKind::Anon => { let reported = self - .tcx + .cx .dcx() .delayed_bug(format!("unexpected anon bound ty: {:?}", bt.var)); return ControlFlow::Break(reported); @@ -656,7 +644,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'tcx> ty::BrNamed(def_id, name) => (def_id, name), ty::BrAnon | ty::BrEnv => { let guar = self - .tcx + .cx .dcx() .delayed_bug(format!("unexpected bound region kind: {:?}", br.kind)); return ControlFlow::Break(guar); @@ -674,7 +662,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'tcx> self.params.insert(param.index); } ty::ConstKind::Bound(db, ty::BoundVar { .. }) if db >= self.depth => { - let guar = self.tcx.dcx().delayed_bug("unexpected escaping late-bound const var"); + let guar = self.cx.dcx().delayed_bug("unexpected escaping late-bound const var"); return ControlFlow::Break(guar); } _ if ct.has_param() || ct.has_bound_vars() => return ct.super_visit_with(self), 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 9c687d3282b..968f38cf05d 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -1,10 +1,9 @@ use crate::errors::{ - self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams, + self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams, ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits, }; use crate::fluent_generated as fluent; use crate::hir_ty_lowering::HirTyLowerer; -use crate::traits::error_reporting::report_object_safety_error; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordMap; @@ -12,10 +11,9 @@ use rustc_errors::MultiSpan; use rustc_errors::{ codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, }; -use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_infer::traits::FulfillmentError; +use rustc_hir::{self as hir, Node}; use rustc_middle::bug; use rustc_middle::query::Key; use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _}; @@ -28,6 +26,8 @@ use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::BytePos; use rustc_span::{Span, Symbol, DUMMY_SP}; +use rustc_trait_selection::error_reporting::traits::report_object_safety_error; +use rustc_trait_selection::traits::FulfillmentError; use rustc_trait_selection::traits::{ object_safety_violations_for_assoc_item, TraitAliasExpansionInfo, }; @@ -46,7 +46,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return; } - self.tcx().dcx().emit_err(MissingTypeParams { + self.dcx().emit_err(MissingTypeParams { span, def_span: self.tcx().def_span(def_id), span_snippet: self.tcx().sess.source_map().span_to_snippet(span).ok(), @@ -109,7 +109,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if is_impl { let trait_name = self.tcx().def_path_str(trait_def_id); - self.tcx().dcx().emit_err(ManualImplementation { span, trait_name }); + self.dcx().emit_err(ManualImplementation { span, trait_name }); } } @@ -121,7 +121,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { assoc_kind: ty::AssocKind, assoc_name: Ident, span: Span, - binding: Option<&hir::TypeBinding<'tcx>>, + constraint: Option<&hir::AssocItemConstraint<'tcx>>, ) -> ErrorGuaranteed where I: Iterator<Item = ty::PolyTraitRef<'tcx>>, @@ -135,7 +135,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .find(|item| tcx.hygienic_eq(assoc_name, item.ident(tcx), r.def_id())) }) { return self.complain_about_assoc_kind_mismatch( - assoc_item, assoc_kind, assoc_name, span, binding, + assoc_item, assoc_kind, assoc_name, span, constraint, ); } @@ -156,7 +156,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if is_dummy { err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span }); - return tcx.dcx().emit_err(err); + return self.dcx().emit_err(err); } let all_candidate_names: Vec<_> = all_candidates() @@ -174,7 +174,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { assoc_kind: assoc_kind_str, suggested_name, }); - return tcx.dcx().emit_err(err); + return self.dcx().emit_err(err); } // If we didn't find a good item in the supertraits (or couldn't get @@ -239,10 +239,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { assoc_kind: assoc_kind_str, suggested_name, }); - return tcx.dcx().emit_err(err); + return self.dcx().emit_err(err); } - let mut err = tcx.dcx().create_err(err); + let mut err = self.dcx().create_err(err); if suggest_constraining_type_param( tcx, generics, @@ -264,7 +264,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } return err.emit(); } - return tcx.dcx().emit_err(err); + return self.dcx().emit_err(err); } } @@ -291,7 +291,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span: assoc_name.span }); } - tcx.dcx().emit_err(err) + self.dcx().emit_err(err) } fn complain_about_assoc_kind_mismatch( @@ -300,18 +300,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { assoc_kind: ty::AssocKind, ident: Ident, span: Span, - binding: Option<&hir::TypeBinding<'tcx>>, + constraint: Option<&hir::AssocItemConstraint<'tcx>>, ) -> ErrorGuaranteed { let tcx = self.tcx(); let bound_on_assoc_const_label = if let ty::AssocKind::Const = assoc_item.kind - && let Some(binding) = binding - && let hir::TypeBindingKind::Constraint { .. } = binding.kind + && let Some(constraint) = constraint + && let hir::AssocItemConstraintKind::Bound { .. } = constraint.kind { - let lo = if binding.gen_args.span_ext.is_dummy() { + let lo = if constraint.gen_args.span_ext.is_dummy() { ident.span } else { - binding.gen_args.span_ext + constraint.gen_args.span_ext }; Some(lo.between(span.shrink_to_hi())) } else { @@ -319,8 +319,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; // FIXME(associated_const_equality): This has quite a few false positives and negatives. - let wrap_in_braces_sugg = if let Some(binding) = binding - && let hir::TypeBindingKind::Equality { term: hir::Term::Ty(hir_ty) } = binding.kind + let wrap_in_braces_sugg = if let Some(constraint) = constraint + && let Some(hir_ty) = constraint.ty() && let ty = self.lower_ty(hir_ty) && (ty.is_enum() || ty.references_error()) && tcx.features().associated_const_equality @@ -333,10 +333,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { None }; - // For equality bounds, we want to blame the term (RHS) instead of the item (LHS) since + // For equality constraints, we want to blame the term (RHS) instead of the item (LHS) since // one can argue that that's more “intuitive” to the user. - let (span, expected_because_label, expected, got) = if let Some(binding) = binding - && let hir::TypeBindingKind::Equality { term } = binding.kind + let (span, expected_because_label, expected, got) = if let Some(constraint) = constraint + && let hir::AssocItemConstraintKind::Equality { term } = constraint.kind { let span = match term { hir::Term::Ty(ty) => ty.span, @@ -347,7 +347,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { (ident.span, None, assoc_kind, assoc_item.kind) }; - tcx.dcx().emit_err(errors::AssocKindMismatch { + self.dcx().emit_err(errors::AssocKindMismatch { span, expected: super::assoc_kind_str(expected), got: super::assoc_kind_str(got), @@ -366,8 +366,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { traits: &[String], name: Symbol, ) -> ErrorGuaranteed { - let mut err = - struct_span_code_err!(self.tcx().dcx(), span, E0223, "ambiguous associated type"); + let mut err = struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type"); if self .tcx() .resolutions(()) @@ -463,9 +462,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } } - let reported = err.emit(); - self.set_tainted_by_errors(reported); - reported + err.emit() } pub(crate) fn complain_about_ambiguous_inherent_assoc_ty( @@ -475,16 +472,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, ) -> ErrorGuaranteed { let mut err = struct_span_code_err!( - self.tcx().dcx(), + self.dcx(), name.span, E0034, "multiple applicable items in scope" ); err.span_label(name.span, format!("multiple `{name}` found")); self.note_ambiguous_inherent_assoc_ty(&mut err, candidates, span); - let reported = err.emit(); - self.set_tainted_by_errors(reported); - reported + err.emit() } // FIXME(fmease): Heavily adapted from `rustc_hir_typeck::method::suggest`. Deduplicate. @@ -576,7 +571,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; let mut err = struct_span_code_err!( - tcx.dcx(), + self.dcx(), name.span, E0220, "associated type `{name}` not found for `{self_ty}` in the current scope" @@ -662,7 +657,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bounds.sort(); bounds.dedup(); - let mut err = tcx.dcx().struct_span_err( + let mut err = self.dcx().struct_span_err( name.span, format!("the associated type `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied") ); @@ -702,7 +697,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { pub(crate) fn complain_about_missing_assoc_tys( &self, associated_types: FxIndexMap<Span, FxIndexSet<DefId>>, - potential_assoc_types: Vec<Span>, + potential_assoc_types: Vec<usize>, trait_bounds: &[hir::PolyTraitRef<'_>], ) { if associated_types.values().all(|v| v.is_empty()) { @@ -745,7 +740,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if object_safety_violations { return; } + + // related to issue #91997, turbofishes added only when in an expr or pat + let mut in_expr_or_pat = false; if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) { + let grandparent = tcx.parent_hir_node(tcx.parent_hir_id(bound.trait_ref.hir_ref_id)); + in_expr_or_pat = match grandparent { + Node::Expr(_) | Node::Pat(_) => true, + _ => false, + }; match bound.trait_ref.path.segments { // FIXME: `trait_ref.path.span` can point to a full path with multiple // segments, even though `trait_ref.path.segments` is of length `1`. Work @@ -791,8 +794,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let path = poly_trait_ref.trait_ref.path.segments.last()?; let args = path.args?; - Some(args.bindings.iter().filter_map(|binding| { - let ident = binding.ident; + Some(args.constraints.iter().filter_map(|constraint| { + let ident = constraint.ident; let trait_def = path.res.def_id(); let assoc_item = tcx.associated_items(trait_def).find_by_name_and_kind( tcx, @@ -829,7 +832,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { trait_bound_spans.sort(); let mut err = struct_span_code_err!( - tcx.dcx(), + self.dcx(), trait_bound_spans, E0191, "the value of the associated type{} {} must be specified", @@ -901,6 +904,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // `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>`. @@ -974,7 +981,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - self.set_tainted_by_errors(err.emit()); + err.emit(); } /// On ambiguous associated type, look for an associated function whose name matches the @@ -1011,17 +1018,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .filter_by_name_unhygienic(Symbol::intern(&name)) .next() { - let reported = - struct_span_code_err!(tcx.dcx(), span, E0223, "ambiguous associated type") - .with_span_suggestion_verbose( - ident2.span.to(ident3.span), - format!("there is an associated function with a similar name: `{name}`"), - name, - Applicability::MaybeIncorrect, - ) - .emit(); - self.set_tainted_by_errors(reported); - Err(reported) + Err(struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type") + .with_span_suggestion_verbose( + ident2.span.to(ident3.span), + format!("there is an associated function with a similar name: `{name}`"), + name, + Applicability::MaybeIncorrect, + ) + .emit()) } else { Ok(()) } @@ -1120,7 +1124,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let last_span = *arg_spans.last().unwrap(); let span: MultiSpan = arg_spans.into(); let mut err = struct_span_code_err!( - self.tcx().dcx(), + self.dcx(), span, E0109, "{kind} arguments are not allowed on {this_type}", @@ -1130,20 +1134,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.span_label(span, format!("not allowed on {what}")); } generics_args_err_extend(self.tcx(), segments, &mut err, err_extend); - let reported = err.emit(); - self.set_tainted_by_errors(reported); - reported + err.emit() } pub fn report_trait_object_addition_traits_error( &self, regular_traits: &Vec<TraitAliasExpansionInfo<'_>>, ) -> ErrorGuaranteed { - let tcx = self.tcx(); let first_trait = ®ular_traits[0]; let additional_trait = ®ular_traits[1]; let mut err = struct_span_code_err!( - tcx.dcx(), + self.dcx(), additional_trait.bottom().1, E0225, "only auto traits can be used as additional traits in a trait object" @@ -1169,9 +1170,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { for more information on them, visit \ <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>", ); - let reported = err.emit(); - self.set_tainted_by_errors(reported); - reported + err.emit() } pub fn report_trait_object_with_no_traits_error( @@ -1185,21 +1184,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .map(|&(trait_ref, _)| trait_ref.def_id()) .find(|&trait_ref| tcx.is_trait_alias(trait_ref)) .map(|trait_ref| tcx.def_span(trait_ref)); - let reported = - tcx.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span }); - self.set_tainted_by_errors(reported); - reported + + self.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span }) } } -/// Emits an error regarding forbidden type binding associations -pub fn prohibit_assoc_item_binding( - tcx: TyCtxt<'_>, - binding: &hir::TypeBinding<'_>, +/// Emit an error for the given associated item constraint. +pub fn prohibit_assoc_item_constraint( + cx: &dyn HirTyLowerer<'_>, + constraint: &hir::AssocItemConstraint<'_>, segment: Option<(DefId, &hir::PathSegment<'_>, Span)>, ) -> ErrorGuaranteed { - let mut err = tcx.dcx().create_err(AssocTypeBindingNotAllowed { - span: binding.span, + let tcx = cx.tcx(); + let mut err = cx.dcx().create_err(AssocItemConstraintsNotAllowedHere { + span: constraint.span, fn_trait_expansion: if let Some((_, segment, span)) = segment && segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar { @@ -1217,13 +1215,11 @@ pub fn prohibit_assoc_item_binding( // otherwise suggest the removal of the binding. if let Some((def_id, segment, _)) = segment && segment.args().parenthesized == hir::GenericArgsParentheses::No - && let hir::TypeBindingKind::Equality { term } = binding.kind { // Suggests removal of the offending binding let suggest_removal = |e: &mut Diag<'_>| { - let bindings = segment.args().bindings; + let constraints = segment.args().constraints; let args = segment.args().args; - let binding_span = binding.span; // Compute the span to remove based on the position // of the binding. We do that as follows: @@ -1236,26 +1232,21 @@ pub fn prohibit_assoc_item_binding( // the start of the next span or will simply be the // span encomassing everything within the generics brackets - let Some(binding_index) = bindings.iter().position(|b| b.hir_id == binding.hir_id) - else { + let Some(index) = constraints.iter().position(|b| b.hir_id == constraint.hir_id) else { bug!("a type binding exists but its HIR ID not found in generics"); }; - let preceding_span = if binding_index > 0 { - Some(bindings[binding_index - 1].span) + let preceding_span = if index > 0 { + Some(constraints[index - 1].span) } else { args.last().map(|a| a.span()) }; - let next_span = if binding_index < bindings.len() - 1 { - Some(bindings[binding_index + 1].span) - } else { - None - }; + let next_span = constraints.get(index + 1).map(|constraint| constraint.span); let removal_span = match (preceding_span, next_span) { - (Some(prec), _) => binding_span.with_lo(prec.hi()), - (None, Some(next)) => binding_span.with_hi(next.lo()), + (Some(prec), _) => constraint.span.with_lo(prec.hi()), + (None, Some(next)) => constraint.span.with_hi(next.lo()), (None, None) => { let Some(generics_span) = segment.args().span_ext() else { bug!("a type binding exists but generic span is empty"); @@ -1266,14 +1257,12 @@ pub fn prohibit_assoc_item_binding( }; // Now emit the suggestion - if let Ok(suggestion) = tcx.sess.source_map().span_to_snippet(removal_span) { - e.span_suggestion_verbose( - removal_span, - "consider removing this type binding", - suggestion, - Applicability::MaybeIncorrect, - ); - } + e.span_suggestion_verbose( + removal_span, + format!("consider removing this associated item {}", constraint.kind.descr()), + "", + Applicability::MaybeIncorrect, + ); }; // Suggest replacing the associated item binding with a generic argument. @@ -1281,7 +1270,7 @@ pub fn prohibit_assoc_item_binding( let suggest_direct_use = |e: &mut Diag<'_>, sp: Span| { if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(sp) { e.span_suggestion_verbose( - binding.span, + constraint.span, format!("to use `{snippet}` as a generic argument specify it directly"), snippet, Applicability::MaybeIncorrect, @@ -1289,22 +1278,78 @@ pub fn prohibit_assoc_item_binding( } }; - // Check if the type has a generic param with the - // same name as the assoc type name in type binding + // Check if the type has a generic param with the same name + // as the assoc type name in the associated item binding. let generics = tcx.generics_of(def_id); - let matching_param = - generics.own_params.iter().find(|p| p.name.as_str() == binding.ident.as_str()); + let matching_param = generics.own_params.iter().find(|p| p.name == constraint.ident.name); // Now emit the appropriate suggestion if let Some(matching_param) = matching_param { - match (&matching_param.kind, term) { - (GenericParamDefKind::Type { .. }, hir::Term::Ty(ty)) => { - suggest_direct_use(&mut err, ty.span); - } - (GenericParamDefKind::Const { .. }, hir::Term::Const(c)) => { + match (constraint.kind, &matching_param.kind) { + ( + hir::AssocItemConstraintKind::Equality { term: hir::Term::Ty(ty) }, + GenericParamDefKind::Type { .. }, + ) => suggest_direct_use(&mut err, ty.span), + ( + hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(c) }, + GenericParamDefKind::Const { .. }, + ) => { let span = tcx.hir().span(c.hir_id); suggest_direct_use(&mut err, span); } + (hir::AssocItemConstraintKind::Bound { bounds }, _) => { + // Suggest `impl<T: Bound> Trait<T> for Foo` when finding + // `impl Trait<T: Bound> for Foo` + + // Get the parent impl block based on the binding we have + // and the trait DefId + let impl_block = tcx + .hir() + .parent_iter(constraint.hir_id) + .find_map(|(_, node)| node.impl_block_of_trait(def_id)); + + let type_with_constraints = + tcx.sess.source_map().span_to_snippet(constraint.span); + + if let Some(impl_block) = impl_block + && let Ok(type_with_constraints) = type_with_constraints + { + // Filter out the lifetime parameters because + // they should be declared before the type parameter + let lifetimes: String = bounds + .iter() + .filter_map(|bound| { + if let hir::GenericBound::Outlives(lifetime) = bound { + Some(format!("{lifetime}, ")) + } else { + None + } + }) + .collect(); + // Figure out a span and suggestion string based on + // whether there are any existing parameters + let param_decl = if let Some(param_span) = + impl_block.generics.span_for_param_suggestion() + { + (param_span, format!(", {lifetimes}{type_with_constraints}")) + } else { + ( + impl_block.generics.span.shrink_to_lo(), + format!("<{lifetimes}{type_with_constraints}>"), + ) + }; + let suggestions = vec![ + param_decl, + (constraint.span.with_lo(constraint.ident.span.hi()), String::new()), + ]; + + err.multipart_suggestion_verbose( + "declare the type parameter right after the `impl` keyword", + suggestions, + Applicability::MaybeIncorrect, + ); + } + } _ => suggest_removal(&mut err), } } else { @@ -1322,8 +1367,7 @@ pub(crate) fn fn_trait_to_string( ) -> String { let args = trait_segment .args - .as_ref() - .and_then(|args| args.args.get(0)) + .and_then(|args| args.args.first()) .and_then(|arg| match arg { hir::GenericArg::Type(ty) => match ty.kind { hir::TyKind::Tup(t) => t @@ -1334,7 +1378,7 @@ pub(crate) fn fn_trait_to_string( _ => tcx.sess.source_map().span_to_snippet(ty.span), } .map(|s| { - // `s.empty()` checks to see if the type is the unit tuple, if so we don't want a comma + // `is_empty()` checks to see if the type is the unit tuple, if so we don't want a comma if parenthesized || s.is_empty() { format!("({s})") } else { format!("({s},)") } }) .ok(), @@ -1344,20 +1388,17 @@ pub(crate) fn fn_trait_to_string( let ret = trait_segment .args() - .bindings + .constraints .iter() - .find_map(|b| match (b.ident.name == sym::Output, &b.kind) { - (true, hir::TypeBindingKind::Equality { term }) => { - let span = match term { - hir::Term::Ty(ty) => ty.span, - hir::Term::Const(c) => tcx.hir().span(c.hir_id), - }; - - (span != tcx.hir().span(trait_segment.hir_id)) - .then_some(tcx.sess.source_map().span_to_snippet(span).ok()) - .flatten() + .find_map(|c| { + if c.ident.name == sym::Output + && let Some(ty) = c.ty() + && ty.span != tcx.hir().span(trait_segment.hir_id) + { + tcx.sess.source_map().span_to_snippet(ty.span).ok() + } else { + None } - _ => None, }) .unwrap_or_else(|| "()".to_string()); 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 749f78e7920..b1c77db9f37 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -1,9 +1,9 @@ -use super::IsMethodCall; +use super::{HirTyLowerer, IsMethodCall}; +use crate::errors::wrong_number_of_generic_args::{GenericArgsInfo, WrongNumberOfGenericArgs}; use crate::hir_ty_lowering::{ - errors::prohibit_assoc_item_binding, ExplicitLateBound, GenericArgCountMismatch, + errors::prohibit_assoc_item_constraint, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgPosition, GenericArgsLowerer, }; -use crate::structured_errors::{GenericArgsInfo, StructuredDiag, WrongNumberOfGenericArgs}; use rustc_ast::ast::ParamKindOrd; use rustc_errors::{ codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan, @@ -13,7 +13,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::GenericArg; use rustc_middle::ty::{ - self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, TyCtxt, + self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, }; use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS; use rustc_span::symbol::{kw, sym}; @@ -22,15 +22,16 @@ use smallvec::SmallVec; /// Report an error that a generic argument did not match the generic parameter that was /// expected. fn generic_arg_mismatch_err( - tcx: TyCtxt<'_>, + cx: &dyn HirTyLowerer<'_>, arg: &GenericArg<'_>, param: &GenericParamDef, possible_ordering_error: bool, help: Option<String>, ) -> ErrorGuaranteed { + let tcx = cx.tcx(); let sess = tcx.sess; let mut err = struct_span_code_err!( - tcx.dcx(), + cx.dcx(), arg.span(), E0747, "{} provided when a {} was expected", @@ -171,7 +172,7 @@ fn generic_arg_mismatch_err( /// - `inferred_kind`: if no parameter was provided, and inference /// is enabled, then creates a suitable inference variable. pub fn lower_generic_args<'tcx: 'a, 'a>( - tcx: TyCtxt<'tcx>, + cx: &dyn HirTyLowerer<'tcx>, def_id: DefId, parent_args: &[ty::GenericArg<'tcx>], has_self: bool, @@ -179,6 +180,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( arg_count: &GenericArgCountResult, ctx: &mut impl GenericArgsLowerer<'a, 'tcx>, ) -> GenericArgsRef<'tcx> { + let tcx = cx.tcx(); // Collect the segments of the path; we need to instantiate arguments // for parameters throughout the entire path (wherever there are // generic parameters). @@ -214,10 +216,11 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( if let Some(¶m) = params.peek() { if param.index == 0 { if let GenericParamDefKind::Type { .. } = param.kind { + assert_eq!(&args[..], &[]); args.push( self_ty .map(|ty| ty.into()) - .unwrap_or_else(|| ctx.inferred_kind(None, param, true)), + .unwrap_or_else(|| ctx.inferred_kind(&args, param, true)), ); params.next(); } @@ -255,6 +258,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( | GenericParamDefKind::Lifetime, _, ) => { + // FIXME(effects): this should be removed // SPECIAL CASE FOR DESUGARED EFFECT PARAMS // This comes from the following example: // @@ -267,7 +271,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( // Since this is a const impl, we need to insert a host arg at the end of // `PartialEq`'s generics, but this errors since `Rhs` isn't specified. // To work around this, we infer all arguments until we reach the host param. - args.push(ctx.inferred_kind(Some(&args), param, infer_args)); + args.push(ctx.inferred_kind(&args, param, infer_args)); params.next(); } (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _) @@ -281,7 +285,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( GenericParamDefKind::Const { .. }, _, ) => { - args.push(ctx.provided_kind(param, arg)); + args.push(ctx.provided_kind(&args, param, arg)); args_iter.next(); params.next(); } @@ -292,7 +296,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( ) => { // We expected a lifetime argument, but got a type or const // argument. That means we're inferring the lifetimes. - args.push(ctx.inferred_kind(None, param, infer_args)); + args.push(ctx.inferred_kind(&args, param, infer_args)); force_infer_lt = Some((arg, param)); params.next(); } @@ -324,7 +328,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( param_types_present.dedup(); generic_arg_mismatch_err( - tcx, + cx, arg, param, !args_iter.clone().is_sorted_by_key(|arg| arg.to_ord()), @@ -379,7 +383,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( assert_eq!(kind, "lifetime"); let (provided_arg, param) = force_infer_lt.expect("lifetimes ought to have been inferred"); - generic_arg_mismatch_err(tcx, provided_arg, param, false, None); + generic_arg_mismatch_err(cx, provided_arg, param, false, None); } break; @@ -388,7 +392,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( (None, Some(¶m)) => { // If there are fewer arguments than parameters, it means // we're inferring the remaining arguments. - args.push(ctx.inferred_kind(Some(&args), param, infer_args)); + args.push(ctx.inferred_kind(&args, param, infer_args)); params.next(); } @@ -403,7 +407,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( /// Checks that the correct number of generic arguments have been provided. /// Used specifically for function calls. pub fn check_generic_arg_count_for_call( - tcx: TyCtxt<'_>, + cx: &dyn HirTyLowerer<'_>, def_id: DefId, generics: &ty::Generics, seg: &hir::PathSegment<'_>, @@ -414,14 +418,14 @@ pub fn check_generic_arg_count_for_call( IsMethodCall::No => GenericArgPosition::Value, }; let has_self = generics.parent.is_none() && generics.has_self; - check_generic_arg_count(tcx, def_id, seg, generics, gen_pos, has_self) + check_generic_arg_count(cx, def_id, seg, generics, gen_pos, has_self) } /// Checks that the correct number of generic arguments have been provided. /// This is used both for datatypes and function calls. -#[instrument(skip(tcx, gen_pos), level = "debug")] +#[instrument(skip(cx, gen_pos), level = "debug")] pub(crate) fn check_generic_arg_count( - tcx: TyCtxt<'_>, + cx: &dyn HirTyLowerer<'_>, def_id: DefId, seg: &hir::PathSegment<'_>, gen_params: &ty::Generics, @@ -444,7 +448,7 @@ pub(crate) fn check_generic_arg_count( .own_params .iter() .filter(|param| { - matches!(param.kind, ty::GenericParamDefKind::Const { is_host_effect: true, .. }) + matches!(param.kind, ty::GenericParamDefKind::Const { synthetic: true, .. }) }) .count(); let named_const_param_count = param_counts.consts - synth_const_param_count; @@ -452,13 +456,13 @@ pub(crate) fn check_generic_arg_count( (gen_pos != GenericArgPosition::Type || seg.infer_args) && !gen_args.has_lifetime_params(); if gen_pos != GenericArgPosition::Type - && let Some(b) = gen_args.bindings.first() + && let Some(c) = gen_args.constraints.first() { - prohibit_assoc_item_binding(tcx, b, None); + prohibit_assoc_item_constraint(cx, c, None); } let explicit_late_bound = - prohibit_explicit_late_bound_lifetimes(tcx, gen_params, gen_args, gen_pos); + prohibit_explicit_late_bound_lifetimes(cx, gen_params, gen_args, gen_pos); let mut invalid_args = vec![]; @@ -474,16 +478,9 @@ pub(crate) fn check_generic_arg_count( return Ok(()); } - if provided_args > max_expected_args { - invalid_args.extend( - gen_args.args[max_expected_args..provided_args].iter().map(|arg| arg.span()), - ); - }; + invalid_args.extend(min_expected_args..provided_args); let gen_args_info = if provided_args > min_expected_args { - invalid_args.extend( - gen_args.args[min_expected_args..provided_args].iter().map(|arg| arg.span()), - ); let num_redundant_args = provided_args - min_expected_args; GenericArgsInfo::ExcessLifetimes { num_redundant_args } } else { @@ -491,17 +488,15 @@ pub(crate) fn check_generic_arg_count( GenericArgsInfo::MissingLifetimes { num_missing_args } }; - let reported = WrongNumberOfGenericArgs::new( - tcx, + let reported = cx.dcx().emit_err(WrongNumberOfGenericArgs::new( + cx.tcx(), gen_args_info, seg, gen_params, has_self as usize, gen_args, def_id, - ) - .diagnostic() - .emit(); + )); Err(reported) }; @@ -537,12 +532,9 @@ pub(crate) fn check_generic_arg_count( let num_default_params = expected_max - expected_min; + let mut all_params_are_binded = false; let gen_args_info = if provided > expected_max { - invalid_args.extend( - gen_args.args[args_offset + expected_max..args_offset + provided] - .iter() - .map(|arg| arg.span()), - ); + invalid_args.extend((expected_max..provided).map(|i| i + args_offset)); let num_redundant_args = provided - expected_max; // Provide extra note if synthetic arguments like `impl Trait` are specified. @@ -557,6 +549,20 @@ pub(crate) fn check_generic_arg_count( } else { let num_missing_args = expected_max - provided; + let constraint_names: Vec<_> = + gen_args.constraints.iter().map(|b| b.ident.name).collect(); + let param_names: Vec<_> = gen_params + .own_params + .iter() + .filter(|param| !has_self || param.index != 0) // Assumes `Self` will always be the first parameter + .map(|param| param.name) + .collect(); + if constraint_names == param_names { + // We set this to true and delay emitting `WrongNumberOfGenericArgs` + // to provide a succinct error for cases like issue #113073 + all_params_are_binded = true; + }; + GenericArgsInfo::MissingTypesOrConsts { num_missing_args, num_default_params, @@ -566,17 +572,19 @@ pub(crate) fn check_generic_arg_count( debug!(?gen_args_info); - let reported = WrongNumberOfGenericArgs::new( - tcx, - gen_args_info, - seg, - gen_params, - params_offset, - gen_args, - def_id, - ) - .diagnostic() - .emit_unless(gen_args.has_err()); + let reported = gen_args.has_err().unwrap_or_else(|| { + cx.dcx() + .create_err(WrongNumberOfGenericArgs::new( + cx.tcx(), + gen_args_info, + seg, + gen_params, + params_offset, + gen_args, + def_id, + )) + .emit_unless(all_params_are_binded) + }); Err(reported) }; @@ -608,14 +616,14 @@ pub(crate) fn check_generic_arg_count( explicit_late_bound, correct: lifetimes_correct .and(args_correct) - .map_err(|reported| GenericArgCountMismatch { reported: Some(reported), invalid_args }), + .map_err(|reported| GenericArgCountMismatch { reported, invalid_args }), } } /// Prohibits explicit lifetime arguments if late-bound lifetime parameters /// are present. This is used both for datatypes and function calls. pub(crate) fn prohibit_explicit_late_bound_lifetimes( - tcx: TyCtxt<'_>, + cx: &dyn HirTyLowerer<'_>, def: &ty::Generics, args: &hir::GenericArgs<'_>, position: GenericArgPosition, @@ -636,18 +644,19 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes( if position == GenericArgPosition::Value && args.num_lifetime_params() != param_counts.lifetimes { - struct_span_code_err!(tcx.dcx(), span, E0794, "{}", msg) + struct_span_code_err!(cx.dcx(), span, E0794, "{}", msg) .with_span_note(span_late, note) .emit(); } else { let mut multispan = MultiSpan::from_span(span); multispan.push_span_label(span_late, note); - tcx.node_span_lint( + cx.tcx().node_span_lint( LATE_BOUND_LIFETIME_ARGUMENTS, args.args[0].hir_id(), multispan, - msg, - |_| {}, + |lint| { + lint.primary_message(msg); + }, ); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index d9d36f5299b..29c71c3fa50 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -4,7 +4,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability}; use rustc_span::Span; -use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName; +use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName; use super::HirTyLowerer; @@ -60,7 +60,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let msg = "trait objects must include the `dyn` keyword"; let label = "add `dyn` keyword before this trait"; let mut diag = - rustc_errors::struct_span_code_err!(tcx.dcx(), self_ty.span, E0782, "{}", msg); + rustc_errors::struct_span_code_err!(self.dcx(), self_ty.span, E0782, "{}", msg); if self_ty.span.can_be_used_for_suggestions() && !self.maybe_suggest_impl_trait(self_ty, &mut diag) { @@ -72,8 +72,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.maybe_suggest_assoc_ty_bound(self_ty, &mut diag); diag.stash(self_ty.span, StashKey::TraitMissingMethod); } else { - let msg = "trait objects without an explicit `dyn` are deprecated"; - tcx.node_span_lint(BARE_TRAIT_OBJECTS, self_ty.hir_id, self_ty.span, msg, |lint| { + tcx.node_span_lint(BARE_TRAIT_OBJECTS, self_ty.hir_id, self_ty.span, |lint| { + lint.primary_message("trait objects without an explicit `dyn` are deprecated"); if self_ty.span.can_be_used_for_suggestions() { lint.multipart_suggestion_verbose( "if this is an object-safe trait, use `dyn`", @@ -182,7 +182,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // For recursive traits, don't downgrade the error. (#119652) is_downgradable = false; } - tcx.check_is_object_safe(id) + tcx.is_object_safe(id) } _ => false, }) @@ -268,8 +268,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn maybe_suggest_assoc_ty_bound(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) { let mut parents = self.tcx().hir().parent_iter(self_ty.hir_id); - if let Some((_, hir::Node::TypeBinding(binding))) = parents.next() - && let hir::TypeBindingKind::Equality { term: hir::Term::Ty(obj_ty) } = binding.kind + if let Some((_, hir::Node::AssocItemConstraint(constraint))) = parents.next() + && let Some(obj_ty) = constraint.ty() { if let Some((_, hir::Node::TraitRef(..))) = parents.next() && let Some((_, hir::Node::Ty(ty))) = parents.next() @@ -279,10 +279,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return; } - let lo = if binding.gen_args.span_ext.is_dummy() { - binding.ident.span + let lo = if constraint.gen_args.span_ext.is_dummy() { + constraint.ident.span } else { - binding.gen_args.span_ext + constraint.gen_args.span_ext }; let hi = obj_ty.span; 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 4b1c0da6ce1..a665306f2c6 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -20,21 +20,20 @@ mod lint; mod object_safety; use crate::bounds::Bounds; -use crate::collect::HirPlaceholderCollector; use crate::errors::{AmbiguousLifetimeBound, WildPatTy}; -use crate::hir_ty_lowering::errors::{prohibit_assoc_item_binding, GenericsArgsErrExtend}; +use crate::hir_ty_lowering::errors::{prohibit_assoc_item_constraint, GenericsArgsErrExtend}; use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; use crate::middle::resolve_bound_vars as rbv; use crate::require_c_abi_if_c_variadic; use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::{ - codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, FatalError, + codes::*, struct_span_code_err, Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, + FatalError, }; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::{walk_generics, Visitor as _}; use rustc_hir::{GenericArg, GenericArgs, HirId}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; @@ -49,8 +48,9 @@ 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::{kw, Ident, Symbol}; -use rustc_span::{sym, Span, DUMMY_SP}; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi; +use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::wf::object_region_bounds; use rustc_trait_selection::traits::{self, ObligationCtxt}; @@ -82,6 +82,20 @@ pub enum PredicateFilter { SelfAndAssociatedTypeBounds, } +#[derive(Debug)] +pub enum RegionInferReason<'a> { + /// Lifetime on a trait object behind a reference. + /// This allows inferring information from the reference. + BorrowedObjectLifetimeDefault, + /// A trait object's lifetime. + ObjectLifetimeDefault, + /// Generic lifetime parameter + Param(&'a ty::GenericParamDef), + RegionPredicate, + Reference, + OutlivesBound, +} + /// A context which can lower type-system entities from the [HIR][hir] to /// the [`rustc_middle::ty`] representation. /// @@ -89,26 +103,19 @@ pub enum PredicateFilter { pub trait HirTyLowerer<'tcx> { fn tcx(&self) -> TyCtxt<'tcx>; - /// Returns the [`DefId`] of the overarching item whose constituents get lowered. - fn item_def_id(&self) -> DefId; + fn dcx(&self) -> DiagCtxtHandle<'_>; - /// Returns `true` if the current context allows the use of inference variables. - fn allow_infer(&self) -> bool; + /// Returns the [`LocalDefId`] of the overarching item whose constituents get lowered. + fn item_def_id(&self) -> LocalDefId; /// Returns the region to use when a lifetime is omitted (and not elided). - fn re_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) - -> Option<ty::Region<'tcx>>; + fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx>; /// Returns the type to use when a type is omitted. fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>; /// Returns the const to use when a const is omitted. - fn ct_infer( - &self, - ty: Ty<'tcx>, - param: Option<&ty::GenericParamDef>, - span: Span, - ) -> Const<'tcx>; + fn ct_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx>; /// Probe bounds in scope where the bounded type coincides with the given type parameter. /// @@ -151,6 +158,14 @@ pub trait HirTyLowerer<'tcx> { poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Ty<'tcx>; + fn lower_fn_sig( + &self, + decl: &hir::FnDecl<'tcx>, + generics: Option<&hir::Generics<'_>>, + hir_id: HirId, + hir_ty: Option<&hir::Ty<'_>>, + ) -> (Vec<Ty<'tcx>>, Ty<'tcx>); + /// Returns `AdtDef` if `ty` is an ADT. /// /// Note that `ty` might be a alias type that needs normalization. @@ -165,12 +180,6 @@ pub trait HirTyLowerer<'tcx> { /// The inference context of the lowering context if applicable. fn infcx(&self) -> Option<&InferCtxt<'tcx>>; - /// Taint the context with errors. - /// - /// Invoke this when you encounter an error from some prior pass like name resolution. - /// This is used to help suppress derived errors typeck might otherwise report. - fn set_tainted_by_errors(&self, e: ErrorGuaranteed); - /// Convenience method for coercing the lowering context into a trait object type. /// /// Most lowering routines are defined on the trait object type directly @@ -215,12 +224,11 @@ pub(crate) enum GenericArgPosition { /// A marker denoting that the generic arguments that were /// provided did not match the respective generic parameters. -#[derive(Clone, Default, Debug)] +#[derive(Clone, Debug)] pub struct GenericArgCountMismatch { - /// Indicates whether a fatal error was reported (`Some`), or just a lint (`None`). - pub reported: Option<ErrorGuaranteed>, - /// A list of spans of arguments provided that were not valid. - pub invalid_args: Vec<Span>, + pub reported: ErrorGuaranteed, + /// A list of indices of arguments provided that were not valid. + pub invalid_args: Vec<usize>, } /// Decorates the result of a generic argument count mismatch @@ -240,13 +248,14 @@ pub trait GenericArgsLowerer<'a, 'tcx> { fn provided_kind( &mut self, + preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx>; fn inferred_kind( &mut self, - args: Option<&[ty::GenericArg<'tcx>]>, + preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, infer_args: bool, ) -> ty::GenericArg<'tcx>; @@ -258,7 +267,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { pub fn lower_lifetime( &self, lifetime: &hir::Lifetime, - def: Option<&ty::GenericParamDef>, + reason: RegionInferReason<'_>, ) -> ty::Region<'tcx> { let tcx = self.tcx(); let lifetime_name = |def_id| tcx.hir().name(tcx.local_def_id_to_hir_id(def_id)); @@ -280,7 +289,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local()); let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id]; - ty::Region::new_early_param(tcx, ty::EarlyParamRegion { def_id, index, name }) + ty::Region::new_early_param(tcx, ty::EarlyParamRegion { index, name }) } Some(rbv::ResolvedArg::Free(scope, id)) => { @@ -292,21 +301,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Some(rbv::ResolvedArg::Error(guar)) => ty::Region::new_error(tcx, guar), - None => { - self.re_infer(def, lifetime.ident.span).unwrap_or_else(|| { - debug!(?lifetime, "unelided lifetime in signature"); - - // This indicates an illegal lifetime - // elision. `resolve_lifetime` should have - // reported an error in this case -- but if - // not, let's error out. - ty::Region::new_error_with_message( - tcx, - lifetime.ident.span, - "unelided lifetime in signature", - ) - }) - } + None => self.re_infer(lifetime.ident.span, reason), } } @@ -324,8 +319,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { None, ty::BoundConstness::NotConst, ); - if let Some(b) = item_segment.args().bindings.first() { - prohibit_assoc_item_binding(self.tcx(), b, Some((def_id, item_segment, span))); + if let Some(c) = item_segment.args().constraints.first() { + prohibit_assoc_item_constraint(self, c, Some((def_id, item_segment, span))); } args } @@ -335,7 +330,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// If this is a trait reference, you also need to pass the self type `self_ty`. /// The lowering process may involve applying defaulted type parameters. /// - /// Associated item bindings are not handled here! + /// Associated item constraints are not handled here! They are either lowered via + /// `lower_assoc_item_constraint` or rejected via `prohibit_assoc_item_constraint`. /// /// ### Example /// @@ -349,7 +345,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// which will have been resolved to a `def_id` /// 3. The `generic_args` contains info on the `<...>` contents. The `usize` type /// parameters are returned in the `GenericArgsRef` - /// 4. Associated type bindings like `Output = u32` are contained in `generic_args.bindings`. + /// 4. Associated item constraints like `Output = u32` are contained in `generic_args.constraints`. /// /// Note that the type listing given here is *exactly* what the user provided. /// @@ -395,7 +391,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } let mut arg_count = check_generic_arg_count( - tcx, + self, def_id, segment, generics, @@ -403,16 +399,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self_ty.is_some(), ); - if let Err(err) = &arg_count.correct - && let Some(reported) = err.reported - { - self.set_tainted_by_errors(reported); - } - // Skip processing if type has no generic parameters. // Traits always have `Self` as a generic parameter, which means they will not return early - // here and so associated type bindings will be handled regardless of whether there are any - // non-`Self` generic parameters. + // here and so associated item constraints will be handled regardless of whether there are + // any non-`Self` generic parameters. if generics.is_own_empty() { return (tcx.mk_args(parent_args), arg_count); } @@ -422,8 +412,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { def_id: DefId, generic_args: &'a GenericArgs<'tcx>, span: Span, - inferred_params: Vec<Span>, infer_args: bool, + incorrect_args: &'a Result<(), GenericArgCountMismatch>, } impl<'a, 'tcx> GenericArgsLowerer<'a, 'tcx> for GenericArgsCtxt<'a, 'tcx> { @@ -438,12 +428,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn provided_kind( &mut self, + _preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { let tcx = self.lowerer.tcx(); - let mut handle_ty_args = |has_default, ty: &hir::Ty<'tcx>| { + if let Err(incorrect) = self.incorrect_args { + if incorrect.invalid_args.contains(&(param.index as usize)) { + return param.to_error(tcx); + } + } + + let handle_ty_args = |has_default, ty: &hir::Ty<'tcx>| { if has_default { tcx.check_optional_stability( param.def_id, @@ -460,17 +457,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }, ); } - if let (hir::TyKind::Infer, false) = (&ty.kind, self.lowerer.allow_infer()) { - self.inferred_params.push(ty.span); - Ty::new_misc_error(tcx).into() - } else { - self.lowerer.lower_ty(ty).into() - } + self.lowerer.lower_ty(ty).into() }; match (¶m.kind, arg) { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { - self.lowerer.lower_lifetime(lt, Some(param)).into() + self.lowerer.lower_lifetime(lt, RegionInferReason::Param(param)).into() } (&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => { handle_ty_args(has_default, ty) @@ -484,17 +476,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::Const::from_anon_const(tcx, did).into() } (&GenericParamDefKind::Const { .. }, hir::GenericArg::Infer(inf)) => { - let ty = tcx - .at(self.span) - .type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"); - if self.lowerer.allow_infer() { - self.lowerer.ct_infer(ty, Some(param), inf.span).into() - } else { - self.inferred_params.push(inf.span); - ty::Const::new_misc_error(tcx, ty).into() - } + self.lowerer.ct_infer(Some(param), inf.span).into() } (kind, arg) => span_bug!( self.span, @@ -505,38 +487,37 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn inferred_kind( &mut self, - args: Option<&[ty::GenericArg<'tcx>]>, + preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, infer_args: bool, ) -> ty::GenericArg<'tcx> { let tcx = self.lowerer.tcx(); + + if let Err(incorrect) = self.incorrect_args { + if incorrect.invalid_args.contains(&(param.index as usize)) { + return param.to_error(tcx); + } + } match param.kind { - GenericParamDefKind::Lifetime => self - .lowerer - .re_infer(Some(param), self.span) - .unwrap_or_else(|| { - debug!(?param, "unelided lifetime in signature"); - - // This indicates an illegal lifetime in a non-assoc-trait position - ty::Region::new_error_with_message( - tcx, - self.span, - "unelided lifetime in signature", - ) - }) - .into(), + GenericParamDefKind::Lifetime => { + self.lowerer.re_infer(self.span, RegionInferReason::Param(param)).into() + } GenericParamDefKind::Type { has_default, .. } => { if !infer_args && has_default { // No type parameter provided, but a default exists. - let args = args.unwrap(); - if args.iter().any(|arg| match arg.unpack() { - GenericArgKind::Type(ty) => ty.references_error(), - _ => false, - }) { + if let Some(prev) = + preceding_args.iter().find_map(|arg| match arg.unpack() { + GenericArgKind::Type(ty) => ty.error_reported().err(), + _ => None, + }) + { // Avoid ICE #86756 when type error recovery goes awry. - return Ty::new_misc_error(tcx).into(); + return Ty::new_error(tcx, prev).into(); } - tcx.at(self.span).type_of(param.def_id).instantiate(tcx, args).into() + tcx.at(self.span) + .type_of(param.def_id) + .instantiate(tcx, preceding_args) + .into() } else if infer_args { self.lowerer.ty_infer(Some(param), self.span).into() } else { @@ -551,48 +532,46 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .no_bound_vars() .expect("const parameter types cannot be generic"); if let Err(guar) = ty.error_reported() { - return ty::Const::new_error(tcx, guar, ty).into(); + return ty::Const::new_error(tcx, guar).into(); } // FIXME(effects) see if we should special case effect params here if !infer_args && has_default { tcx.const_param_default(param.def_id) - .instantiate(tcx, args.unwrap()) + .instantiate(tcx, preceding_args) .into() } else { if infer_args { - self.lowerer.ct_infer(ty, Some(param), self.span).into() + self.lowerer.ct_infer(Some(param), self.span).into() } else { // We've already errored above about the mismatch. - ty::Const::new_misc_error(tcx, ty).into() + ty::Const::new_misc_error(tcx).into() } } } } } } + if let ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst = constness + && generics.has_self + && !tcx.is_const_trait(def_id) + { + let reported = self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait { + span, + modifier: constness.as_str(), + }); + arg_count.correct = Err(GenericArgCountMismatch { reported, invalid_args: vec![] }); + } let mut args_ctx = GenericArgsCtxt { lowerer: self, def_id, span, generic_args: segment.args(), - inferred_params: vec![], infer_args: segment.infer_args, + incorrect_args: &arg_count.correct, }; - if let ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst = constness - && generics.has_self - && !tcx.has_attr(def_id, sym::const_trait) - { - let e = tcx.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait { - span, - modifier: constness.as_str(), - }); - self.set_tainted_by_errors(e); - arg_count.correct = - Err(GenericArgCountMismatch { reported: Some(e), invalid_args: vec![] }); - } let args = lower_generic_args( - tcx, + self, def_id, parent_args, self_ty.is_some(), @@ -621,8 +600,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { None, ty::BoundConstness::NotConst, ); - if let Some(b) = item_segment.args().bindings.first() { - prohibit_assoc_item_binding(self.tcx(), b, Some((item_def_id, item_segment, span))); + if let Some(c) = item_segment.args().constraints.first() { + prohibit_assoc_item_constraint(self, c, Some((item_def_id, item_segment, span))); } args } @@ -654,13 +633,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// /// *Polymorphic* in the sense that it may bind late-bound vars. /// - /// This may generate auxiliary bounds if the trait reference contains associated item bindings. + /// This may generate auxiliary bounds iff the trait reference contains associated item constraints. /// /// ### Example /// /// Given the trait ref `Iterator<Item = u32>` and the self type `Ty`, this will add the /// - /// 1. *trait predicate* `<Ty as Iterator>` (known as `Foo: Iterator` in surface syntax) and the + /// 1. *trait predicate* `<Ty as Iterator>` (known as `Ty: Iterator` in the surface syntax) and the /// 2. *projection predicate* `<Ty as Iterator>::Item = u32` /// /// to `bounds`. @@ -707,34 +686,41 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { debug!(?bound_vars); let poly_trait_ref = ty::Binder::bind_with_vars( - ty::TraitRef::new(tcx, trait_def_id, generic_args), + ty::TraitRef::new_from_args(tcx, trait_def_id, generic_args), bound_vars, ); debug!(?poly_trait_ref); - bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity); + bounds.push_trait_bound( + tcx, + self.item_def_id().to_def_id(), + poly_trait_ref, + span, + polarity, + constness, + ); - let mut dup_bindings = FxIndexMap::default(); - for binding in trait_segment.args().bindings { - // Don't register additional associated type bounds for negative bounds, - // since we should have emitten an error for them earlier, and they will - // not be well-formed! + let mut dup_constraints = FxIndexMap::default(); + for constraint in trait_segment.args().constraints { + // Don't register any associated item constraints for negative bounds, + // since we should have emitted an error for them earlier, and they + // would not be well-formed! if polarity != ty::PredicatePolarity::Positive { assert!( - self.tcx().dcx().has_errors().is_some(), - "negative trait bounds should not have bindings", + self.dcx().has_errors().is_some(), + "negative trait bounds should not have assoc item constraints", ); continue; } // Specify type to assert that error was already reported in `Err` case. - let _: Result<_, ErrorGuaranteed> = self.lower_assoc_item_binding( + let _: Result<_, ErrorGuaranteed> = self.lower_assoc_item_constraint( trait_ref.hir_ref_id, poly_trait_ref, - binding, + constraint, bounds, - &mut dup_bindings, - binding.span, + &mut dup_constraints, + constraint.span, only_self_bounds, ); // Okay to ignore `Err` because of `ErrorGuaranteed` (see above). @@ -766,10 +752,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Some(self_ty), constness, ); - if let Some(b) = trait_segment.args().bindings.first() { - prohibit_assoc_item_binding(self.tcx(), b, Some((trait_def_id, trait_segment, span))); + if let Some(c) = trait_segment.args().constraints.first() { + prohibit_assoc_item_constraint(self, c, Some((trait_def_id, trait_segment, span))); } - ty::TraitRef::new(self.tcx(), trait_def_id, generic_args) + ty::TraitRef::new_from_args(self.tcx(), trait_def_id, generic_args) } fn probe_trait_that_defines_assoc_item( @@ -799,7 +785,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // 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 = ty::AliasTy::new(tcx, did, args); + let alias_ty = ty::AliasTy::new_from_args(tcx, did, args); Ty::new_alias(tcx, ty::Weak, alias_ty) } else { tcx.at(span).type_of(did).instantiate(tcx, args) @@ -849,7 +835,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// /// This fails if there is no such bound in the list of candidates or if there are multiple /// candidates in which case it reports ambiguity. - #[instrument(level = "debug", skip(self, all_candidates, ty_param_name, binding), ret)] + #[instrument(level = "debug", skip(self, all_candidates, ty_param_name, constraint), ret)] fn probe_single_bound_for_assoc_item<I>( &self, all_candidates: impl Fn() -> I, @@ -858,7 +844,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { assoc_kind: ty::AssocKind, assoc_name: Ident, span: Span, - binding: Option<&hir::TypeBinding<'tcx>>, + constraint: Option<&hir::AssocItemConstraint<'tcx>>, ) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> where I: Iterator<Item = ty::PolyTraitRef<'tcx>>, @@ -877,9 +863,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { assoc_kind, assoc_name, span, - binding, + constraint, ); - self.set_tainted_by_errors(reported); return Err(reported); }; debug!(?bound); @@ -889,7 +874,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let assoc_kind_str = assoc_kind_str(assoc_kind); let ty_param_name = &ty_param_name.to_string(); - let mut err = tcx.dcx().create_err(crate::errors::AmbiguousAssocItem { + let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem { span, assoc_kind: assoc_kind_str, assoc_name, @@ -897,8 +882,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }); // Provide a more specific error code index entry for equality bindings. err.code( - if let Some(binding) = binding - && let hir::TypeBindingKind::Equality { .. } = binding.kind + if let Some(constraint) = constraint + && let hir::AssocItemConstraintKind::Equality { .. } = constraint.kind { E0222 } else { @@ -906,7 +891,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }, ); - // FIXME(#97583): Resugar equality bounds to type/const bindings. + // FIXME(#97583): Print associated item bindings properly (i.e., not as equality predicates!). // FIXME: Turn this into a structured, translateable & more actionable suggestion. let mut where_bounds = vec![]; for bound in [bound, bound2].into_iter().chain(matching_candidates) { @@ -921,9 +906,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bound_span, format!("ambiguous `{assoc_name}` from `{}`", bound.print_trait_sugared(),), ); - if let Some(binding) = binding { - match binding.kind { - hir::TypeBindingKind::Equality { term } => { + if let Some(constraint) = constraint { + match constraint.kind { + hir::AssocItemConstraintKind::Equality { term } => { let term: ty::Term<'_> = match term { hir::Term::Ty(ty) => self.lower_ty(ty).into(), hir::Term::Const(ct) => { @@ -937,7 +922,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { )); } // FIXME: Provide a suggestion. - hir::TypeBindingKind::Constraint { bounds: _ } => {} + hir::AssocItemConstraintKind::Bound { bounds: _ } => {} } } else { err.span_suggestion_verbose( @@ -962,7 +947,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { )); } let reported = err.emit(); - self.set_tainted_by_errors(reported); if !where_bounds.is_empty() { return Err(reported); } @@ -1061,7 +1045,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // trait reference. let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else { // A cycle error occurred, most likely. - tcx.dcx().span_bug(span, "expected cycle error"); + self.dcx().span_bug(span, "expected cycle error"); }; self.probe_single_bound_for_assoc_item( @@ -1091,10 +1075,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let reported = if variant_resolution.is_some() { // Variant in type position let msg = format!("expected type, found variant `{assoc_ident}`"); - tcx.dcx().span_err(span, msg) + self.dcx().span_err(span, msg) } else if qself_ty.is_enum() { let mut err = struct_span_code_err!( - tcx.dcx(), + self.dcx(), assoc_ident.span, E0599, "no variant named `{}` found for enum `{}`", @@ -1135,7 +1119,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() { // `<impl Trait as OtherTrait>::Assoc` makes no sense. struct_span_code_err!( - tcx.dcx(), + self.dcx(), tcx.def_span(alias_ty.def_id), E0667, "`impl Trait` is not allowed in path parameters" @@ -1155,45 +1139,41 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { assoc_ident.name, ) }; - self.set_tainted_by_errors(reported); return Err(reported); } }; let trait_did = bound.def_id(); - let assoc_ty_did = self.probe_assoc_ty(assoc_ident, hir_ref_id, span, trait_did).unwrap(); - let ty = self.lower_assoc_ty(span, assoc_ty_did, assoc_segment, bound); + let assoc_ty = self + .probe_assoc_item(assoc_ident, ty::AssocKind::Type, hir_ref_id, span, trait_did) + .expect("failed to find associated type"); + let ty = self.lower_assoc_ty(span, assoc_ty.def_id, assoc_segment, bound); if let Some(variant_def_id) = variant_resolution { - tcx.node_span_lint( - AMBIGUOUS_ASSOCIATED_ITEMS, - hir_ref_id, - span, - "ambiguous associated item", - |lint| { - let mut could_refer_to = |kind: DefKind, def_id, also| { - let note_msg = format!( - "`{}` could{} refer to the {} defined here", - assoc_ident, - also, - tcx.def_kind_descr(kind, def_id) - ); - lint.span_note(tcx.def_span(def_id), note_msg); - }; + tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| { + lint.primary_message("ambiguous associated item"); + let mut could_refer_to = |kind: DefKind, def_id, also| { + let note_msg = format!( + "`{}` could{} refer to the {} defined here", + assoc_ident, + also, + tcx.def_kind_descr(kind, def_id) + ); + lint.span_note(tcx.def_span(def_id), note_msg); + }; - could_refer_to(DefKind::Variant, variant_def_id, ""); - could_refer_to(DefKind::AssocTy, assoc_ty_did, " also"); + could_refer_to(DefKind::Variant, variant_def_id, ""); + could_refer_to(DefKind::AssocTy, assoc_ty.def_id, " also"); - lint.span_suggestion( - span, - "use fully-qualified syntax", - format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident), - Applicability::MachineApplicable, - ); - }, - ); + lint.span_suggestion( + span, + "use fully-qualified syntax", + format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident), + Applicability::MachineApplicable, + ); + }); } - Ok((ty, DefKind::AssocTy, assoc_ty_did)) + Ok((ty, DefKind::AssocTy, assoc_ty.def_id)) } fn probe_inherent_assoc_ty( @@ -1220,7 +1200,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let candidates: Vec<_> = tcx .inherent_impls(adt_did)? .iter() - .filter_map(|&impl_| Some((impl_, self.probe_assoc_ty_unchecked(name, block, impl_)?))) + .filter_map(|&impl_| { + let (item, scope) = + self.probe_assoc_item_unchecked(name, ty::AssocKind::Type, block, impl_)?; + Some((impl_, (item.def_id, scope))) + }) .collect(); if candidates.is_empty() { @@ -1264,7 +1248,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }, )?; - self.check_assoc_ty(assoc_item, name, def_scope, block, span); + self.check_assoc_item(assoc_item, name, def_scope, block, span); // FIXME(fmease): Currently creating throwaway `parent_args` to please // `lower_generic_args_of_assoc_item`. Modify the latter instead (or sth. similar) to @@ -1276,7 +1260,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .chain(args.into_iter().skip(parent_args.len())), ); - let ty = Ty::new_alias(tcx, ty::Inherent, ty::AliasTy::new(tcx, assoc_item, args)); + let ty = + Ty::new_alias(tcx, ty::Inherent, ty::AliasTy::new_from_args(tcx, assoc_item, args)); Ok(Some((ty, assoc_item))) } @@ -1298,7 +1283,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .copied() .filter(|&(impl_, _)| { infcx.probe(|_| { - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); let self_ty = ocx.normalize(&ObligationCause::dummy(), param_env, self_ty); let impl_args = infcx.fresh_args_for_item(span, impl_); @@ -1351,50 +1336,68 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - fn probe_assoc_ty(&self, name: Ident, block: HirId, span: Span, scope: DefId) -> Option<DefId> { - let (item, def_scope) = self.probe_assoc_ty_unchecked(name, block, scope)?; - self.check_assoc_ty(item, name, def_scope, block, span); + /// Given name and kind search for the assoc item in the provided scope and check if it's accessible[^1]. + /// + /// [^1]: I.e., accessible in the provided scope wrt. visibility and stability. + fn probe_assoc_item( + &self, + ident: Ident, + kind: ty::AssocKind, + block: HirId, + span: Span, + scope: DefId, + ) -> Option<ty::AssocItem> { + let (item, scope) = self.probe_assoc_item_unchecked(ident, kind, block, scope)?; + self.check_assoc_item(item.def_id, ident, scope, block, span); Some(item) } - fn probe_assoc_ty_unchecked( + /// Given name and kind search for the assoc item in the provided scope + /// *without* checking if it's accessible[^1]. + /// + /// [^1]: I.e., accessible in the provided scope wrt. visibility and stability. + fn probe_assoc_item_unchecked( &self, - name: Ident, + ident: Ident, + kind: ty::AssocKind, block: HirId, scope: DefId, - ) -> Option<(DefId, DefId)> { + ) -> Option<(ty::AssocItem, /*scope*/ DefId)> { let tcx = self.tcx(); - let (ident, def_scope) = tcx.adjust_ident_and_get_scope(name, scope, block); + let (ident, def_scope) = tcx.adjust_ident_and_get_scope(ident, scope, block); // We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()` // instead of calling `filter_by_name_and_kind` which would needlessly normalize the // `ident` again and again. - let item = tcx.associated_items(scope).in_definition_order().find(|i| { - i.kind.namespace() == Namespace::TypeNS - && i.ident(tcx).normalize_to_macros_2_0() == ident - })?; + let item = tcx + .associated_items(scope) + .filter_by_name_unhygienic(ident.name) + .find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == ident)?; - Some((item.def_id, def_scope)) + Some((*item, def_scope)) } - fn check_assoc_ty(&self, item: DefId, name: Ident, def_scope: DefId, block: HirId, span: Span) { + /// Check if the given assoc item is accessible in the provided scope wrt. visibility and stability. + fn check_assoc_item( + &self, + item_def_id: DefId, + ident: Ident, + scope: DefId, + block: HirId, + span: Span, + ) { let tcx = self.tcx(); - let kind = DefKind::AssocTy; - - if !tcx.visibility(item).is_accessible_from(def_scope, tcx) { - let kind = tcx.def_kind_descr(kind, item); - let msg = format!("{kind} `{name}` is private"); - let def_span = tcx.def_span(item); - let reported = tcx - .dcx() - .struct_span_err(span, msg) - .with_code(E0624) - .with_span_label(span, format!("private {kind}")) - .with_span_label(def_span, format!("{kind} defined here")) - .emit(); - self.set_tainted_by_errors(reported); + + if !tcx.visibility(item_def_id).is_accessible_from(scope, tcx) { + self.dcx().emit_err(crate::errors::AssocItemIsPrivate { + span, + kind: tcx.def_descr(item_def_id), + name: ident, + defined_here_label: tcx.def_span(item_def_id), + }); } - tcx.check_stability(item, Some(block), span, None); + + tcx.check_stability(item_def_id, Some(block), span, None); } fn probe_traits_that_match_assoc_ty( @@ -1477,16 +1480,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let def_id = self.item_def_id(); debug!(item_def_id = ?def_id); - let parent_def_id = def_id - .as_local() - .map(|def_id| tcx.local_def_id_to_hir_id(def_id)) - .map(|hir_id| tcx.hir().get_parent_item(hir_id).to_def_id()); + // FIXME: document why/how this is different from `tcx.local_parent(def_id)` + let parent_def_id = + tcx.hir().get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id(); debug!(?parent_def_id); // If the trait in segment is the same as the trait defining the item, // use the `<Self as ..>` syntax in the error. - let is_part_of_self_trait_constraints = def_id == trait_def_id; - let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id); + let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id; + let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id; let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait { vec!["Self".to_string()] @@ -1525,7 +1527,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let item_args = self.lower_generic_args_of_assoc_item(span, item_def_id, item_segment, trait_ref.args); - Ty::new_projection(tcx, item_def_id, item_args) + Ty::new_projection_from_args(tcx, item_def_id, item_args) } pub fn prohibit_generic_args<'a>( @@ -1545,8 +1547,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { for segment in segments { // Only emit the first error to avoid overloading the user with error messages. - if let Some(b) = segment.args().bindings.first() { - return Err(prohibit_assoc_item_binding(self.tcx(), b, None)); + if let Some(c) = segment.args().constraints.first() { + return Err(prohibit_assoc_item_constraint(self, c, None)); } } @@ -1806,7 +1808,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // `AlwaysApplicable` impl needs a `T: ?Sized` bound for // this to compile if we were to normalize here. if forbid_generic && ty.has_param() { - let mut err = tcx.dcx().struct_span_err( + let mut err = self.dcx().struct_span_err( path.span, "generic `Self` types are currently not permitted in anonymous constants", ); @@ -1818,7 +1820,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.span_note(impl_.self_ty.span, "not a concrete type"); } let reported = err.emit(); - self.set_tainted_by_errors(reported); Ty::new_error(tcx, reported) } else { ty @@ -1830,19 +1831,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { path.segments[..path.segments.len() - 2].iter(), GenericsArgsErrExtend::None, ); - // HACK: until we support `<Type as ~const Trait>`, assume all of them are. - let constness = if tcx.has_attr(tcx.parent(def_id), sym::const_trait) { - ty::BoundConstness::ConstIfConst - } else { - ty::BoundConstness::NotConst - }; self.lower_qpath( span, opt_self_ty, def_id, &path.segments[path.segments.len() - 2], path.segments.last().unwrap(), - constness, + ty::BoundConstness::NotConst, ) } Res::PrimTy(prim_ty) => { @@ -1865,7 +1860,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .tcx() .dcx() .span_delayed_bug(path.span, "path with `Res::Err` but no error emitted"); - self.set_tainted_by_errors(e); Ty::new_error(self.tcx(), e) } Res::Def(..) => { @@ -1876,7 +1870,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); Ty::new_error( self.tcx(), - self.tcx().dcx().span_delayed_bug(span, "incorrect resolution for `Self`"), + self.dcx().span_delayed_bug(span, "incorrect resolution for `Self`"), ) } _ => span_bug!(span, "unexpected resolution: {:?}", path.res), @@ -1914,7 +1908,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// /// Early-bound const parameters get lowered to [`ty::ConstKind::Param`] /// and late-bound ones to [`ty::ConstKind::Bound`]. - pub(crate) fn lower_const_param(&self, hir_id: HirId, param_ty: Ty<'tcx>) -> Const<'tcx> { + pub(crate) fn lower_const_param(&self, hir_id: HirId) -> Const<'tcx> { let tcx = self.tcx(); match tcx.named_bound_var(hir_id) { Some(rbv::ResolvedArg::EarlyBound(def_id)) => { @@ -1924,12 +1918,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { 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) + ty::Const::new_param(tcx, ty::ParamConst::new(index, name)) } Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { - ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index), param_ty) + ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index)) } - Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar, param_ty), + Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar), arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", hir_id), } } @@ -1949,7 +1943,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let sig_span = self.tcx().def_span(sig_id); let mut try_emit = |descr| { if emit { - self.tcx().dcx().emit_err(crate::errors::NotSupportedDelegation { + self.dcx().emit_err(crate::errors::NotSupportedDelegation { span, descr, callee_span: sig_span, @@ -1967,7 +1961,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } let sig_generics = self.tcx().generics_of(sig_id); - let parent = self.tcx().parent(self.item_def_id()); + let parent = self.tcx().local_parent(self.item_def_id()); let parent_generics = self.tcx().generics_of(parent); let parent_is_trait = (self.tcx().def_kind(parent) == DefKind::Trait) as usize; @@ -1999,14 +1993,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) -> Ty<'tcx> { if self.check_delegation_constraints(sig_id, span, idx == hir::InferDelegationKind::Output) { - let e = self.tcx().dcx().span_delayed_bug(span, "not supported delegation case"); - self.set_tainted_by_errors(e); + let e = self.dcx().span_delayed_bug(span, "not supported delegation case"); return Ty::new_error(self.tcx(), e); }; let sig = self.tcx().fn_sig(sig_id); let sig_generics = self.tcx().generics_of(sig_id); - let parent = self.tcx().parent(self.item_def_id()); + let parent = self.tcx().local_parent(self.item_def_id()); let parent_def_kind = self.tcx().def_kind(parent); let sig = if let DefKind::Impl { .. } = parent_def_kind @@ -2054,7 +2047,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.lower_ty(ty)), hir::TyKind::Ptr(mt) => Ty::new_ptr(tcx, self.lower_ty(mt.ty), mt.mutbl), hir::TyKind::Ref(region, mt) => { - let r = self.lower_lifetime(region, None); + let r = self.lower_lifetime(region, RegionInferReason::Reference); debug!(?r); let t = self.lower_ty_common(mt.ty, true, false); Ty::new_ref(tcx, r, t, mt.mutbl) @@ -2145,7 +2138,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } hir::TyKind::Array(ty, length) => { let length = match length { - hir::ArrayLen::Infer(inf) => self.ct_infer(tcx.types.usize, None, inf.span), + hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span), hir::ArrayLen::Body(constant) => { ty::Const::from_anon_const(tcx, constant.def_id) } @@ -2165,7 +2158,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let ty = self.lower_ty(ty); let pat_ty = match pat.kind { hir::PatKind::Wild => { - let err = tcx.dcx().emit_err(WildPatTy { span: pat.span }); + let err = self.dcx().emit_err(WildPatTy { span: pat.span }); Ty::new_error(tcx, err) } hir::PatKind::Range(start, end, include_end) => { @@ -2176,17 +2169,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } _ => (expr, None), }; - let c = match &expr.kind { + let (c, c_ty) = match &expr.kind { hir::ExprKind::Lit(lit) => { let lit_input = LitToConstInput { lit: &lit.node, ty, neg: neg.is_some() }; - match tcx.lit_to_const(lit_input) { + let ct = match tcx.lit_to_const(lit_input) { Ok(c) => c, Err(LitToConstError::Reported(err)) => { - ty::Const::new_error(tcx, err, ty) + ty::Const::new_error(tcx, err) } Err(LitToConstError::TypeError) => todo!(), - } + }; + (ct, ty) } hir::ExprKind::Path(hir::QPath::Resolved( @@ -2204,19 +2198,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .type_of(def_id) .no_bound_vars() .expect("const parameter types cannot be generic"); - self.lower_const_param(expr.hir_id, ty) + let ct = self.lower_const_param(expr.hir_id); + (ct, ty) } _ => { let err = tcx .dcx() .emit_err(crate::errors::NonConstRange { span: expr.span }); - ty::Const::new_error(tcx, err, ty) + (ty::Const::new_error(tcx, err), Ty::new_error(tcx, err)) } }; - self.record_ty(expr.hir_id, c.ty(), expr.span); + self.record_ty(expr.hir_id, c_ty, expr.span); if let Some((id, span)) = neg { - self.record_ty(id, c.ty(), span); + self.record_ty(id, c_ty, span); } c }; @@ -2283,7 +2278,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &lifetimes[i] ) }; - self.lower_lifetime(lifetime, None).into() + self.lower_lifetime(lifetime, RegionInferReason::Param(¶m)).into() } else { tcx.mk_param_from_def(param) } @@ -2291,7 +2286,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { debug!(?args); if in_trait { - Ty::new_projection(tcx, def_id, args) + Ty::new_projection_from_args(tcx, def_id, args) } else { Ty::new_opaque(tcx, def_id, args) } @@ -2322,92 +2317,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let bound_vars = tcx.late_bound_vars(hir_id); debug!(?bound_vars); - // We proactively collect all the inferred type params to emit a single error per fn def. - let mut visitor = HirPlaceholderCollector::default(); - let mut infer_replacements = vec![]; - - if let Some(generics) = generics { - walk_generics(&mut visitor, generics); - } - - let input_tys: Vec<_> = decl - .inputs - .iter() - .enumerate() - .map(|(i, a)| { - if let hir::TyKind::Infer = a.kind - && !self.allow_infer() - { - if let Some(suggested_ty) = - self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i)) - { - infer_replacements.push((a.span, suggested_ty.to_string())); - return Ty::new_error_with_message( - self.tcx(), - a.span, - suggested_ty.to_string(), - ); - } - } - - // Only visit the type looking for `_` if we didn't fix the type above - visitor.visit_ty(a); - self.lower_arg_ty(a, None) - }) - .collect(); - - let output_ty = match decl.output { - hir::FnRetTy::Return(output) => { - if let hir::TyKind::Infer = output.kind - && !self.allow_infer() - && let Some(suggested_ty) = - self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None) - { - infer_replacements.push((output.span, suggested_ty.to_string())); - Ty::new_error_with_message(self.tcx(), output.span, suggested_ty.to_string()) - } else { - visitor.visit_ty(output); - self.lower_ty(output) - } - } - hir::FnRetTy::DefaultReturn(..) => tcx.types.unit, - }; + let (input_tys, output_ty) = self.lower_fn_sig(decl, generics, hir_id, hir_ty); debug!(?output_ty); let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, safety, abi); let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars); - if !self.allow_infer() && !(visitor.0.is_empty() && infer_replacements.is_empty()) { - // We always collect the spans for placeholder types when evaluating `fn`s, but we - // only want to emit an error complaining about them if infer types (`_`) are not - // allowed. `allow_infer` gates this behavior. We check for the presence of - // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`. - - let mut diag = crate::collect::placeholder_type_error_diag( - tcx, - generics, - visitor.0, - infer_replacements.iter().map(|(s, _)| *s).collect(), - true, - hir_ty, - "function", - ); - - if !infer_replacements.is_empty() { - diag.multipart_suggestion( - format!( - "try replacing `_` with the type{} in the corresponding trait method signature", - rustc_errors::pluralize!(infer_replacements.len()), - ), - infer_replacements, - Applicability::MachineApplicable, - ); - } - - self.set_tainted_by_errors(diag.emit()); - } - // Find any late-bound regions declared in return type that do // not appear in the arguments. These are not well-formed. // @@ -2422,7 +2338,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.validate_late_bound_regions(late_bound_in_args, late_bound_in_ret, |br_name| { struct_span_code_err!( - tcx.dcx(), + self.dcx(), decl.output.span(), E0581, "return type references {}, which is not constrained by the fn input types", @@ -2437,7 +2353,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// corresponding function in the trait that the impl implements, if it exists. /// If arg_idx is Some, then it corresponds to an input type index, otherwise it /// corresponds to the return type. - fn suggest_trait_fn_ty_for_impl_fn_infer( + pub(super) fn suggest_trait_fn_ty_for_impl_fn_infer( &self, fn_hir_id: HirId, arg_idx: Option<usize>, @@ -2473,11 +2389,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } #[instrument(level = "trace", skip(self, generate_err))] - fn validate_late_bound_regions( - &self, + fn validate_late_bound_regions<'cx>( + &'cx self, constrained_regions: FxHashSet<ty::BoundRegionKind>, referenced_regions: FxHashSet<ty::BoundRegionKind>, - generate_err: impl Fn(&str) -> Diag<'tcx>, + generate_err: impl Fn(&str) -> Diag<'cx>, ) { for br in referenced_regions.difference(&constrained_regions) { let br_name = match *br { @@ -2502,7 +2418,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.note("consider introducing a named lifetime parameter"); } - self.set_tainted_by_errors(err.emit()); + err.emit(); } } @@ -2543,7 +2459,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // error. let r = derived_region_bounds[0]; if derived_region_bounds[1..].iter().any(|r1| r != *r1) { - self.set_tainted_by_errors(tcx.dcx().emit_err(AmbiguousLifetimeBound { span })); + self.dcx().emit_err(AmbiguousLifetimeBound { span }); } Some(r) } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs index 4f7a39d0250..aafadc7f9cb 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs @@ -1,5 +1,7 @@ use crate::bounds::Bounds; -use crate::hir_ty_lowering::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds}; +use crate::hir_ty_lowering::{ + GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds, RegionInferReason, +}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; @@ -11,7 +13,7 @@ use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::{self, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{DynKind, Upcast}; use rustc_span::{ErrorGuaranteed, Span}; -use rustc_trait_selection::traits::error_reporting::report_object_safety_error; +use rustc_trait_selection::error_reporting::traits::report_object_safety_error; use rustc_trait_selection::traits::{self, hir_ty_lowering_object_safety_violations}; use smallvec::{smallvec, SmallVec}; @@ -57,7 +59,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut trait_bounds = vec![]; let mut projection_bounds = vec![]; - for (pred, span) in bounds.clauses() { + for (pred, span) in bounds.clauses(tcx) { let bound_pred = pred.kind(); match bound_pred.skip_binder() { ty::ClauseKind::Trait(trait_pred) => { @@ -131,7 +133,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { tcx.associated_items(pred.def_id()) .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Type) - .filter(|item| !item.is_impl_trait_in_trait()) + .filter(|item| { + !item.is_impl_trait_in_trait() && !item.is_effects_desugaring + }) .map(|item| item.def_id), ); } @@ -141,9 +145,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // `trait_object_dummy_self`, so check for that. let references_self = match pred.skip_binder().term.unpack() { ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()), - ty::TermKind::Const(c) => { - c.ty().walk().any(|arg| arg == dummy_self.into()) - } + // FIXME(associated_const_equality): We should walk the const instead of not doing anything + ty::TermKind::Const(_) => false, }; // If the projection output contains `Self`, force the user to @@ -233,7 +236,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ty::new_misc_error(tcx).into() } else if arg.walk().any(|arg| arg == dummy_self.into()) { references_self = true; - let guar = tcx.dcx().span_delayed_bug( + let guar = self.dcx().span_delayed_bug( span, "trait object trait bounds reference `Self`", ); @@ -259,8 +262,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if references_self { let def_id = i.bottom().0.def_id(); - let reported = struct_span_code_err!( - tcx.dcx(), + struct_span_code_err!( + self.dcx(), i.bottom().1, E0038, "the {} `{}` cannot be made into an object", @@ -272,7 +275,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .error_msg(), ) .emit(); - self.set_tainted_by_errors(reported); } ty::ExistentialTraitRef { def_id: trait_ref.def_id, args } @@ -321,30 +323,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Use explicitly-specified region bound. let region_bound = if !lifetime.is_elided() { - self.lower_lifetime(lifetime, None) + self.lower_lifetime(lifetime, RegionInferReason::ObjectLifetimeDefault) } else { self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| { if tcx.named_bound_var(lifetime.hir_id).is_some() { - self.lower_lifetime(lifetime, None) + self.lower_lifetime(lifetime, RegionInferReason::ObjectLifetimeDefault) } else { - self.re_infer(None, span).unwrap_or_else(|| { - let err = struct_span_code_err!( - tcx.dcx(), - span, - E0228, - "the lifetime bound for this object type cannot be deduced \ - from context; please supply an explicit bound" - ); - let e = if borrowed { - // We will have already emitted an error E0106 complaining about a - // missing named lifetime in `&dyn Trait`, so we elide this one. - err.delay_as_bug() + self.re_infer( + span, + if borrowed { + RegionInferReason::ObjectLifetimeDefault } else { - err.emit() - }; - self.set_tainted_by_errors(e); - ty::Region::new_error(tcx, e) - }) + RegionInferReason::BorrowedObjectLifetimeDefault + }, + ) } }) }; diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 10101aa046e..13993a1992b 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -67,7 +67,7 @@ fn diagnostic_hir_wf_check<'tcx>( impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { let infcx = self.tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let tcx_ty = self.icx.lower_ty(ty); // This visitor can walk into binders, resulting in the `tcx_ty` to @@ -158,7 +158,7 @@ fn diagnostic_hir_wf_check<'tcx>( }, hir::Node::Field(field) => vec![field.ty], hir::Node::ForeignItem(ForeignItem { - kind: ForeignItemKind::Static(ty, _), .. + kind: ForeignItemKind::Static(ty, _, _), .. }) => vec![*ty], hir::Node::GenericParam(hir::GenericParam { kind: hir::GenericParamKind::Type { default: Some(ty), .. }, diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index 002be61196a..5cc1ec71757 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -86,6 +86,8 @@ fn enforce_impl_params_are_constrained( let impl_predicates = tcx.predicates_of(impl_def_id); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::instantiate_identity); + impl_trait_ref.error_reported()?; + let mut input_parameters = cgp::parameters_for_impl(tcx, impl_self_ty, impl_trait_ref); cgp::identify_constrained_generic_params( tcx, diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 6967cb4d9d0..5b8b6e98125 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -78,7 +78,7 @@ use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{GenericArg, GenericArgs, GenericArgsRef}; use rustc_span::{ErrorGuaranteed, Span}; -use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{self, translate_args_with_cause, wf, ObligationCtxt}; @@ -196,7 +196,7 @@ fn get_impl_args( impl2_node: Node, ) -> Result<(GenericArgsRef<'_>, GenericArgsRef<'_>), ErrorGuaranteed> { let infcx = &tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); let param_env = tcx.param_env(impl1_def_id); let impl1_span = tcx.def_span(impl1_def_id); let assumed_wf_types = ocx.assumed_wf_types_and_report_errors(param_env, impl1_def_id)?; diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index d1e50e13894..dd7fbba753b 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -55,22 +55,24 @@ This API is completely unstable and subject to change. */ +// tidy-alphabetical-start +#![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::potential_query_instability)] #![allow(rustc::untranslatable_diagnostic)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] -#![feature(rustdoc_internals)] -#![allow(internal_features)] #![feature(control_flow_enum)] #![feature(if_let_guard)] #![feature(is_sorted)] #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(never_type)] -#![feature(lazy_cell)] +#![feature(rustdoc_internals)] #![feature(slice_partition_dedup)] #![feature(try_blocks)] +#![feature(unwrap_infallible)] +// tidy-alphabetical-end #[macro_use] extern crate tracing; @@ -90,7 +92,6 @@ mod errors; pub mod hir_wf_check; mod impl_wf_check; mod outlives; -pub mod structured_errors; mod variance; use rustc_hir as hir; @@ -150,8 +151,10 @@ pub fn provide(providers: &mut Providers) { pub fn check_crate(tcx: TyCtxt<'_>) { let _prof_timer = tcx.sess.timer("type_check_crate"); - if tcx.features().rustc_attrs { - let _ = tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx)); + // FIXME(effects): remove once effects is implemented in old trait solver + // or if the next solver is stabilized. + if tcx.features().effects && !tcx.next_trait_solver_globally() { + tcx.dcx().emit_err(errors::EffectsWithoutNextSolver); } tcx.sess.time("coherence_checking", || { @@ -168,11 +171,11 @@ pub fn check_crate(tcx: TyCtxt<'_>) { }); if tcx.features().rustc_attrs { - let _ = tcx.sess.time("variance_testing", || variance::test::test_variance(tcx)); - } - - if tcx.features().rustc_attrs { - let _ = collect::test_opaque_hidden_types(tcx); + tcx.sess.time("outlives_dumping", || outlives::dump::inferred_outlives(tcx)); + tcx.sess.time("variance_dumping", || variance::dump::variances(tcx)); + collect::dump::opaque_hidden_types(tcx); + collect::dump::predicates_and_item_bounds(tcx); + collect::dump::def_parents(tcx); } // Make sure we evaluate all static and (non-associated) const items, even if unused. diff --git a/compiler/rustc_hir_analysis/src/outlives/dump.rs b/compiler/rustc_hir_analysis/src/outlives/dump.rs new file mode 100644 index 00000000000..ab50d9e86ef --- /dev/null +++ b/compiler/rustc_hir_analysis/src/outlives/dump.rs @@ -0,0 +1,29 @@ +use rustc_middle::bug; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::sym; + +pub(crate) fn inferred_outlives(tcx: TyCtxt<'_>) { + for id in tcx.hir().items() { + if !tcx.has_attr(id.owner_id, sym::rustc_outlives) { + continue; + } + + let preds = tcx.inferred_outlives_of(id.owner_id); + let mut preds: Vec<_> = preds + .iter() + .map(|(pred, _)| match pred.kind().skip_binder() { + ty::ClauseKind::RegionOutlives(p) => p.to_string(), + ty::ClauseKind::TypeOutlives(p) => p.to_string(), + err => bug!("unexpected clause {:?}", err), + }) + .collect(); + preds.sort(); + + let span = tcx.def_span(id.owner_id); + let mut err = tcx.dcx().struct_span_err(span, sym::rustc_outlives.as_str()); + for pred in preds { + err.note(pred); + } + err.emit(); + } +} diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index 1de7a0f7bc7..bbfadbb5c30 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -6,7 +6,7 @@ use super::utils::*; #[derive(Debug)] pub struct ExplicitPredicatesMap<'tcx> { - map: FxIndexMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>, + map: FxIndexMap<DefId, ty::EarlyBinder<'tcx, RequiredPredicates<'tcx>>>, } impl<'tcx> ExplicitPredicatesMap<'tcx> { @@ -18,7 +18,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { &mut self, tcx: TyCtxt<'tcx>, def_id: DefId, - ) -> &ty::EarlyBinder<RequiredPredicates<'tcx>> { + ) -> &ty::EarlyBinder<'tcx, RequiredPredicates<'tcx>> { self.map.entry(def_id).or_insert_with(|| { let predicates = if def_id.is_local() { tcx.explicit_predicates_of(def_id) diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index e6c582667ba..af08f50f655 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -15,7 +15,7 @@ use super::utils::*; /// now be filled with inferred predicates. pub(super) fn infer_predicates( tcx: TyCtxt<'_>, -) -> FxIndexMap<DefId, ty::EarlyBinder<RequiredPredicates<'_>>> { +) -> FxIndexMap<DefId, ty::EarlyBinder<'_, RequiredPredicates<'_>>> { debug!("infer_predicates"); let mut explicit_map = ExplicitPredicatesMap::new(); @@ -101,7 +101,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, - global_inferred_outlives: &FxIndexMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>, + global_inferred_outlives: &FxIndexMap<DefId, ty::EarlyBinder<'tcx, RequiredPredicates<'tcx>>>, required_predicates: &mut RequiredPredicates<'tcx>, explicit_map: &mut ExplicitPredicatesMap<'tcx>, ) { @@ -322,7 +322,7 @@ fn check_inferred_predicates<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, args: ty::GenericArgsRef<'tcx>, - global_inferred_outlives: &FxIndexMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>, + global_inferred_outlives: &FxIndexMap<DefId, ty::EarlyBinder<'tcx, RequiredPredicates<'tcx>>>, required_predicates: &mut RequiredPredicates<'tcx>, ) { // Load the current set of inferred and explicit predicates from `global_inferred_outlives` diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs index 97fd7731b1e..1f74ebf99f1 100644 --- a/compiler/rustc_hir_analysis/src/outlives/mod.rs +++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs @@ -5,10 +5,9 @@ use rustc_middle::ty::GenericArgKind; use rustc_middle::ty::{self, CratePredicatesMap, TyCtxt, Upcast}; use rustc_span::Span; +pub(crate) mod dump; mod explicit; mod implicit_infer; -/// Code to write unit test for outlives. -pub mod test; mod utils; pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_hir_analysis/src/outlives/test.rs b/compiler/rustc_hir_analysis/src/outlives/test.rs deleted file mode 100644 index e9b6c679bd5..00000000000 --- a/compiler/rustc_hir_analysis/src/outlives/test.rs +++ /dev/null @@ -1,31 +0,0 @@ -use rustc_middle::bug; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::{symbol::sym, ErrorGuaranteed}; - -pub fn test_inferred_outlives(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { - let mut res = Ok(()); - for id in tcx.hir().items() { - // For unit testing: check for a special "rustc_outlives" - // attribute and report an error with various results if found. - if tcx.has_attr(id.owner_id, sym::rustc_outlives) { - let predicates = tcx.inferred_outlives_of(id.owner_id); - let mut pred: Vec<String> = predicates - .iter() - .map(|(out_pred, _)| match out_pred.kind().skip_binder() { - ty::ClauseKind::RegionOutlives(p) => p.to_string(), - ty::ClauseKind::TypeOutlives(p) => p.to_string(), - err => bug!("unexpected clause {:?}", err), - }) - .collect(); - pred.sort(); - - let span = tcx.def_span(id.owner_id); - let mut err = tcx.dcx().struct_span_err(span, "rustc_outlives"); - for p in pred { - err.note(p); - } - res = Err(err.emit()); - } - } - res -} diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs index 5086c2af3f6..08015c28a26 100644 --- a/compiler/rustc_hir_analysis/src/outlives/utils.rs +++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs @@ -1,9 +1,9 @@ use rustc_data_structures::fx::FxIndexMap; -use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_middle::ty::{self, Region, Ty, TyCtxt}; use rustc_middle::ty::{GenericArg, GenericArgKind}; use rustc_middle::{bug, span_bug}; use rustc_span::Span; +use rustc_type_ir::outlives::{push_outlives_components, Component}; use smallvec::smallvec; /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred diff --git a/compiler/rustc_hir_analysis/src/structured_errors.rs b/compiler/rustc_hir_analysis/src/structured_errors.rs deleted file mode 100644 index 5abfd25dd95..00000000000 --- a/compiler/rustc_hir_analysis/src/structured_errors.rs +++ /dev/null @@ -1,36 +0,0 @@ -mod missing_cast_for_variadic_arg; -mod sized_unsized_cast; -mod wrong_number_of_generic_args; - -pub use self::{ - missing_cast_for_variadic_arg::*, sized_unsized_cast::*, wrong_number_of_generic_args::*, -}; - -use rustc_errors::{Diag, ErrCode}; -use rustc_session::Session; - -pub trait StructuredDiag<'tcx> { - fn session(&self) -> &Session; - - fn code(&self) -> ErrCode; - - fn diagnostic(&self) -> Diag<'tcx> { - let err = self.diagnostic_common(); - - if self.session().teach(self.code()) { - self.diagnostic_extended(err) - } else { - self.diagnostic_regular(err) - } - } - - fn diagnostic_common(&self) -> Diag<'tcx>; - - fn diagnostic_regular(&self, err: Diag<'tcx>) -> Diag<'tcx> { - err - } - - fn diagnostic_extended(&self, err: Diag<'tcx>) -> Diag<'tcx> { - err - } -} diff --git a/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs deleted file mode 100644 index 0e78acbeae2..00000000000 --- a/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs +++ /dev/null @@ -1,57 +0,0 @@ -use crate::{errors, structured_errors::StructuredDiag}; -use rustc_errors::{codes::*, Diag}; -use rustc_middle::ty::{Ty, TypeVisitableExt}; -use rustc_session::Session; -use rustc_span::Span; - -pub struct MissingCastForVariadicArg<'tcx, 's> { - pub sess: &'tcx Session, - pub span: Span, - pub ty: Ty<'tcx>, - pub cast_ty: &'s str, -} - -impl<'tcx> StructuredDiag<'tcx> for MissingCastForVariadicArg<'tcx, '_> { - fn session(&self) -> &Session { - self.sess - } - - fn code(&self) -> ErrCode { - E0617 - } - - fn diagnostic_common(&self) -> Diag<'tcx> { - let (sugg_span, replace, help) = - if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.span) { - (Some(self.span), format!("{} as {}", snippet, self.cast_ty), None) - } else { - (None, "".to_string(), Some(())) - }; - - let mut err = self.sess.dcx().create_err(errors::PassToVariadicFunction { - span: self.span, - ty: self.ty, - cast_ty: self.cast_ty, - help, - replace, - sugg_span, - }); - - if self.ty.references_error() { - err.downgrade_to_delayed_bug(); - } - - err - } - - fn diagnostic_extended(&self, mut err: Diag<'tcx>) -> Diag<'tcx> { - err.note(format!( - "certain types, like `{}`, must be casted before passing them to a \ - variadic function, because of arcane ABI rules dictated by the C \ - standard", - self.ty - )); - - err - } -} diff --git a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs deleted file mode 100644 index 9e871ff9af0..00000000000 --- a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs +++ /dev/null @@ -1,56 +0,0 @@ -use crate::{errors, structured_errors::StructuredDiag}; -use rustc_errors::{codes::*, Diag}; -use rustc_middle::ty::{Ty, TypeVisitableExt}; -use rustc_session::Session; -use rustc_span::Span; - -pub struct SizedUnsizedCast<'tcx> { - pub sess: &'tcx Session, - pub span: Span, - pub expr_ty: Ty<'tcx>, - pub cast_ty: String, -} - -impl<'tcx> StructuredDiag<'tcx> for SizedUnsizedCast<'tcx> { - fn session(&self) -> &Session { - self.sess - } - - fn code(&self) -> ErrCode { - E0607 - } - - fn diagnostic_common(&self) -> Diag<'tcx> { - let mut err = self.sess.dcx().create_err(errors::CastThinPointerToFatPointer { - span: self.span, - expr_ty: self.expr_ty, - cast_ty: self.cast_ty.to_owned(), - }); - - if self.expr_ty.references_error() { - err.downgrade_to_delayed_bug(); - } - - err - } - - fn diagnostic_extended(&self, mut err: Diag<'tcx>) -> Diag<'tcx> { - err.help( - "Thin pointers are \"simple\" pointers: they are purely a reference to a -memory address. - -Fat pointers are pointers referencing \"Dynamically Sized Types\" (also -called DST). DST don't have a statically known size, therefore they can -only exist behind some kind of pointers that contain additional -information. Slices and trait objects are DSTs. In the case of slices, -the additional information the fat pointer holds is their size. - -To fix this error, don't try to cast directly between thin and fat -pointers. - -For more information about casts, take a look at The Book: -https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions", - ); - err - } -} diff --git a/compiler/rustc_hir_analysis/src/variance/dump.rs b/compiler/rustc_hir_analysis/src/variance/dump.rs new file mode 100644 index 00000000000..1a17dabb677 --- /dev/null +++ b/compiler/rustc_hir_analysis/src/variance/dump.rs @@ -0,0 +1,32 @@ +use rustc_hir::def::DefKind; +use rustc_hir::def_id::CRATE_DEF_ID; +use rustc_middle::ty::TyCtxt; +use rustc_span::symbol::sym; + +pub(crate) fn variances(tcx: TyCtxt<'_>) { + if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) { + for id in tcx.hir().items() { + let DefKind::OpaqueTy = tcx.def_kind(id.owner_id) else { continue }; + + let variances = tcx.variances_of(id.owner_id); + + tcx.dcx().emit_err(crate::errors::VariancesOf { + span: tcx.def_span(id.owner_id), + variances: format!("{variances:?}"), + }); + } + } + + for id in tcx.hir().items() { + if !tcx.has_attr(id.owner_id, sym::rustc_variance) { + continue; + } + + let variances = tcx.variances_of(id.owner_id); + + tcx.dcx().emit_err(crate::errors::VariancesOf { + span: tcx.def_span(id.owner_id), + variances: format!("{variances:?}"), + }); + } +} diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 1977451f39e..29f96e27b64 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -22,8 +22,7 @@ mod constraints; /// Code to solve constraints and write out the results. mod solve; -/// Code to write unit tests of variance. -pub mod test; +pub(crate) mod dump; /// Code for transforming variances. mod xform; diff --git a/compiler/rustc_hir_analysis/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs deleted file mode 100644 index c211e1af046..00000000000 --- a/compiler/rustc_hir_analysis/src/variance/test.rs +++ /dev/null @@ -1,37 +0,0 @@ -use rustc_hir::def::DefKind; -use rustc_hir::def_id::CRATE_DEF_ID; -use rustc_middle::ty::TyCtxt; -use rustc_span::symbol::sym; -use rustc_span::ErrorGuaranteed; - -use crate::errors; - -pub fn test_variance(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { - let mut res = Ok(()); - if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) { - for id in tcx.hir().items() { - if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) { - let variances_of = tcx.variances_of(id.owner_id); - - res = Err(tcx.dcx().emit_err(errors::VariancesOf { - span: tcx.def_span(id.owner_id), - variances_of: format!("{variances_of:?}"), - })); - } - } - } - - // For unit testing: check for a special "rustc_variance" - // attribute and report an error with various results if found. - for id in tcx.hir().items() { - if tcx.has_attr(id.owner_id, sym::rustc_variance) { - let variances_of = tcx.variances_of(id.owner_id); - - res = Err(tcx.dcx().emit_err(errors::VariancesOf { - span: tcx.def_span(id.owner_id), - variances_of: format!("{variances_of:?}"), - })); - } - } - res -} |
