Issue #1028: Decision: does a method lend a by-value data parameter (ADR-277 D17), for trait methods only or for every method?

Open and answer this issue on GitHub.

ready · opened 2026-10-31 · updated 2026-11-03 · 2 comments

The question

ADR-277 D17 (#1012, option E) says a trait method’s keeps column covers every by-value parameter, code or data, and that “by value no longer means kept”. Brief b1012c was meant to build the data half. It stopped (Result: blocked, docs/briefs/b1012c-trait-column-data.md.report.md) because the column is not what refuses the lending:

Probe (an inherent method with an empty keeps), refused with NK2105:

struct Count { base: i64 }
impl Count { fn size(ref self, text: String) -> i64 sync { return self.base + text.len() } }
fn main() { let c = Count { base: 1 }; let own = f"{c.base}x"; println(c.size(own)); println(own) }

The same probe under a trait bound is refused the same way. With the keeps.rs seed removed, the ledger column of Measure::size becomes empty, but nothing lowers differently.

Alternatives

1. Lift the exclusion for trait methods and their impls only.

2. Lift it for every method.

3. Neither for now. D17 then holds for code parameters only, and gets amended to say so.

Recommendation

2, built in two steps:

  1. Trait methods and impls first, behind the existing receiver check: the column decides, so #1012 can go on.
  2. Inherent methods next, as their own brief, with the lowered-file churn in one commit.

The end state is one rule for every callee, as ADR-094 D2 says. Option 1 as the end state would write a distinction into the language that only the build history explains.

After the decision

An amendment line in ADR-277 D17 (and ADR-094 D2 if 2), and a To build list on #1012 (and a new issue for the inherent step if 2). b1012c is out of the batch until then.

Comments

keywan-ghadami, 2026-10-31

Answers to the four follow-up questions

I checked each answer against today’s code on develop. A probe was run where the code alone did not settle the question.

1. Resolving the method target: is the contract known before lending is decided?

The checker resolves every method call statically and writes the result down. The emitter decides lending later, from that record.

2. Do an inherent method and a trait method with the same behaviour lend the same way? Special cases?

The rule is the same, but which column decides differs, and that difference is the point of D17.

3. Rust lowering: are the references right, and can Rust host callers and existing packages cope?

4. Regressions: which methods change their calling convention, and can it be tested completely?

The recommendation does not change: option 2, built in two steps.


Generated by Claude Code

keywan-ghadami, 2026-10-31

Decided (owner, 2026-10-31): option 2, with additional tests.

Every method lends a by-value data parameter its body only reads, as every free function does (ADR-094 D2). The receiver exclusion in lends_with / emit_arg_only_read and the comment that justifies it go away. In the end there is one rule for every callee.

Built in two steps, as recommended:

  1. Trait methods and their impls. The trait’s keeps column decides for every impl, because an impl must match the trait’s Rust signature. This unblocks b1012c / #1012.
  2. Inherent methods, as their own issue and brief. The lowered-file churn goes in one commit: up to 27 parameters in 22 methods in tools/, none in examples or package ledgers.

Additional tests (owner’s condition). Each step brings its own tests/compiler/ programs. As a minimum:

Next: an amendment line in ADR-277 D17 and ADR-094 D2, the To build list for step 1 on #1012, and a new issue for step 2 (label ready). b1012c goes back into the batch after that.


Generated by Claude Code

Back to Open Issues