Skip to content

infer: mutating a container through a const reference loops the typer (error[30507]) instead of reporting the const write #3622

Description

@aleksisch

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions