Sylwester Lachiewicz created THRIFT-6197:
--------------------------------------------
Summary: Go generator mishandles typedefs, so aliased structs and
forward-declared typedefs generate code that does not compile
Key: THRIFT-6197
URL: https://issues.apache.org/jira/browse/THRIFT-6197
Project: Thrift
Issue Type: Bug
Components: Go - Compiler
Reporter: Sylwester Lachiewicz
The Go generator does not resolve typedefs to their underlying definition when
it emits field types, so any typedef of a struct, and any typedef used before
it is declared, produces Go code that does not compile.
Verified with the released 0.24.0 compiler; the generated packages were built
with Go 1.27 against the current lib/go/thrift.
h3. Case 1: typedef declared after first use
{code}
struct Bar {
1: optional Foo foo,
}
typedef i32 Foo
{code}
The field takes the underlying type rather than the alias, and the read path
then assigns a *Foo to it:
{code}
type Foo int32
type Bar struct {
Foo *int32 `thrift:"foo,1" db:"foo" json:"foo,omitempty"`
}
{code}
{noformat}
t5601.go:108:11: cannot use &temp (value of type *Foo) as *int32 value in
assignment
{noformat}
This is THRIFT-5601, and the field-type half of it is THRIFT-5489.
h3. Case 2: typedef of a struct in the same file
{code}
struct Inner { 1: required string s }
typedef Inner InnerAlias
struct Outer { 1: optional InnerAlias a }
service Svc { InnerAlias get(1: InnerAlias x) }
{code}
The alias is generated as a pointer type, and the field then adds a second
pointer:
{code}
type InnerAlias *Inner
...
A *InnerAlias `thrift:"a,1" db:"a" json:"a,omitempty"`
{code}
{noformat}
t4901.go:247:8: cannot use &Inner{} (value of type *Inner) as *InnerAlias
value in assignment
t4901.go:248:16: p.A.Read undefined (type *InnerAlias has no field or method
Read)
t4901.go:282:17: p.A.Write undefined (type *InnerAlias has no field or method
Write)
t4901.go:298:10: p.A.Equals undefined (type *InnerAlias has no field or method
Equals)
t4901.go:472:40: cannot use args.X (variable of type *InnerAlias) as InnerAlias
value in argument to p.handler.Get
{noformat}
This is THRIFT-4901, and the service-signature errors are THRIFT-3491.
h3. Case 3: typedef of a struct from an included file
{code}
// Base.thrift
namespace go a.X.c
struct Foo { 1: required string s }
// Child.thrift
namespace go a.Y.c
include "Base.thrift"
typedef Base.Foo Foo
struct Bar { 1: Foo f }
{code}
{noformat}
Child.go:107:8: cannot use &c.Foo{} (value of type *"a/X/c".Foo) as *Foo value
in assignment
Child.go:108:16: p.F.Read undefined (type *Foo has no field or method Read)
Child.go:141:16: p.F.Write undefined (type *Foo has no field or method Write)
{noformat}
This is THRIFT-3037, open since 2015.
h3. Why one ticket
All three come from the same place: the generator decides a field's Go type
from the typedef itself instead of from the type it resolves to, and separately
emits a pointer alias for a struct typedef. THRIFT-5601, THRIFT-5489,
THRIFT-4901, THRIFT-3491 and THRIFT-3037 are five views of that. THRIFT-5463 is
likely the same, though it was not reproduced here.
A fix should cover, at minimum: a typedef declared after use, a typedef of a
struct in the same file, a typedef of a struct across an include, and a typedef
of a container. Note that the THRIFT-5601 fix was reverted once before, so the
regression coverage matters as much as the fix.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)