Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update for Go 1.19 and support generics. #49

Merged
merged 20 commits into from
Jan 17, 2024

Conversation

paddycarver
Copy link
Contributor

Update go.mod to indicate support for Go 1.19.

Add support for generic interfaces, i.e. interfaces that accept a type parameter.

For example, you can now have this kind of interface:

type Interface[Kind any] interface {
	DoTheThing() Kind
}

and if you run impl 's StringImpl' 'Interface[string] it will generate the following code:

func (s StringImpl) DoTheThing() string {
	// normal impl stub here
}

Fixes #44.

Copy link
Owner

@josharian josharian left a comment

Choose a reason for hiding this comment

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

I haven't looked at this in any depth, just took a superficial pass. Gotta return to family now. Will look more carefully once the first round trip is complete. :)

go.mod Outdated Show resolved Hide resolved
go.mod Show resolved Hide resolved
impl.go Outdated Show resolved Hide resolved
impl.go Outdated Show resolved Hide resolved
impl.go Outdated Show resolved Hide resolved
impl.go Outdated Show resolved Hide resolved
impl.go Outdated Show resolved Hide resolved
@paddycarver
Copy link
Contributor Author

Thanks for the review! I'll follow up on it when the chosen fam isn't making cookies with me, so I'll likely get to it this week. It's your repo so I'll do whatever you like, just want to explain a couple of the choices I made you raised questions about to make sure the suggested fix is actually what you want. 🙂

I am using this in anger locally, and while I think there are some iterative improvements that could happen (I'd love to be able to inject the types into the generated comments! Though I think some design work there may be needed...) it's been awesome to have working. (Though I gotta follow up with a highly suspect PR to vim-go as well. 😬)

Enjoy the family time! This will keep. 🙂

@josharian
Copy link
Owner

just want to explain a couple of the choices I made you raised questions about to make sure the suggested fix is actually what you want.

Absolutely. Code review is an iterative process in which multiple people collectively try to write clear, simple code. :)

This will keep.

Indeed. :) Happy holidays!

go.mod Outdated
golang.org/x/tools v0.4.0
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
)
require golang.org/x/tools v0.4.0
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think this is just the result of running go mod tidy on main. If you get something different, please shout?

@paddycarver
Copy link
Contributor Author

Think I resolved all the comments. Sorry, this has evolved a bit (I realized my handling of parsing out the type params was a bit too naive and switched it up for proper AST parsing) but hopefully I've commented things well enough that it's easier to follow, and hopefully the expansion makes it more robust.

@josharian
Copy link
Owner

Hi! Just letting you know I haven't forgotten about this. :)

@paddycarver
Copy link
Contributor Author

Appreciate the update, but also no worries! You set clear expectations at the outset that it would get reviewed when you had time, and I'm content using my fork (and giving it some mileage in anger, seeing if I can break it/if I missed anything), so no pressure here. 😄

@nieomylnieja
Copy link

a year passed, is the project abandoned?

@josharian
Copy link
Owner

josharian commented Jan 14, 2024

is the project abandoned?

No, its maintainer is just pretty seriously distractible. But amenable to gentle pings.

I'll aim to take a look sometime over the coming weeks.

Do you need this particular improvement?

@nieomylnieja
Copy link

@josharian I'd really appreciate it, although, as @paddycarver stated, not a blocker, I've built it with his changes :)

@paddycarver
Copy link
Contributor Author

It happens to all of us!

I'll take a look at the conflicts here and see if I can resolve them quickly, but I know this turned into more of A Thing than I had originally expected. If it's too invasive/too complicated, I'd love that feedback, and I'll see if I can find a less-technically-correct-but-easier-to-implement version.

I have been using the version of impl this PR represents for about a year now, with some pretty heavy generics usage, and it seems to be working for me. vim-go requires some updates to allow quoting the input, but that's not a problem for this repo. 😁

Update go.mod to indicate support for Go 1.19.

Add support for generic interfaces, i.e. interfaces that accept a type
parameter.

For example, you can now have this kind of interface:

```go
type Interface[Kind any] interface {
	DoTheThing() Kind
}
```

and if you run `impl 's StringImpl' 'Interface[string]` it will generate
the following code:

```go
func (s StringImpl) DoTheThing() string {
	// normal impl stub here
}
```

Fixes josharian#44.
Turns out we need to use 1.18 because we have generics in our testdata
package now, meaning `go test` won't run unless our go.mod is set to
1.18.
Add a comment documenting the purpose of parseTypeParams.

Add tests exercising parseTypeParams.

Simplify parseTypeParams by using strings.Cut instead of index math.
Instead of parsing generic types using string manipulation, parse them
using the go/parse package to get the AST.

Rather than bespokely handling the AST stuff everywhere, pull it out
into a recursive helper function (we need it to be recursive because
generics allow for some pretty complex AST constructs).

Rather than passing around a type ID and its params everywhere, create a
Type struct that contains both.

Pull our type param matching out into a helper function.
Add a test for the interface assertion that was failing.
Had a lingering type assertion that should have used the ID from the
parsed AST type instead.

Also noticed that we were losing the package names on the type
parameters, which would lead to potentially-subtle incorrect results; we
should always be using the package if the user submits it. This requires
an update to typeFromAST to preserve the package, and then updating
findInterface to strip the package off when dealing with qualified
interfaces.
@paddycarver
Copy link
Contributor Author

Think I got the conflicts resolved. 😄 Tests still pass.

Copy link
Owner

@josharian josharian left a comment

Choose a reason for hiding this comment

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

I pushed a handful of fixes / nitpicks. Just a few open questions...

impl.go Outdated
}
prefix := "["
if specType.Len != nil {
prefix += specType.Len.(*ast.BasicLit).Value
Copy link
Owner

Choose a reason for hiding this comment

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

Does this work when the type is [...]T?

impl.go Outdated
return Type{}, err
}
return Type{
ID: "map[" + key.String() + "]" + value.String(),
Copy link
Owner

Choose a reason for hiding this comment

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

in other places you're careful to only touch the ID, not the params, of subtypes but here, the params get clobbered. makes me feel unsure i understand what this code is doing.

impl.go Outdated
}

func typeFromAST(in ast.Expr) (Type, error) {
switch specType := in.(type) {
Copy link
Owner

Choose a reason for hiding this comment

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

is there any way to avoid rebuilding an entire node printing infrastructure? it'd be nice to somehow use go/format or go/printer.

impl.go Outdated
// func Foo[Param1, Param2](context.Context, Param1) Param2
// We're gonna need to complicate everything to support that
// construction, and we don't actually need the deconstructed
// bits, so we're just... not going to deconstruct it at all.
Copy link
Owner

Choose a reason for hiding this comment

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

can we use go/printer or go/format here? this is an awful lot of new code.

@josharian
Copy link
Owner

Oops. Of course, I can't push changes to your fork. The changes I added are in the generics branch on this repo: main...generics

@paddycarver
Copy link
Contributor Author

2024-01-16 21_48_13-Update for Go 1 19 and support generics  by paddycarver · Pull Request #49 · jos

Hmmm, you should be able to push to my branch.... I can pull those edits in when I get a chance if we can't figure out how to give you push access.

Since I opened this PR I became a dad, so while your questions are eminently fair, I don't know the answers without diving into it again and reloading a bunch of context, and that's a harder thing to achieve now than it was before. 😅 I'll put it on my to-do list, but please feel free to nudge me (anyone reading this) with a ping if it seems like I may have forgotten about it.

@josharian
Copy link
Owner

Since I opened this PR I became a dad

Congrats! Go be a father, I'll just wrap this up now.

The code can in fact be considerably simplified. I'll do that and then merge.

@josharian josharian merged commit e6bec82 into josharian:main Jan 17, 2024
1 check passed
@nieomylnieja
Copy link

Thanks a lot for this one @paddycarver @josharian <3

@paddycarver
Copy link
Contributor Author

Thank you! I'm glad you knew of a simpler way, that part of the PR is where I looked up and realized this might've gotten away from me a bit, so I appreciate the pointer to where the reusable functionality lives. 😀

@paddycarver paddycarver deleted the generics branch January 19, 2024 20:01
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.

Add support for generics
3 participants