Repository navigation
fix(analyser): make a type parameter one type across a call, and op= a call like any other ⚖️ - #332
Conversation
…a call like any other ⚖️ Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0ab1afe5aa
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| CallNodes { | ||
| arguments: vec![None, Some(r_value.id)], | ||
| result: None, | ||
| result: Some(l_value.id), |
There was a problem hiding this comment.
Check an Any-typed target before calling a resolved operator
When the target has type Any and only one ordinary operator overload is viable, resolve_call_now promotes the dynamic pick to a resolved call, but expected_of_any cannot emit a check for the first argument because its node is None. For example, fn choose(a: Int, b: Int) => a; let x: Any = "wrong"; x choose= 1; can pass a String directly into the Int parameter, whereas x = choose(x, 1) checks and rejects it. Previously, fully known operand types used dynamic dispatch here, which checked the actual left operand before selecting the overload. Preserve that check when routing augmented assignments through ordinary call constraints; checking the result at writeback does not validate the argument before the function executes.
Useful? React with 👍 / 👎.
…ls 🎯 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. 🎉 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Picking an overload matched each argument against its parameter on its own, so a type parameter could stand for a different type at each position:
max(T, T) -> Tlooked like it took a Float and an Int. The solver's unification got it right for ordinary calls, but three places worked around the picker instead, anda op= bwent through the picker alone. Sobest max= x, withbesta Float andxan Int, passed analysis and failed when it ran, whilebest = max(best, x)was rejected (found in an Advent of Code solution).List<Any>makesTAny), and a value passed forTitself has to fit it, sopush(List<Any>, String)still fitspush(List<T>, T). An argument of typeAnyas a whole agrees with anything, as it's checked where it's passed.a op= bis now a call constraint like any other, asa = op(a, b): one path instead of two (the separate one that picked overloads for known operand types is gone), and an in-place overload such as++=is used where it takes the operands exactly. An operator with no plain counterpart, like a set's-=, is called when no plain operator takes the operands.resolve_overloads, and the eligibility gate for exact in-place picks.Behaviour changes:
best max= xwith a Float and an Int is an analysis error, asmax(best, x)is.a op= bwith a right operand of typeAnyis no longer an error. It works likea = a op b: the operator makes a new value, which is checked where it's written back, so a value that doesn't fit never reaches the target. As nothing says the operand fits, it doesn't change the target in place; a cast to the target's type does.values ++= ["two"]on aList<Int>now reports that no++takesList<Int>, List<String>instead of a type mismatch.The manual's augmented-assignment and casts pages describe the new rules.
🤖 Generated with Claude Code