Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1849,7 +1849,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {

assert_eq!(tcx.trait_impl_of_assoc(def_id), None);
self.prove_clauses(
args.types().map(|ty| ty::ClauseKind::WellFormed(ty.into())),
args.terms().map(|t| ty::ClauseKind::WellFormed(t.into())),
locations,
ConstraintCategory::Boring,
);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1431,6 +1431,7 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>(
ty: Ty<'tcx>,
) -> SmallVec<Option<&'ll DIType>> {
if let ty::Adt(def, args) = *ty.kind() {
// FIXME: also do consts?
if args.types().next().is_some() {
let generics = cx.tcx.generics_of(def.did());
let names = get_parameter_names(cx, generics);
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ impl<'ll, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
generics: &ty::Generics,
args: GenericArgsRef<'tcx>,
) -> &'ll DIArray {
if args.types().next().is_none() {
if args.terms().next().is_none() {
return create_DIArray(DIB(cx), &[]);
}

Expand All @@ -293,6 +293,7 @@ impl<'ll, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
let names = get_parameter_names(cx, generics);
iter::zip(args, names)
.filter_map(|(kind, name)| {
// FIXME: debug info for consts (using `createTemplateValueParameter`?)
kind.as_type().map(|ty| {
let actual_type = cx.tcx.normalize_erasing_regions(
cx.typing_env(),
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_middle/src/ty/generic_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,11 @@ impl<'tcx> GenericArgs<'tcx> {
self.iter().filter_map(|k| k.as_const())
}

#[inline]
pub fn terms(&self) -> impl DoubleEndedIterator<Item = ty::Term<'tcx>> {
self.iter().filter_map(|k| k.as_term())
}

/// Returns generic arguments that are not lifetimes.
#[inline]
pub fn non_erasable_generics(&self) -> impl DoubleEndedIterator<Item = GenericArgKind<'tcx>> {
Expand Down
4 changes: 1 addition & 3 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2305,9 +2305,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
// `Foo<...>`.
if let Some(arg) = args.types().next() {
if let ty::Adt(_, arg_args) = arg.kind() {
if arg_args.consts().next().is_none()
&& arg_args.types().next().is_none()
{
if arg_args.terms().next().is_none() {
// Single param type with no type or const parameters:
// `Foo<Bar<'a>>`.
true
Expand Down
4 changes: 1 addition & 3 deletions compiler/rustc_mir_transform/src/function_item_references.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
other_abi => format!("extern {other_abi} "),
};
let ident = self.tcx.item_ident(fn_id);
let ty_params = fn_args.types().map(|ty| format!("{ty}"));
let const_params = fn_args.consts().map(|c| format!("{c}"));
let params = ty_params.chain(const_params).join(", ");
let params = fn_args.terms().map(|term| format!("{term}")).join(", ");
let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder();
let variadic = if fn_sig.c_variadic() { ", ..." } else { "" };
let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -677,7 +677,7 @@ impl<'tcx> InferSourceKind<'tcx> {
|| matches!(
ty.kind(),
ty::Adt(_, args)
if args.types().count() == 0 && args.consts().count() == 0
if args.terms().next().is_none()
)
{
// `ty` is either `_`, a primitive type like `u32` or a type with no type or
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,12 +255,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// Pick the first generic parameter that still contains inference variables as the one
// we're going to emit an error for. If there are none (see above), fall back to
// a more general error.
let term = data
.trait_ref
.args
.iter()
.filter_map(ty::GenericArg::as_term)
.find(|s| s.has_non_region_infer());
let term = data.trait_ref.args.terms().find(|s| s.has_non_region_infer());

let mut err = if let Some(term) = term {
let candidates: Vec<_> = self
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_trait_selection/src/traits/auto_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
let new_args = new_trait.trait_ref.args;
let old_args = old_trait.trait_ref.args;

if !new_args.types().eq(old_args.types()) {
if !new_args.terms().eq(old_args.terms()) {
// We can't compare lifetimes if the types are different,
// so skip checking `old_clause`.
return true;
Expand Down Expand Up @@ -625,7 +625,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
}

fn is_param_no_infer(&self, args: GenericArgsRef<'tcx>) -> bool {
self.is_of_param(args.type_at(0)) && !args.types().any(|t| t.has_infer_types())
self.is_of_param(args.type_at(0)) && !args.terms().any(|t| t.has_infer_types())
}

pub fn is_of_param(&self, ty: Ty<'tcx>) -> bool {
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1237,6 +1237,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// This suffices to allow chains like `FnMut` implemented in
// terms of `Fn` etc, but we could probably make this more
// precise still.
//
// FIXME(min_generic_const_args): Consider consts as well?
let unbound_input_types =
stack.fresh_trait_pred.skip_binder().trait_ref.args.types().any(|ty| ty.is_fresh());

Expand Down
2 changes: 1 addition & 1 deletion src/tools/clippy/clippy_lints/src/manual_bits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<
cx.typeck_results()
.node_args(count_func.hir_id)
.types()
.next()
.nth(0) // the `T` in `size_of::<T>`
.map(|resolved_ty| (real_ty_span, resolved_ty))
} else {
None
Expand Down
2 changes: 1 addition & 1 deletion src/tools/clippy/clippy_lints/src/methods/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ impl SelfKind {
} else if let ty::Adt(adt_def, args) = ty.kind()
&& matches!(cx.tcx.get_diagnostic_name(adt_def.did()), Some(sym::Rc | sym::Arc))
{
args.types().next() == Some(parent_ty)
args.iter().filter_map(ty::GenericArg::as_type).nth(0) == Some(parent_ty)

@LorrensP-2158466 LorrensP-2158466 Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From @lcnr in the zulip discussion:

yeah, the fact that accessing just types is often vaguely wrong and doesn't allow for random access, so doing iter().filter_map(GenericArg::as_type).nth(1) is beter for that

View changes since the review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that can just be next().as_type() 🤔

} else {
false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ enum RepeatKind {

fn get_ty_param(ty: Ty<'_>) -> Option<Ty<'_>> {
if let ty::Adt(_, subs) = ty.kind() {
subs.types().next()
subs.iter().filter_map(ty::GenericArg::as_type).nth(0)

@lcnr lcnr Aug 6, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

subs.iter().filter_map(ty::GenericArg::as_type).next() .nth(0) is always worse than next 🤔

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so iter().next().as_type(), gotcha.

} else {
None
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, iter: &hir::Expr
let collect_ret_ty = cx.typeck_results().expr_ty(expr);
if collect_ret_ty.is_diag_item(cx, sym::Result)
&& let ty::Adt(_, args) = collect_ret_ty.kind()
&& let Some(result_t) = args.types().next()
&& let Some(result_t) = args.iter().filter_map(ty::GenericArg::as_type).nth(0)
&& result_t.is_unit()
// get parts for snippet
{
Expand Down
4 changes: 3 additions & 1 deletion src/tools/clippy/clippy_lints/src/methods/ok_expect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
/// Given a `Result<T, E>` type, return its error type (`E`).
fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option<Ty<'a>> {
match ty.kind() {
ty::Adt(adt, args) if cx.tcx.is_diagnostic_item(sym::Result, adt.did()) => args.types().nth(1),
ty::Adt(adt, args) if cx.tcx.is_diagnostic_item(sym::Result, adt.did()) => {
args.iter().filter_map(ty::GenericArg::as_type).nth(1)
},
_ => None,
}
}
8 changes: 6 additions & 2 deletions src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, inverted:
Some(sym::mem_size_of | sym::mem_size_of_val)
)
{
cx.typeck_results().node_args(count_func.hir_id).types().next()
cx.typeck_results()
.node_args(count_func.hir_id)
.iter()
.filter_map(ty::GenericArg::as_type)
.nth(0)
} else {
None
}
Expand Down Expand Up @@ -92,7 +96,7 @@ fn get_pointee_ty_and_count_expr<'tcx>(
))

// Get the pointee type
&& let Some(pointee_ty) = cx.typeck_results().node_args(func.hir_id).types().next()
&& let Some(pointee_ty) = cx.typeck_results().node_args(func.hir_id).iter().filter_map(ty::GenericArg::as_type).nth(0)
{
return Some((pointee_ty, count));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,12 +323,16 @@ fn is_size_pair(ty: Ty<'_>) -> bool {
}

fn same_except_params<'tcx>(subs1: GenericArgsRef<'tcx>, subs2: GenericArgsRef<'tcx>) -> bool {
// TODO: check const parameters as well. Currently this will consider `Array<5>` the same as
// `Array<6>`
for (ty1, ty2) in subs1.types().zip(subs2.types()).filter(|(ty1, ty2)| ty1 != ty2) {
match (ty1.kind(), ty2.kind()) {
(ty::Param(_), _) | (_, ty::Param(_)) => (),
(ty::Adt(adt1, subs1), ty::Adt(adt2, subs2)) if adt1 == adt2 && same_except_params(subs1, subs2) => (),
for (t1, t2) in subs1.terms().zip(subs2.terms()).filter(|(t1, t2)| t1 != t2) {
match (t1.kind(), t2.kind()) {
(ty::TermKind::Ty(ty1), ty::TermKind::Ty(ty2)) => match (ty1.kind(), ty2.kind()) {
(ty::Param(_), _) | (_, ty::Param(_)) => (),
(ty::Adt(adt1, subs1), ty::Adt(adt2, subs2)) if adt1 == adt2 && same_except_params(subs1, subs2) => (),
_ => return false,
},
// FIXME: check const parameters better as well. Currently this will consider `Array<5>` the same as
// `Array<6>`
(ty::TermKind::Const(c1), ty::TermKind::Const(c2)) if c1 == c2 => todo!(),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's a todo!() here - probably should either keep the old behavior of considering all consts to be equal, or properly implement this, instead of panicing~

(today I learned that tidy doesn't run on src/tools/clippy, todo!() is banned by tidy)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I meant to ask a follow up question on this.

Consts are interned as well, right? But are there cases where they are not the same "const" but are still the same? Otherwise this can just return true indeed.

(today I learned that tidy doesn't run on src/tools/clippy, todo!() is banned by tidy)

Yeah me to :D.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it to => true for now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For purposes of this real wonky function, yeah, consts can contain params. IMO, drop the guard, just have (ty::TermKind::Const(c1), ty::TermKind::Const(c2)) => (), to retain the old behavior, with the old comment. This function is only called in clippy::transmute_undefined_repr, which "has had multiple problems in the past and was moved to nursery" rust-lang/rust-clippy#8496 so preserving whatever wonky behavior it has for now seems best. (Hypothesizing a future fix, this should probably be a type relation or somesuch rather than doing a wonky custom relation on just ADTs? I mean, properly, I think maybe it should be doing a trait solver .eq() and checking if there's a solution. Idk.)

(Also, shouldn't return true but rather continue to the next term)

_ => return false,
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/tools/clippy/clippy_lints/src/useless_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
&& let b = cx.typeck_results().expr_ty(recv)
&& a.is_diag_item(cx, sym::Result)
&& let ty::Adt(_, args) = a.kind()
&& let Some(a_type) = args.types().next()
&& let Some(a_type) = args.iter().filter_map(GenericArg::as_type).nth(0)
&& same_type_modulo_regions(a_type, b)
{
span_lint_and_help(
Expand All @@ -424,7 +424,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
if name == sym::try_from_fn
&& a.is_diag_item(cx, sym::Result)
&& let ty::Adt(_, args) = a.kind()
&& let Some(a_type) = args.types().next()
&& let Some(a_type) = args.iter().filter_map(GenericArg::as_type).nth(0)
&& same_type_modulo_regions(a_type, b)
{
let hint = format!("consider removing `{}()`", snippet(cx, path.span, "TryFrom::try_from"));
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/lint/function-item-references.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ unsafe extern "C" fn variadic(_x: u32, _args: ...) { }
fn take_generic_ref<'a, T>(_x: &'a T) { }
fn take_generic_array<T, const N: usize>(_x: [T; N]) { }
fn multiple_generic<T, U>(_x: T, _y: U) { }
fn multiple_generic_arrays<T, U, const N: usize, const M: usize>(_x: [T; N], _y: [U; M]) { }
fn multiple_generic_arrays<T, const N: usize, U, const M: usize>(_x: [T; N], _y: [U; M]) { }
Comment thread
LorrensP-2158466 marked this conversation as resolved.

//function references passed to these functions should never lint
fn call_fn(f: &dyn Fn(u32) -> u32, x: u32) { f(x); }
Expand Down Expand Up @@ -120,7 +120,7 @@ fn main() {
//~^ WARNING taking a reference to a function item does not give a function pointer
println!("{:p}", &multiple_generic::<u32, f32>);
//~^ WARNING taking a reference to a function item does not give a function pointer
println!("{:p}", &multiple_generic_arrays::<u32, f32, 4, 8>);
println!("{:p}", &multiple_generic_arrays::<u32, 4, f32, 8>);
//~^ WARNING taking a reference to a function item does not give a function pointer
println!("{:p}", &std::env::var::<String>);
//~^ WARNING taking a reference to a function item does not give a function pointer
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/lint/function-item-references.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ LL | println!("{:p}", &multiple_generic::<u32, f32>);
warning: taking a reference to a function item does not give a function pointer
--> $DIR/function-item-references.rs:123:22
|
LL | println!("{:p}", &multiple_generic_arrays::<u32, f32, 4, 8>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: cast `multiple_generic_arrays` to obtain a function pointer: `multiple_generic_arrays::<u32, f32, 4, 8> as fn(_, _)`
LL | println!("{:p}", &multiple_generic_arrays::<u32, 4, f32, 8>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: cast `multiple_generic_arrays` to obtain a function pointer: `multiple_generic_arrays::<u32, 4, f32, 8> as fn(_, _)`

warning: taking a reference to a function item does not give a function pointer
--> $DIR/function-item-references.rs:125:22
Expand Down
Loading