Skip to content

Write a Go type down over the whole declaration, not its first line - #72

Merged
matt-edmondson merged 1 commit into
mainfrom
claude/nice-davinci-4k08vm
Sep 15, 2026
Merged

matt-edmondson merged 1 commit into
mainfrom
claude/nice-davinci-4k08vm

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #63

What was wrong

CLAUDE.md states the decision: a type parameter on a ClassDeclaration is written down rather than written, because a method on a generic Go type needs the parameters in three places and spelled two ways. The emission only half kept it — the type was declared without parameters, and then a field, a parameter and a result went on spelling them:

// over T : struct, INumber<T>
type Length struct {
	Value T
}

func LengthFromMeter(value T) Length[T] {
	return Create(value)
}

Three things disagree in six lines, and go vet says so: undefined: T, and Length[T] subscripts a type that takes no parameters. Nothing in the text shows either.

What changed

The write-down now reaches the whole declaration rather than its first line, which is the resolution the issue calls the smaller one and the one that matches the stated decision.

  • GoGenerator holds the parameters a type was written down over for as long as that type's members are being written. A type spelled for one of those names is spelled any; a mention of the type itself carries no arguments, because a type declared without parameters takes none.
  • A type parameter on a function is a real one and reaches none of this — func first[T any](values []T) T is unchanged.
  • A type declared inside another is written beside it and is not written over these parameters, so it is emitted before the scope opens.
  • The note above the declaration now says what became of the parameters, so the comment and the file under it agree — which was the issue's actual complaint.

The same input now comes out as:

// Holds one of whatever it was given.
// over T : Stringer
// each of those is any below, and Boxed itself takes none
type Boxed struct {
	held any
}

func BoxedHold(value any) Boxed {
	return Boxed{held: value}
}

func (self Boxed) Held() any {
	return self.held
}

Spelling SpellType, SpellTypeName and their callers is now instance work rather than static, since the answer depends on which declaration is being written.

Tests

  • GoGeneratedSourceCompilesTests grows the case it was missing, which is the point of the issue's Missing coverage section: a struct with a parameterised field, a static factory answering the type, and a driver in the same package that uses both. This is the only way either error is visible — RustGeneratedSourceCompilesTests has had the equivalent all along, which is why Rust's answer was right and this one was not.
  • GoGeneratorTests pins the same shape headlessly, so the answer still holds where no Go toolchain is on the path, plus a companion case asserting a function's own parameters stay generic.

Verified by reverting GoGenerator.cs alone and re-running: both new checks fail (./exemplar.go:101:7: undefined: T, invalid operation: Boxed[T] (Boxed is not a generic type)), and pass with the change. Full suite: 861 passed, 0 failed, with a real Go 1.24 toolchain on the path. Release build of the solution is clean.

CLAUDE.md is updated so the stated decision includes the half that makes it hold.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KGA295odwYgzWvncYaLEu3


Generated by Claude Code

…loses #63) [patch]

A type parameter on a ClassDeclaration is written down rather than written,
which is the decision CLAUDE.md states. The emission only half kept it: the
type was declared without parameters, and then a field, a parameter and a
result went on spelling them — `held T` and `Boxed[T]` beside a `Boxed` that
takes none. That is `undefined: T` and `Boxed is not a generic type`, neither
of which the text shows.

The write-down now reaches the whole declaration. While a type's members are
written, its parameters are names the file does not hold, so a type spelled
for one is spelled `any`, and a mention of the type itself carries no
arguments. A type parameter on a function is a real one and reaches none of
this. The note above the declaration says what became of them, so the comment
and the file under it agree.

GoGeneratedSourceCompilesTests grows the case it was missing — a struct with a
parameterised field, a static factory answering the type, and a driver using
both — so the answer is compiled rather than asserted, which is the only way
either error is visible. GoGeneratorTests pins the same shape headlessly, for
where no Go toolchain is on the path.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KGA295odwYgzWvncYaLEu3
@sonarqubecloud

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit 96a3c9a into main Sep 15, 2026
13 checks passed
@matt-edmondson
matt-edmondson deleted the claude/nice-davinci-4k08vm branch September 15, 2026 13:55
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.

Go writes a generic type it did not declare, so the generated package does not compile

2 participants