Skip to content

rewrite-kotlin: extend recipe DSL rewrite { } to { } arity from 2 to 12#7890

Merged
jkschneider merged 1 commit into
mainfrom
kotlin-dsl-arity-12
Jun 3, 2026
Merged

rewrite-kotlin: extend recipe DSL rewrite { } to { } arity from 2 to 12#7890
jkschneider merged 1 commit into
mainfrom
kotlin-dsl-arity-12

Conversation

@jkschneider

Copy link
Copy Markdown
Member

Summary

Adds rewrite overloads + RewriteAdviceN carriers for arities 3 through 12, and registers the corresponding RewriteAdviceN.to FQNs with the K2 IR generation pass.

Why

The DSL's two-parameter ceiling forced anyone generating Kotlin recipes — including LLM agents that synthesize templates from natural-language prompts — to either skip higher-arity patterns or split them into separate templates per arity. A single Arrays.asList(a, b, c)List.of(a, b, c) pattern couldn't be expressed, because:

rewrite { a: Any, b: Any, c: Any -> java.util.Arrays.asList(a, b, c) } to { a, b, c -> java.util.List.of(a, b, c) }

fails to resolve — no 3-param rewrite overload exists. K2 reports none of the following candidates is applicable and the whole recipe(...) { edit { ... } } block fails to compile, taking the valid 1- and 2-arg rewrites in the same edit block down with it.

The agent-tools-bench copilot sweeps that exercise the Kotlin DSL produce templates with arities up to 6 routinely; arities 7–12 are uncommon but cheap to add while the change is fresh, and head off the same failure for String.format(...)-shape patterns where the format-arg count drives the rewrite arity.

What changed

  • RecipeDsl.kt — 9 new rewrite(...) overload pairs (single + vararg) for arities 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, plus matching RewriteAdviceN<P1..Pn, R> carriers with infix fun to(after: (P1..Pn) -> R2). Follows the same pluginRequired() stub pattern as the existing arities 0/1/2.
  • RecipeIrGenerationExtension.ktREWRITE_ADVICE_TO_FQNS switches from a hand-enumerated set of three constants to (0..12).map { "org.openrewrite.RewriteAdvice$it.to" }.toSet().

The IR-walking code in validateBeforeLambda and the to-call dispatch in processRecipeBuilder already read parameter counts off fn.valueParameters generically — the only arity-bound location in the plugin was the FQN allow-list.

Test plan

  • :rewrite-kotlin:compileKotlin — clean against the new arities
  • :rewrite-kotlin:test --tests "*RecipeDsl*" — existing surface tests pass
  • End-to-end: compile an arity-3 recipe in a downstream consumer (moderne-cli's pattern_replace tool) and confirm it produces changes against a target codebase

…o 12

Adds `rewrite` overloads + `RewriteAdviceN` carriers for arities 3 through 12, and registers the corresponding `RewriteAdviceN.to` FQNs with the K2 IR generation pass.

## Why

The DSL's two-parameter ceiling forced agents (and humans) generating recipes for common Java patterns to either skip higher-arity cases or split them into separate templates per arity. A single `Arrays.asList(a, b, c)` -> `List.of(a, b, c)` pattern couldn't be expressed — `rewrite { a: Any, b: Any, c: Any -> java.util.Arrays.asList(a, b, c) }` fails to resolve because no 3-param overload exists. K2 then reports "none of the following candidates is applicable" and the whole `recipe(...) { edit { ... } }` block fails to compile, taking the valid 1- and 2-arg rewrites in the same edit block down with it.

The agent-tools-bench copilot sweeps exercising the Kotlin DSL produce templates with arities up to 6 routinely; arities 7-12 are uncommon but cheap to add now while the change is fresh, and head off the same failure for `String.format(...)`-shape patterns where format-arg count drives the rewrite arity directly.

## What changed

- `RecipeDsl.kt`: nine new `rewrite(...)` overloads (single + vararg) for arities 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, plus matching `RewriteAdviceN<P1..Pn, R>` carriers with `infix fun to(after: (P1..Pn) -> R2)`.
- `RecipeIrGenerationExtension.kt`: `REWRITE_ADVICE_TO_FQNS` switches from a hand-enumerated set to `(0..12).map { "org.openrewrite.RewriteAdvice$it.to" }.toSet()`.

The IR-walking code in `validateBeforeLambda` and the `to`-call dispatch in `processRecipeBuilder` already read parameter counts off `fn.valueParameters` generically, so no further pass changes are needed — the only arity-bound spot was the FQN allow-list.

## Test plan

- [x] `:rewrite-kotlin:compileKotlin` (no errors against the new arities)
- [x] `:rewrite-kotlin:test --tests "*RecipeDsl*"` passes
- [ ] End-to-end: compile an arity-3 recipe in a downstream consumer (moderne-cli's pattern_replace tool) and confirm it produces changes against a target codebase
@github-project-automation github-project-automation Bot moved this to In Progress in OpenRewrite Jun 3, 2026
@jkschneider jkschneider merged commit 64f0542 into main Jun 3, 2026
1 check passed
@jkschneider jkschneider deleted the kotlin-dsl-arity-12 branch June 3, 2026 14:18
@github-project-automation github-project-automation Bot moved this from In Progress to Done in OpenRewrite Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

1 participant