diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 23881c4b124..df792b87056 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1961,33 +1961,90 @@ pub fn reuse_or_mk_predicate( if pred.kind() != binder { self.mk_predicate(binder) } else { pred } } + pub fn check_args_compatible(self, def_id: DefId, args: &'tcx [ty::GenericArg<'tcx>]) -> bool { + self.check_args_compatible_inner(def_id, args, false) + } + + fn check_args_compatible_inner( + self, + def_id: DefId, + args: &'tcx [ty::GenericArg<'tcx>], + nested: bool, + ) -> bool { + let generics = self.generics_of(def_id); + + // IATs themselves have a weird arg setup (self + own args), but nested items *in* IATs + // (namely: opaques, i.e. ATPITs) do not. + let own_args = if !nested + && let DefKind::AssocTy = self.def_kind(def_id) + && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id)) + { + if generics.params.len() + 1 != args.len() { + return false; + } + + if !matches!(args[0].unpack(), ty::GenericArgKind::Type(_)) { + return false; + } + + &args[1..] + } else { + if generics.count() != args.len() { + return false; + } + + let (parent_args, own_args) = args.split_at(generics.parent_count); + + if let Some(parent) = generics.parent + && !self.check_args_compatible_inner(parent, parent_args, true) + { + return false; + } + + own_args + }; + + for (param, arg) in std::iter::zip(&generics.params, own_args) { + match (¶m.kind, arg.unpack()) { + (ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_)) + | (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_)) + | (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {} + _ => return false, + } + } + + true + } + + pub fn assert_args_compatible(self, def_id: DefId, args: &'tcx [ty::GenericArg<'tcx>]) { + if !self.check_args_compatible(def_id, args) { + if let DefKind::AssocTy = self.def_kind(def_id) + && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id)) + { + bug!() + } else { + bug!( + "args not compatible with generics for {}: args={:#?}, generics={:#?}", + self.def_path_str(def_id), + args, + ty::GenericArgs::identity_for_item(self, def_id) + ); + } + } + } + #[inline(always)] pub(crate) fn check_and_mk_args( self, _def_id: DefId, args: impl IntoIterator>>, ) -> GenericArgsRef<'tcx> { - let args = args.into_iter().map(Into::into); + let args = self.mk_args_from_iter(args.into_iter().map(Into::into)); #[cfg(debug_assertions)] { - let generics = self.generics_of(_def_id); - - let n = if let DefKind::AssocTy = self.def_kind(_def_id) - && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(_def_id)) - { - // If this is an inherent projection. - generics.params.len() + 1 - } else { - generics.count() - }; - assert_eq!( - (n, Some(n)), - args.size_hint(), - "wrong number of generic parameters for {_def_id:?}: {:?}", - args.collect::>(), - ); + self.assert_args_compatible(_def_id, args); } - self.mk_args_from_iter(args) + args } #[inline] diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index b5e619f1e2a..dc1ad1da7e1 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1624,13 +1624,9 @@ pub fn new_imm_ptr(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { #[inline] pub fn new_adt(tcx: TyCtxt<'tcx>, def: AdtDef<'tcx>, args: GenericArgsRef<'tcx>) -> Ty<'tcx> { - debug_assert_eq!( - tcx.generics_of(def.did()).count(), - args.len(), - "wrong number of args for ADT: {:#?} vs {:#?}", - tcx.generics_of(def.did()).params, - args - ); + if cfg!(debug_assertions) { + tcx.assert_args_compatible(def.did(), args); + } Ty::new(tcx, Adt(def, args)) } @@ -1711,11 +1707,9 @@ pub fn new_closure( def_id: DefId, closure_args: GenericArgsRef<'tcx>, ) -> Ty<'tcx> { - debug_assert_eq!( - closure_args.len(), - tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 3, - "closure constructed with incorrect generic parameters" - ); + if cfg!(debug_assertions) { + tcx.assert_args_compatible(def_id, closure_args); + } Ty::new(tcx, Closure(def_id, closure_args)) } @@ -1725,11 +1719,9 @@ pub fn new_coroutine_closure( def_id: DefId, closure_args: GenericArgsRef<'tcx>, ) -> Ty<'tcx> { - debug_assert_eq!( - closure_args.len(), - tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 5, - "closure constructed with incorrect generic parameters" - ); + if cfg!(debug_assertions) { + tcx.assert_args_compatible(def_id, closure_args); + } Ty::new(tcx, CoroutineClosure(def_id, closure_args)) } @@ -1739,11 +1731,9 @@ pub fn new_coroutine( def_id: DefId, coroutine_args: GenericArgsRef<'tcx>, ) -> Ty<'tcx> { - debug_assert_eq!( - coroutine_args.len(), - tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 6, - "coroutine constructed with incorrect number of generic parameters" - ); + if cfg!(debug_assertions) { + tcx.assert_args_compatible(def_id, coroutine_args); + } Ty::new(tcx, Coroutine(def_id, coroutine_args)) } diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 66688893235..d8aeadd07b3 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -1,4 +1,4 @@ -use crate::traits::{check_args_compatible, specialization_graph}; +use crate::traits::specialization_graph; use super::assembly::structural_traits::AsyncCallableRelevantTypes; use super::assembly::{self, structural_traits, Candidate}; @@ -247,7 +247,7 @@ fn consider_impl_candidate( assoc_def.defining_node, ); - if !check_args_compatible(tcx, assoc_def.item, args) { + if !tcx.check_args_compatible(assoc_def.item.def_id, args) { return error_response( ecx, "associated item has mismatched generic item arguments", diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 3ab4872fffe..2c8116b779b 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -61,12 +61,12 @@ pub use self::structural_match::search_for_structural_match_violation; pub use self::structural_normalize::StructurallyNormalizeExt; pub use self::util::elaborate; -pub use self::util::{ - check_args_compatible, supertrait_def_ids, supertraits, transitive_bounds, - transitive_bounds_that_define_assoc_item, SupertraitDefIds, -}; pub use self::util::{expand_trait_aliases, TraitAliasExpander, TraitAliasExpansionInfo}; pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices}; +pub use self::util::{ + supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_item, + SupertraitDefIds, +}; pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer}; pub use rustc_infer::traits::*; diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index c33e24b1094..9d744d9a032 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -2,7 +2,6 @@ use std::ops::ControlFlow; -use super::check_args_compatible; use super::specialization_graph; use super::translate_args; use super::util; @@ -2030,7 +2029,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( } else { ty.map_bound(|ty| ty.into()) }; - if !check_args_compatible(tcx, assoc_ty.item, args) { + if !tcx.check_args_compatible(assoc_ty.item.def_id, args) { let err = Ty::new_error_with_message( tcx, obligation.cause.span, diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 50cc0ed90fb..d29fc7921bc 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -344,46 +344,6 @@ pub enum TupleArgumentsFlag { No, } -// Verify that the trait item and its implementation have compatible args lists -pub fn check_args_compatible<'tcx>( - tcx: TyCtxt<'tcx>, - assoc_item: ty::AssocItem, - args: ty::GenericArgsRef<'tcx>, -) -> bool { - fn check_args_compatible_inner<'tcx>( - tcx: TyCtxt<'tcx>, - generics: &'tcx ty::Generics, - args: &'tcx [ty::GenericArg<'tcx>], - ) -> bool { - if generics.count() != args.len() { - return false; - } - - let (parent_args, own_args) = args.split_at(generics.parent_count); - - if let Some(parent) = generics.parent - && let parent_generics = tcx.generics_of(parent) - && !check_args_compatible_inner(tcx, parent_generics, parent_args) - { - return false; - } - - for (param, arg) in std::iter::zip(&generics.params, own_args) { - match (¶m.kind, arg.unpack()) { - (ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_)) - | (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_)) - | (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {} - _ => return false, - } - } - - true - } - - let generics = tcx.generics_of(assoc_item.def_id); - check_args_compatible_inner(tcx, generics, args) -} - /// Executes `f` on `value` after replacing all escaping bound variables with placeholders /// and then replaces these placeholders with the original bound variables in the result. /// diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index fc16edc6d13..a652bb78116 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -7,7 +7,6 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; use rustc_span::Span; -use rustc_trait_selection::traits::check_args_compatible; use crate::errors::{DuplicateArg, NotParam}; @@ -250,7 +249,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) { ty::GenericArgs::identity_for_item(self.tcx, parent), ); - if check_args_compatible(self.tcx, assoc, impl_args) { + if self.tcx.check_args_compatible(assoc.def_id, impl_args) { self.tcx .type_of(assoc.def_id) .instantiate(self.tcx, impl_args)