Calling a mutating generic (push) through a const reference to a container makes type inference oscillate until it gives up, instead of reporting can't write to a constant value.
Repro
options gen2
[export]
def main {
var a : array<int>
let r & = a
r |> push(5)
}
error[30507]: type inference exceeded maximum allowed number of passes (50)
this is likely due to a loop in the type system
Same with a struct field container, and with the reference type spelled out (so it is not auto-inference of &):
struct Bag { xs : array<int> }
var b : Bag
let r : Bag const& = b
r.xs |> push(5) // error[30507]
A scalar behaves correctly — the const write is diagnosed:
var i = 1
let r & = i
r = 5 // error[30952]: can't write to a constant value, int const& = int const
What oscillates
With options log_infer_passes the call site flips between the generic name and its instance on every pass, forever:
pass N : builtin::push(r,5)
pass N+1 : __::builtin`push`4379756157886752001(r,5)
pass N+2 : builtin::push(r,5)
...
The instance is generated with a non-const parameter (as the -const contract on array<auto(numT)> demands):
// from generic builtin::push(Arr: array<auto(numT)> -const; value: numT const ==const -#): auto
def private builtin`push`4379756157886752001(var Arr:array<int aka numT> explicit; value:int aka numT const ==const) : auto
The argument r is array<int> const&, so the instance cannot match; resolution falls back to the generic name, re-instantiates, and the cycle repeats. reportAstChanged fires on every pass, so the pass limit is the only thing that stops it.
Expected: a diagnostic at the call site — can't write to a constant value (30952) or "no matching function" — not a pass-limit error that points at the type system rather than the user's code.
Environment
- master, Linux, RelWithDebInfo
- Found while investigating the
let & = / -const interaction in visitLet (unrelated to that fix; reproduces with a plain local and no unsafe)
Calling a mutating generic (
push) through a const reference to a container makes type inference oscillate until it gives up, instead of reportingcan't write to a constant value.Repro
Same with a struct field container, and with the reference type spelled out (so it is not auto-inference of
&):A scalar behaves correctly — the const write is diagnosed:
What oscillates
With
options log_infer_passesthe call site flips between the generic name and its instance on every pass, forever:The instance is generated with a non-const parameter (as the
-constcontract onarray<auto(numT)>demands):The argument
risarray<int> const&, so the instance cannot match; resolution falls back to the generic name, re-instantiates, and the cycle repeats.reportAstChangedfires on every pass, so the pass limit is the only thing that stops it.Expected: a diagnostic at the call site —
can't write to a constant value(30952) or "no matching function" — not a pass-limit error that points at the type system rather than the user's code.Environment
let & =/-constinteraction invisitLet(unrelated to that fix; reproduces with a plain local and nounsafe)