Skip to content

fix: Port call expr type checking and closure upvar inference from rustc#22101

Merged
ChayimFriedman2 merged 5 commits intorust-lang:masterfrom
ChayimFriedman2:port-infer-call
Apr 20, 2026
Merged

fix: Port call expr type checking and closure upvar inference from rustc#22101
ChayimFriedman2 merged 5 commits intorust-lang:masterfrom
ChayimFriedman2:port-infer-call

Conversation

@ChayimFriedman2
Copy link
Copy Markdown
Contributor

@ChayimFriedman2 ChayimFriedman2 commented Apr 20, 2026

The first commits are small.

The biggest differences from rustc are due to the fact that we need to precisely store all source spans for captures, for the convert_closure_to_fn assist.

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Apr 20, 2026
#[test]
fn capture_specific_fields() {
size_and_align_expr! {
minicore: fn;
Copy link
Copy Markdown
Contributor Author

@ChayimFriedman2 ChayimFriedman2 Apr 20, 2026

Choose a reason for hiding this comment

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

The new call implementation is sensitive to FnX in core; anything that call closures need them, or it'll panic.

View changes since the review

}
"#,
expect!["53..79;20..21;67..72 ByRef(Shared) *a &'? bool"],
expect!["53..79;20..21;62..72 ByRef(Immutable) *a &'<erased> bool"],
Copy link
Copy Markdown
Contributor Author

@ChayimFriedman2 ChayimFriedman2 Apr 20, 2026

Choose a reason for hiding this comment

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

I have to admit I didn't check all the changed ranges here to make sense 😅 If the reviewer wants to do that, well..., that's not easy. But convert_closure_to_fn relies on the ranges and its test passes, and I did check the capture kinds.

View changes since the review

"#,
r#"
struct A { b: &'static B, c: i32 }
struct A { b: &'static mut B, c: i32 }
Copy link
Copy Markdown
Contributor Author

@ChayimFriedman2 ChayimFriedman2 Apr 20, 2026

Choose a reason for hiding this comment

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

Here I changed it to mut because leaving it as is (there is a test down with the same structs I left as-is), the capture will be &B instead of &i32. This is due to truncate_capture_for_optimization(), which we didn't have earlier.

View changes since the review

## Captures
* `x.f1` by move
* `(*x.f2.0.0).f` by mutable borrow
* `x.f2.0.0.f` by mutable borrow
Copy link
Copy Markdown
Contributor Author

@ChayimFriedman2 ChayimFriedman2 Apr 20, 2026

Choose a reason for hiding this comment

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

This is due to a small change (in my opinion, and in the code): I decided that we don't need a separate display() for the place, and we can use display_for_source_code(). The difference between the two used to be that the non-source-code version always printed derefs, with parentheses if needed. I decided now that it's nicer to show without them, given that the user expects autoderef anyway. Note that in the closure_captures.rs tests we do print all derefs, to ensure better coverage.

View changes since the review

fn foo() {
let closure;
// ^^^^^^^ impl Fn()
// ^^^^^^^ impl FnOnce()
Copy link
Copy Markdown
Contributor Author

@ChayimFriedman2 ChayimFriedman2 Apr 20, 2026

Choose a reason for hiding this comment

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

The functions in this test error in rustc, so whatever we infer is good enough.

View changes since the review

let res: serde_json::Value = serde_json::from_str(res.as_str().unwrap()).unwrap();
let arr = res.as_array().unwrap();
assert_eq!(arr.len(), 2);
assert_eq!(arr.len(), 1);
Copy link
Copy Markdown
Contributor Author

@ChayimFriedman2 ChayimFriedman2 Apr 20, 2026

Choose a reason for hiding this comment

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

There previously was a duplicate goal.

View changes since the review

@ChayimFriedman2 ChayimFriedman2 force-pushed the port-infer-call branch 3 times, most recently from 3154dc6 to cb0f840 Compare April 20, 2026 01:26
@ChayimFriedman2
Copy link
Copy Markdown
Contributor Author

This analysis_stats failure - turns out we're just missing match arm guards in walk_child_exprs() 🫢

@ChayimFriedman2 ChayimFriedman2 force-pushed the port-infer-call branch 5 times, most recently from a16543e to 37febba Compare April 20, 2026 04:08
f(*expr);
arms.iter().for_each(|arm| {
f(arm.expr);
if let Some(guard) = arm.guard {
Copy link
Copy Markdown
Member

@Veykril Veykril Apr 20, 2026

Choose a reason for hiding this comment

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

In these kinds of functions we should really enforce restructuring patterns to catch things 😅

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.

Agree, but it's better to leave that to another PR.

@@ -1,3 +1,4 @@
//- minicore: fn
Copy link
Copy Markdown
Member

@Veykril Veykril Apr 20, 2026

Choose a reason for hiding this comment

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

Curious where we panic without language items, ideally that wouldn't happen (even if in practice no one will ever write a no_core rust program without the fn traits ...). Just looks a bit odd to add a mini core directive here haha

View changes since the review

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.

I wonder if we should add this directive as enabled by default for tests now

Copy link
Copy Markdown
Contributor Author

@ChayimFriedman2 ChayimFriedman2 Apr 20, 2026

Choose a reason for hiding this comment

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

It panicked in the past as Expected to find a suitable `Fn`/`FnMut`/`FnOnce` implementation for ... in callee.rs, this was copied from rustc and I preferred not to change it. But I was forced to, because it panicked in the sysroot run in CI (it doesn't have a proper sysroot configured), and there I could not inject a minicore 😅

Comment thread crates/hir-ty/src/utils.rs
Self::try_overloaded_call_step(call_expr, callee_expr, arg_exprs, &mut autoderef);
}

// FIXME: rustc does some ABI checks here, but the ABI mapping is in rustc_target and we don't have access to that crate.
Copy link
Copy Markdown
Member

@Veykril Veykril Apr 20, 2026

Choose a reason for hiding this comment

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

Curious what mapping you are speaking of here 🤔

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.

Comment on lines -641 to -642
// FIXME: remove this field
pub mutated_bindings_in_closure: FxHashSet<BindingId>,
Copy link
Copy Markdown
Member

@Veykril Veykril Apr 20, 2026

Choose a reason for hiding this comment

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

Comment thread crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs Outdated
@ChayimFriedman2 ChayimFriedman2 added this pull request to the merge queue Apr 20, 2026
Merged via the queue into rust-lang:master with commit cc5bc48 Apr 20, 2026
18 checks passed
@ChayimFriedman2 ChayimFriedman2 deleted the port-infer-call branch April 20, 2026 12:11
@rustbot rustbot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Apr 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants