Skip to content

add support for time.Time#25

Merged
emidoots merged 3 commits into
hexops:mainfrom
michaellzc:08-08-add_support_for_time.Time
Aug 8, 2023
Merged

add support for time.Time#25
emidoots merged 3 commits into
hexops:mainfrom
michaellzc:08-08-add_support_for_time.Time

Conversation

@michaellzc

@michaellzc michaellzc commented Aug 8, 2023

Copy link
Copy Markdown
Contributor

related #11

TODO

  • support *time.Time

I am not sure what is the best way to render *time.Time:

✅ generic (this is not supported given the current target Go version is 1.15 in go.mod)

// an exported func from valast
func Ptr[V any](v V) *V {
	return &v
}

// render as
valast.Ptr(time.Date(...))

❌ inline anonymous fn

// render as
func(t time.Time) *time.Time { return &t }(time.Date(...))

thoughts?

  • By selecting this checkbox, I agree to license my contributions to this project under the license(s) described in the LICENSE file, and I have the right to do so or have received permission to do so by an employer or client I am producing work for whom has this right.

Test plan

all tests passed

go test                                                                                                                                                                                                                                                                                                       13:00:24
PASS
ok      github.com/hexops/valast        0.960s

Tested this change with workspace in https://github.com/sourcegraph/controller, and it seems to work just fine. It was able to automatically wrap *time.Time to Ptr(time.Date()) and valast pkg was imported properly in _test.go file as well.

@emidoots

emidoots commented Aug 8, 2023

Copy link
Copy Markdown
Member

Thanks for sending @michaellzc - I'd be happy to merge this.

I can offer a few options:

  1. I can merge this as-is, without support for *time.Time - I'm content with doing that.
  2. You can implement *time.Time using the generic Ptr approach, I would be happy to have that change and require the latest-and-greatest Go version in go.mod.

I'll let you decide which one you want to go for depending on how much time you want to spend here.

@michaellzc

michaellzc commented Aug 8, 2023

Copy link
Copy Markdown
Contributor Author

2. You can implement *time.Time using the generic Ptr approach, I would be happy to have that change and require the latest-and-greatest Go version in go.mod.

😛 I need *time.Time for my own use case, so I'll continue on option 2 with a twist:

// an exported func from autogold
func TimePtr(t time.Time) *time.Time {
	return &t
}

// render as
autogold.TimePtr(time.Date(...))

SomethingPtr is quite a common pattern in many Go projects, e.g., k8s.io/utils/pointer, github.com/aws/jsii-runtime-go.

it's not elegant, but we can avoid breaking backward compatibility unless we have to.

@emidoots

emidoots commented Aug 8, 2023

Copy link
Copy Markdown
Member

@michaellzc I'm not a fan of that TimePtr change - that feels awkward and a bit cluttery of the API space. I have zero qualms about breaking compatibility, so please do the Ptr approach unless there's something that makes that much more difficult

@michaellzc

Copy link
Copy Markdown
Contributor Author

nice, let's do the Ptr then

@michaellzc michaellzc force-pushed the 08-08-add_support_for_time.Time branch 5 times, most recently from d12b5d9 to 60af2cf Compare August 8, 2023 20:00
@michaellzc michaellzc marked this pull request as ready for review August 8, 2023 20:03
@michaellzc michaellzc force-pushed the 08-08-add_support_for_time.Time branch from 60af2cf to e44ce5a Compare August 8, 2023 20:06
@michaellzc michaellzc changed the title add support for time.Time add support for time.Time Aug 8, 2023
Comment thread valast.go Outdated
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

Merging #25 (1c77fe9) into main (5de3f44) will increase coverage by 1.02%.
The diff coverage is 97.14%.

❗ Your organization is not using the GitHub App Integration. As a result you may experience degraded service beginning May 15th. Please install the Github App Integration for your organization. Read more.

@@            Coverage Diff             @@
##             main      #25      +/-   ##
==========================================
+ Coverage   74.36%   75.38%   +1.02%     
==========================================
  Files           6        7       +1     
  Lines         745      780      +35     
==========================================
+ Hits          554      588      +34     
- Misses        144      145       +1     
  Partials       47       47              
Files Changed Coverage Δ
ptr.go 0.00% <0.00%> (ø)
valast.go 82.22% <100.00%> (+1.45%) ⬆️

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@emidoots

emidoots commented Aug 8, 2023

Copy link
Copy Markdown
Member

@michaellzc not sure if you'd be up for it (fine if not) but maybe you could remove valast.Addr in favor of valast.Ptr? It's doing the same thing but results in uglier ASTs as it doesn't use generics:

valast/valast.go

Lines 151 to 167 in 5de3f44

// Addr returns a pointer to the given value.
//
// It is the only way to create a reference to certain values within a Go expression,
// for example since &"hello" is illegal, it can instead be written in a single expression as:
//
// valast.Addr("hello").(*string)
func Addr(v interface{}) interface{} {
vv := reflect.ValueOf(v)
// Create a slice with v in it so that we have an addressable value.
sliceType := reflect.SliceOf(vv.Type())
slice := reflect.MakeSlice(sliceType, 1, 1)
if v != nil {
slice.Index(0).Set(vv)
}
return slice.Index(0).Addr().Interface()
}

No worries if not, just let me know what you decide & I'll merge either way.

Comment thread valast.go
Comment on lines -506 to +513
AST: &ast.TypeAssertExpr{
X: &ast.CallExpr{
Fun: &ast.SelectorExpr{
X: ast.NewIdent("valast"),
Sel: ast.NewIdent("Addr"),
},
Args: []ast.Expr{elem.AST},
AST: &ast.CallExpr{
Fun: &ast.SelectorExpr{
X: ast.NewIdent("valast"),
Sel: ast.NewIdent("Ptr"),
},
Type: ptrType.AST,
Args: []ast.Expr{elem.AST},

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

👀

Comment thread valast.go
Comment on lines -552 to +556
AST: &ast.TypeAssertExpr{
X: &ast.CallExpr{
Fun: &ast.SelectorExpr{
X: ast.NewIdent("valast"),
Sel: ast.NewIdent("Addr"),
},
Args: []ast.Expr{elem.AST},
AST: &ast.CallExpr{
Fun: &ast.SelectorExpr{
X: ast.NewIdent("valast"),
Sel: ast.NewIdent("Ptr"),
},
Type: ptrType.AST,
Args: []ast.Expr{elem.AST},

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

👀

@michaellzc

Copy link
Copy Markdown
Contributor Author

@michaellzc not sure if you'd be up for it (fine if not) but maybe you could remove valast.Addr in favor of valast.Ptr? It's doing the same thing but results in uglier ASTs as it doesn't use generics:

valast/valast.go

Lines 151 to 167 in 5de3f44

// Addr returns a pointer to the given value.
//
// It is the only way to create a reference to certain values within a Go expression,
// for example since &"hello" is illegal, it can instead be written in a single expression as:
//
// valast.Addr("hello").(*string)
func Addr(v interface{}) interface{} {
vv := reflect.ValueOf(v)
// Create a slice with v in it so that we have an addressable value.
sliceType := reflect.SliceOf(vv.Type())
slice := reflect.MakeSlice(sliceType, 1, 1)
if v != nil {
slice.Index(0).Set(vv)
}
return slice.Index(0).Addr().Interface()
}

No worries if not, just let me know what you decide & I'll merge either way.

refactor from Addr to Ptr is done.

Trying to understand what is going in AddrInterface see if we can get rid of it as well

@michaellzc

michaellzc commented Aug 8, 2023

Copy link
Copy Markdown
Contributor Author

@michaellzc not sure if you'd be up for it (fine if not) but maybe you could remove valast.Addr in favor of valast.Ptr? It's doing the same thing but results in uglier ASTs as it doesn't use generics:

valast/valast.go

Lines 151 to 167 in 5de3f44

// Addr returns a pointer to the given value.
//
// It is the only way to create a reference to certain values within a Go expression,
// for example since &"hello" is illegal, it can instead be written in a single expression as:
//
// valast.Addr("hello").(*string)
func Addr(v interface{}) interface{} {
vv := reflect.ValueOf(v)
// Create a slice with v in it so that we have an addressable value.
sliceType := reflect.SliceOf(vv.Type())
slice := reflect.MakeSlice(sliceType, 1, 1)
if v != nil {
slice.Index(0).Set(vv)
}
return slice.Index(0).Addr().Interface()
}

No worries if not, just let me know what you decide & I'll merge either way.

refactor from Addr to Ptr is done.

Trying to understand what is going in AddrInterface see if we can get rid of it as well

possible solution for future reference:

// It doesn't work for all cases yet
func InterfacePtr[V any, I any](v *V, pointerToType *I) *I {
	sliceType := reflect.SliceOf(reflect.TypeOf(pointerToType).Elem())
	slice := reflect.MakeSlice(sliceType, 1, 1)
	if v != nil {
		slice.Index(0).Set(reflect.ValueOf(v))
	}
	return slice.Index(0).Addr().Interface().(*I)
}

I may find some existing problems with AddrInterface, so I am going to leave it as it is.

  1. Many tests are not setting options to ExportedOnly, and the rendered code contains a private struct foo from internal/test pkg.

  2. Rendered output of TestPointers/interface is not valid Go

// input
v := test.Bazer(test.NewBaz())
&v

// output
valast.AddrInterface(test.Bazer{&test.Baz{
	Bam:  (1.34 + 0i),
	zeta: &test.foo{bar: "hello"},
}},
	(*test.Bazer)(nil)).(*test.Bazer)

I don't think you can do test.Bazer{&test.Baz{}} with an interface in Go (Bazer is an interface)

@michaellzc michaellzc requested a review from emidoots August 8, 2023 21:55
@emidoots emidoots merged commit 465506f into hexops:main Aug 8, 2023
@michaellzc michaellzc deleted the 08-08-add_support_for_time.Time branch August 8, 2023 22:02
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