Skip to content

Canonicalize foreach range-source/induction-variable sugar to a dedicated induction variable #5

Description

@Garfee023

Summary

The foreach sugar form

foreach a(lb:ub[:step]) { ... }

is desugared at parse time to foreach a = a(lb:ub[:step]). This gives a single name a two distinct meanings:

  1. the with-declared bounded variable (a), which supplies the loop bounds; and
  2. the induction variable visible inside the loop body.

Problem

The two meanings are currently disambiguated by convention rather than by structure:

  • the bound is read from the type system (the BoundedType upper bound), while
  • the value in the body resolves to the induction variable via scope shadowing.

This works today, but it is fragile. Any future feature that needs to read the bound of a from inside the loop body would silently resolve to the induction variable instead, because that is what the name a maps to in that scope.

Proposal

Canonicalize (normalize) the sugar form into an explicit, fresh induction variable:

foreach __iv_a = a(lb:ub[:step]) { ... }

and rewrite references to a inside the loop body to __iv_a. This makes the separation structural: the source variable a always denotes the bound, and __iv_a always denotes the induction variable.

This mirrors what code generation already does at emit time (it introduces an __iv_<name> remapping for with-in matchers). The proposal is to lift that remapping into AST normalization so that every consumer (all backends, and any future passes) benefits uniformly instead of each one re-deriving the same convention.

Example

with {i} in [12] {
  foreach i(2:) {
    // inside the body, i is the induction variable
  }
  // outside the loop, i(-2) reads the bound (12) -> 10
}

Scope

  • General language/normalization feature; applies to all backends.
  • A lowering/normalization refactor with no observable behavior change for existing programs.

Acceptance criteria

  • foreach a(...) and foreach c = a(...) both lower to an explicit __iv_<name> induction variable.
  • Body references to the source name are rewritten to the induction variable.
  • Negative-index bound accesses such as a(-1) continue to resolve against the bounded type.
  • Existing tests pass unchanged.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions