-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Assert that args are actually compatible with their generics, rather than just their count #123240
Changes from all commits
e3025d6
c9f8529
657dadf
03163ef
bd8ca78
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1961,33 +1961,104 @@ impl<'tcx> TyCtxt<'tcx> { | |
if pred.kind() != binder { self.mk_predicate(binder) } else { pred } | ||
} | ||
|
||
#[inline(always)] | ||
pub(crate) fn check_and_mk_args( | ||
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: impl IntoIterator<Item: Into<GenericArg<'tcx>>>, | ||
) -> GenericArgsRef<'tcx> { | ||
let args = args.into_iter().map(Into::into); | ||
#[cfg(debug_assertions)] | ||
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. | ||
Comment on lines
+1976
to
+1977
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we have a test that exercises this or could you post a snippet? haven't wrapped my head around that yet There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. consider an ITIATII (impl trait in associated type in inherent impl):
The |
||
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)) | ||
{ | ||
let generics = self.generics_of(_def_id); | ||
if generics.params.len() + 1 != args.len() { | ||
return false; | ||
} | ||
|
||
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 !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) | ||
{ | ||
// 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::<Vec<_>>(), | ||
); | ||
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, | ||
} | ||
} | ||
self.mk_args_from_iter(args) | ||
|
||
true | ||
} | ||
|
||
/// With `cfg(debug_assertions)`, assert that args are compatible with their generics, | ||
/// and print out the args if not. | ||
pub fn debug_assert_args_compatible(self, def_id: DefId, args: &'tcx [ty::GenericArg<'tcx>]) { | ||
if cfg!(debug_assertions) { | ||
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!( | ||
"args not compatible with generics for {}: args={:#?}, generics={:#?}", | ||
self.def_path_str(def_id), | ||
args, | ||
// Make `[Self, GAT_ARGS...]` (this could be simplified) | ||
self.mk_args_from_iter( | ||
[self.types.self_param.into()].into_iter().chain( | ||
self.generics_of(def_id) | ||
.own_args(ty::GenericArgs::identity_for_item(self, def_id)) | ||
.iter() | ||
.copied() | ||
) | ||
) | ||
); | ||
} 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<Item: Into<GenericArg<'tcx>>>, | ||
) -> GenericArgsRef<'tcx> { | ||
let args = self.mk_args_from_iter(args.into_iter().map(Into::into)); | ||
self.debug_assert_args_compatible(def_id, args); | ||
args | ||
} | ||
|
||
#[inline] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lol you just keep improving things I've recently looked at. in this case, #123140. appreciate it 🙏