Skip to content

Fix: CT parameter name uniqueness in CancellationToken overload generation#339

Merged
sergey-tihon merged 2 commits intorepo-assist/feat-cancellationtoken-issue-212-2026-03-23-448c1cde90ec7d95from
copilot/sub-pr-336
Mar 25, 2026
Merged

Fix: CT parameter name uniqueness in CancellationToken overload generation#339
sergey-tihon merged 2 commits intorepo-assist/feat-cancellationtoken-issue-212-2026-03-23-448c1cde90ec7d95from
copilot/sub-pr-336

Conversation

Copy link
Contributor

Copilot AI commented Mar 23, 2026

If an OpenAPI spec defines a parameter named cancellationToken, the generated overload would emit two parameters with the same name — one from the spec and one for the injected CancellationToken.

Changes

  • Track used parameter names: The parameter-fold now returns the usedNames set alongside providedParameters instead of discarding it with |> snd
  • Unique CT parameter naming: The injected CT parameter resolves to the first unused name in the sequence cancellationTokencancellationToken1cancellationToken2 → …, matching the existing UniqueNameGenerator convention
  • Position-based extraction unaffected: invokeCode already extracts the CT argument by position (last in args), so it correctly handles the CT regardless of the name chosen
let usedNames, providedParameters =
    ((Set.empty, []), orderedParameters)
    ||> List.fold(fun (names, parameters) current -> ...)
    |> fun (names, ps) -> names, List.rev ps

let ctParamName =
    Seq.initInfinite(fun i -> if i = 0 then "cancellationToken" else $"cancellationToken{i}")
    |> Seq.find(fun n -> not(Set.contains n usedNames))

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

…I params named 'cancellationToken'

Co-authored-by: sergey-tihon <1197905+sergey-tihon@users.noreply.github.com>
Agent-Logs-Url: https://github.com/fsprojects/SwaggerProvider/sessions/7d588ec7-c4df-4a6c-89f8-9c13c2472d29
Copilot AI changed the title [WIP] [WIP] Address feedback on CancellationToken support for OpenApiClientProvider Fix: CT parameter name uniqueness in CancellationToken overload generation Mar 23, 2026
Copilot AI requested a review from sergey-tihon March 23, 2026 22:26
@sergey-tihon sergey-tihon marked this pull request as ready for review March 25, 2026 07:06
Copilot AI review requested due to automatic review settings March 25, 2026 07:06
@sergey-tihon sergey-tihon merged commit ee4db30 into repo-assist/feat-cancellationtoken-issue-212-2026-03-23-448c1cde90ec7d95 Mar 25, 2026
8 checks passed
@sergey-tihon sergey-tihon deleted the copilot/sub-pr-336 branch March 25, 2026 07:06
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a codegen edge case in the v3 OpenAPI client type provider where injecting a CancellationToken overload could produce duplicate parameter names when the OpenAPI spec already defines a cancellationToken parameter.

Changes:

  • Preserve the usedNames set from the OpenAPI parameter fold instead of discarding it.
  • Generate a unique injected CT parameter name (cancellationToken, cancellationToken1, cancellationToken2, …) that avoids collisions with OpenAPI parameters.
  • Keep CancellationToken extraction position-based in invokeCode (so behavior doesn’t depend on the chosen parameter name).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +180 to 191
// Find a unique name for the CancellationToken parameter that doesn't
// conflict with any OpenAPI parameter already in use.
let ctParamName =
Seq.initInfinite(fun i ->
if i = 0 then
"cancellationToken"
else
$"cancellationToken{i}")
|> Seq.find(fun n -> not(Set.contains n usedNames))

let ctParam = ProvidedParameter(ctParamName, typeof<Threading.CancellationToken>)
providedParameters @ [ ctParam ]
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a regression test for the name-collision scenario this change fixes (an OpenAPI parameter named cancellationToken). Without a test that loads/generates a client from such a spec and asserts the generated overload compiles (and/or that the injected CT param gets a suffixed name), this could regress unnoticed.

Copilot uses AI. Check for mistakes.
Comment on lines +181 to 189
// conflict with any OpenAPI parameter already in use.
let ctParamName =
Seq.initInfinite(fun i ->
if i = 0 then
"cancellationToken"
else
$"cancellationToken{i}")
|> Seq.find(fun n -> not(Set.contains n usedNames))

Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This introduces a second ad-hoc unique-name generator (Seq.initInfinite + Set.contains) even though the codebase already has UniqueNameGenerator with the same suffixing convention (and case-insensitive uniqueness). Consider factoring this into a shared helper (or reusing UniqueNameGenerator by seeding it with usedNames) to avoid future divergence in how “unique names” are defined.

Suggested change
// conflict with any OpenAPI parameter already in use.
let ctParamName =
Seq.initInfinite(fun i ->
if i = 0 then
"cancellationToken"
else
$"cancellationToken{i}")
|> Seq.find(fun n -> not(Set.contains n usedNames))
// conflict with any OpenAPI parameter already in use, using the shared
// UniqueNameGenerator to keep suffixing and case sensitivity consistent.
let nameGen = UniqueNameGenerator()
usedNames |> Set.iter (fun n -> nameGen.Claim n |> ignore)
let ctParamName = nameGen.Claim "cancellationToken"

Copilot uses AI. Check for mistakes.
Copilot AI added a commit that referenced this pull request Mar 25, 2026
…dering + uniqueness improvements from this PR

Both branches fixed CT name uniqueness independently. This branch additionally
fixes the parameter ordering bug (CT must precede optional params). The merge
keeps the more complete implementation (buildProvidedParameters helper, two-pass
required/optional split, ctArgIndex insertion) and discards the simpler
base-branch approach that still appended CT after optional params.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants