Skip to content

Conversation

@sergiogiro
Copy link

@sergiogiro sergiogiro commented Nov 16, 2025

Fixes #16019 by reborrowing, instead of using by_ref, when the iterator expression is not Sized.

changelog: [`while_let_on_iterator`]: fixes broken suggestion by using reborrow instead of `by_ref` for references to traits that are not `Sized`

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Nov 16, 2025
@rustbot
Copy link
Collaborator

rustbot commented Nov 16, 2025

r? @Jarcho

rustbot has assigned @Jarcho.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@github-actions
Copy link

github-actions bot commented Nov 16, 2025

No changes for bbadb72

@Jarcho
Copy link
Contributor

Jarcho commented Nov 17, 2025

The suggestion used to be to borrow/reborrow before it was changed to by_ref. The only change that needs to happen is a check if the iterator expression has a type of &mut ?Sized. The can be done by checking the type's kind for a reference and using Ty::is_sized on the referent type.

@sergiogiro
Copy link
Author

The suggestion used to be to borrow/reborrow before it was changed to by_ref. The only change that needs to happen is a check if the iterator expression has a type of &mut ?Sized. The can be done by checking the type's kind for a reference and using Ty::is_sized on the referent type.

Great, thanks, I can rework the PR to do a reborrow only when needed.

@sergiogiro sergiogiro force-pushed the sergio-clippy/avoid-by-ref-in-suggestion-for-while-replacement branch from 9638f9c to 1c8b099 Compare November 17, 2025 13:13
@sergiogiro sergiogiro force-pushed the sergio-clippy/avoid-by-ref-in-suggestion-for-while-replacement branch from 1c8b099 to f4496bf Compare November 17, 2025 13:19
@sergiogiro
Copy link
Author

Thanks for the advice. Now the PR just changes the behaviour for non-sized types, and adds a couple tests accordingly.

@sergiogiro sergiogiro changed the title Fixes #16109: Avoid by_ref in suggestions to remove while-let loops Fixes #16109: For non-sized types, use reborrow in suggestions to remove while-let loops Nov 17, 2025
Comment on lines 363 to 374
fn make_iterator_snippet<'tcx>(cx: &LateContext<'tcx>, iter_expr: &Expr<'tcx>, iterator: impl Into<String>) -> String {
let iterator = iterator.into();
let ty = cx.typeck_results().expr_ty(iter_expr);

if let ty::Ref(_, inner_ty, _) = ty.kind()
&& !inner_ty.is_sized(cx.tcx, cx.typing_env())
{
return format!("&mut *{iterator}");
}

format!("{iterator}.by_ref()")
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This won't work if auto-deref is used for the next call. A simple example is:

struct S<T>(T);
impl<T> core::ops::Deref for S<T> {
    type Target = T;
    fn deref(&self) -> &Self::Target { &self.0 }
}
impl<T> core::ops::DerefMut for S<T> {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}

fn f(mut x: S<S<&mut dyn Iterator<Item = u32>>>) {
    while let Some(_) = x.next() {}
    // suggestion: `for _ in &mut **x {}`
}

What you'll need to do is walk the adjustments to find the last deref and use that type for the sized check and suggest applying all the derefs manually.

if let Some((n, adjust)) = cx
    .typeck_results()
    .expr_adjustments(e)
    .iter()
    .take_while(|x| matches!(x.kind, Adjust::Deref(_)))
    .enumerate()
    .last()
    && !adjust.target.is_sized(cx.tcx, cx.typing_env())
{
    format!("&mut {:*<n$}{iterator}", '*', n = n + 1)
} else {
    // by_ref
}

There will always be at least one deref adjustment on the expression since the receiver type on Iterator::next is a reference.

Copy link
Author

Choose a reason for hiding this comment

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

Thank you so much for the help, doing it this way now.

make_iterator_snippet(cx, iter_expr, iterator)
} else {
""
iterator.to_string()
Copy link
Contributor

Choose a reason for hiding this comment

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

Should be into_owned.

Copy link
Author

Choose a reason for hiding this comment

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

Yes, thank you, changed it now.

/// Constructs the transformed iterator expression for the suggestion.
/// Returns `iterator.by_ref()` unless the iterator type is a reference to an unsized type,
/// in which case it returns `&mut *iterator`.
fn make_iterator_snippet<'tcx>(cx: &LateContext<'tcx>, iter_expr: &Expr<'tcx>, iterator: impl Into<String>) -> String {
Copy link
Contributor

Choose a reason for hiding this comment

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

Just take &str rather than Into<String>.

Copy link
Author

Choose a reason for hiding this comment

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

Sorted now.

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties labels Nov 27, 2025
@rustbot
Copy link
Collaborator

rustbot commented Nov 27, 2025

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@sergiogiro
Copy link
Author

sergiogiro commented Nov 29, 2025

Thank you so much for the guidance, it's been educative and a lot of fun to work on this issue.

I added the case suggested in the PR comment as test, plus some other tests to check the intended behavior in detail. Happy to delete tests if you think they're too many.

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties and removed S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) labels Nov 29, 2025
@sergiogiro sergiogiro requested a review from Jarcho November 29, 2025 18:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties

Projects

None yet

Development

Successfully merging this pull request may close these issues.

while_let_on_iterator suggested solution doesn't work in default implementations of traits without explicit Sized bound

3 participants