mirror of
https://github.com/burrowers/garble
synced 2026-06-06 15:24:28 +00:00
0b1cbdf300
Field names are obfuscated with the identity of their containing struct as
a salt, which must be stable across packages so that converting between
identical struct types keeps working. Hashing field types into that salt
breaks for an anonymous struct{F Q} returned by a generic function: the
declaring package hashes the type parameter Q while a consuming package only
sees an instantiation such as struct{F int}, with no origin to recover Q.
The previous commit fixed this for a named generic field type, but not for
a bare type parameter.
Drop field types and fold in the field position instead, which is stable
across instantiations and conversions yet still keeps reordered structs
distinct. This only makes more fields share a salt, which is harmless as
non-identical structs are never converted between one another.
Since field types are no longer hashed, the salt never recurses into the
rest of the type graph, so the type-argument NOTE(garble) tweak to the
*types.Named case added by the previous commit is now dead code; revert it
to keep the bundled hasher faithful to upstream.
148 lines
2.7 KiB
Plaintext
148 lines
2.7 KiB
Plaintext
exec garble build
|
|
! binsubstr main$exe ${WORK} 'garble_main.go' 'GenericFunc' 'GenericVector' 'PredeclaredSignedInteger' 'StringableSignedInteger' 'CombineEmbeds' 'GenericParam'
|
|
-- go.mod --
|
|
module test/main
|
|
|
|
go 1.23
|
|
-- garble_main.go --
|
|
package main
|
|
|
|
import "test/main/lib"
|
|
|
|
func main() {
|
|
GenericFunc[int, int](1, 2)
|
|
var _ GenericVector[int]
|
|
|
|
g1 := GenericGraph[string]{Content: "Foo"}
|
|
g1.Edges = make([]GenericGraph[string], 1)
|
|
|
|
g2 := GenericGraph[*[]byte]{Content: new([]byte)}
|
|
g2.Edges = make([]GenericGraph[*[]byte], 1)
|
|
|
|
var ga genericAlias
|
|
ga.list = nil
|
|
var gan genericAliasNamed
|
|
gan.list = nil
|
|
|
|
e := lib.Entry[string, int]{Key: "foo", Data: 123}
|
|
r := lib.Load[string, int](e)
|
|
_ = r.Data
|
|
|
|
_ = lib.SelectWhere.Users.Name
|
|
_ = lib.SelectIdentity.Value
|
|
|
|
// A plain struct is convertible to a generic instantiation whose origin
|
|
// underlying uses a type parameter; both fields must obfuscate alike.
|
|
_ = lib.Box[int](struct{ Contents int }{})
|
|
}
|
|
|
|
func GenericFunc[GenericParamA, B any](x GenericParamA, y B) {}
|
|
|
|
type GenericVector[GenericParamT any] []GenericParamT
|
|
|
|
type GenericGraph[T any] struct {
|
|
Content T
|
|
Edges []GenericGraph[T]
|
|
}
|
|
|
|
type PredeclaredSignedInteger interface {
|
|
int | int8 | int16 | int32 | int64
|
|
}
|
|
|
|
type StringableSignedInteger interface {
|
|
~int | ~int8 | ~int16 | ~int32 | ~int64
|
|
|
|
String() string
|
|
}
|
|
|
|
type CombineEmbeds interface {
|
|
string | int
|
|
|
|
interface{ EmbeddedMethod() }
|
|
RegularMethod()
|
|
}
|
|
|
|
type Slice[T any] []T
|
|
|
|
func sliceOfPointer() Slice[*any] {
|
|
return []*any{}
|
|
}
|
|
|
|
type Map[K, V comparable] map[K]V
|
|
|
|
var _ = Map[string, struct{}]{}
|
|
|
|
type Result[T any] interface {
|
|
AsResult() Result[T]
|
|
Redirect(struct { ret T })
|
|
}
|
|
|
|
type AsyncResult[oldT, newT any] struct {}
|
|
|
|
func (w *AsyncResult[oldT, newT]) AsResult() Result[newT] {
|
|
return w
|
|
}
|
|
|
|
func (w *AsyncResult[oldT, newT]) Redirect(struct {ret newT}) {}
|
|
|
|
type genericAlias = generic[int]
|
|
type generic[T any] struct {
|
|
list *T
|
|
}
|
|
|
|
type genericAliasNamed genericAlias
|
|
|
|
func byKeys[T any](m map[string]T) []struct {
|
|
K string
|
|
V T
|
|
} {
|
|
vs := make([]struct {
|
|
K string
|
|
V T
|
|
}, 0, len(m))
|
|
for k, v := range m {
|
|
vs = append(vs, struct {
|
|
K string
|
|
V T
|
|
}{k, v})
|
|
}
|
|
return vs
|
|
}
|
|
|
|
var _ = byKeys(map[string]int{"one": 1})
|
|
-- lib/lib.go --
|
|
package lib
|
|
|
|
type Result[Data any] struct {
|
|
Data Data
|
|
}
|
|
|
|
type Entry[Key ~string, Data any] struct {
|
|
Key Key
|
|
Data Data
|
|
}
|
|
|
|
func Load[Key ~string, Data any](e Entry[Key, Data]) Result[Data] {
|
|
return Result[Data]{Data: e.Data}
|
|
}
|
|
|
|
type Filter[Q any] struct{ Name Q }
|
|
|
|
func Where[Q any]() struct {
|
|
Users Filter[Q]
|
|
} {
|
|
return struct{ Users Filter[Q] }{}
|
|
}
|
|
|
|
var SelectWhere = Where[int]()
|
|
|
|
func Identity[Q any]() struct {
|
|
Value Q
|
|
} {
|
|
return struct{ Value Q }{}
|
|
}
|
|
|
|
var SelectIdentity = Identity[int]()
|
|
|
|
type Box[T any] struct{ Contents T }
|