From 0b1fa64a92016ee91fdaf2f6106578f0c5908484 Mon Sep 17 00:00:00 2001 From: yongruilin Date: Sat, 12 Jul 2025 04:42:46 +0000 Subject: [PATCH] refactor(validation-gen): streamline type validation logic - Consolidated type validation checks into a new function for improved readability and maintainability. - Updated the method to utilize the new validation function, simplifying error handling for unsupported types. - Removed redundant code related to pointer and map validations, enhancing clarity in the validation process. - Adjusted test cases in to reflect changes in type handling and ensure consistency with the new validation logic. Co-authored-by: Tim Hockin Co-authored-by: Aaron Prindle Co-authored-by: Joe Betz --- .../cmd/validation-gen/util/util.go | 6 +- .../cmd/validation-gen/validation.go | 145 +++++----- .../cmd/validation-gen/validation_test.go | 262 +++++++++--------- 3 files changed, 203 insertions(+), 210 deletions(-) diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/util/util.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/util/util.go index 25165586610..4566699baff 100644 --- a/staging/src/k8s.io/code-generator/cmd/validation-gen/util/util.go +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/util/util.go @@ -66,7 +66,8 @@ func IsNilableType(t *types.Type) bool { // - given `type X []int; *X`, returns `*[]int` func NativeType(t *types.Type) *types.Type { ptrs := 0 - for { + conditionMet := false + for !conditionMet { switch t.Kind { case types.Alias: t = t.Underlying @@ -74,10 +75,9 @@ func NativeType(t *types.Type) *types.Type { ptrs++ t = t.Elem default: - goto done + conditionMet = true } } -done: for range ptrs { t = types.PointerTo(t) } diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/validation.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/validation.go index 837eb7dcd05..c9725138158 100644 --- a/staging/src/k8s.io/code-generator/cmd/validation-gen/validation.go +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/validation.go @@ -237,56 +237,10 @@ func (td *typeDiscoverer) discoverType(t *types.Type, fldPath *field.Path) (*typ } } - // Catch some edge cases that we don't want to handle (yet?). This happens + // Catch some cases that we don't want to handle (yet?). This happens // as early as possible to make all the other code simpler. - switch t.Kind { - case types.Builtin, types.Struct: - // Allowed - case types.Interface: - // We can't do much with interfaces, but they pop up in some places - // like RawExtension. - case types.Alias: - if t.Underlying.Kind == types.Pointer { - return nil, fmt.Errorf("field %s (%s): typedefs to pointers are not supported", fldPath.String(), t) - } - case types.Pointer: - pointee := util.NativeType(t.Elem) - switch pointee.Kind { - case types.Pointer: - return nil, fmt.Errorf("field %s (%s): pointers to pointers are not supported", fldPath.String(), t) - case types.Slice, types.Array: - return nil, fmt.Errorf("field %s (%s): pointers to lists are not supported", fldPath.String(), t) - case types.Map: - return nil, fmt.Errorf("field %s (%s): pointers to maps are not supported", fldPath.String(), t) - } - case types.Array: - return nil, fmt.Errorf("field %s (%s): fixed-size arrays are not supported", fldPath.String(), t) - case types.Slice: - elem := util.NativeType(t.Elem) - switch elem.Kind { - case types.Pointer: - return nil, fmt.Errorf("field %s (%s): lists of pointers are not supported", fldPath.String(), t) - case types.Slice: - if util.NativeType(elem.Elem) != types.Byte { - return nil, fmt.Errorf("field %s (%s): lists of lists are not supported", fldPath.String(), t) - } - case types.Map: - return nil, fmt.Errorf("field %s (%s): lists of maps are not supported", fldPath.String(), t) - } - case types.Map: - key := util.NativeType(t.Key) - if key != types.String { - return nil, fmt.Errorf("field %s (%s): maps with non-string keys are not supported", fldPath.String(), t) - } - elem := util.NativeType(t.Elem) - switch elem.Kind { - case types.Pointer: - return nil, fmt.Errorf("field %s (%s): maps of pointers are not supported", fldPath.String(), t) - case types.Map: - return nil, fmt.Errorf("field %s (%s): maps of maps are not supported", fldPath.String(), t) - } - default: - return nil, fmt.Errorf("field %s (%v, kind %v) is not supported", fldPath.String(), t, t.Kind) + if err := td.verifySupportedType(t); err != nil { + return nil, fmt.Errorf("field %s (%s): %w", fldPath.String(), t, err) } // Discovery applies to values, not pointers. @@ -410,11 +364,7 @@ func (td *typeDiscoverer) discoverType(t *types.Type, fldPath *field.Path) (*typ } else if validations.Empty() { klog.V(6).InfoS("no type-attached validations", "type", t) } else { - // TODO: This check is placed here to allow map-of-slices fields to exist in the type - // system, while preventing validation on them since that functionality is not yet - // implemented. Once validation support for map-of-slices is added, this check should - // be removed. - if util.NativeType(t).Kind == types.Map && util.NativeType(t).Elem.Kind == types.Slice { + if util.NonPointer(util.NativeType(t)).Kind == types.Map && util.NonPointer(util.NativeType(t)).Elem.Kind == types.Slice { return nil, fmt.Errorf("field %s: validation for map of slices is not supported", fldPath) } klog.V(5).InfoS("found type-attached validations", "n", validations.Len(), "type", t) @@ -532,6 +482,61 @@ func (td *typeDiscoverer) discoverType(t *types.Type, fldPath *field.Path) (*typ return thisNode, nil } +// verifySupportedType checks whether the given type is supported. +func (td *typeDiscoverer) verifySupportedType(t *types.Type) error { + switch t.Kind { + case types.Builtin, types.Struct: + // Allowed + case types.Interface: + // We can't do much with interfaces, but they pop up in some places + // like RawExtension. + case types.Alias: + if t.Underlying.Kind == types.Pointer { + return fmt.Errorf("typedefs to pointers are not supported") + } + case types.Pointer: + pointee := util.NativeType(t.Elem) + switch pointee.Kind { + case types.Pointer: + return fmt.Errorf("pointers to pointers are not supported") + case types.Slice, types.Array: + return fmt.Errorf("pointers to lists are not supported") + case types.Map: + return fmt.Errorf("pointers to maps are not supported") + } + case types.Array: + return fmt.Errorf("fixed-size arrays are not supported") + case types.Slice: + elem := util.NativeType(t.Elem) + switch elem.Kind { + case types.Pointer: + return fmt.Errorf("lists of pointers are not supported") + case types.Slice: + if util.NativeType(elem.Elem) != types.Byte { + return fmt.Errorf("lists of lists are not supported") + } + case types.Map: + return fmt.Errorf("lists of maps are not supported") + } + case types.Map: + key := util.NativeType(t.Key) + if key != types.String { + return fmt.Errorf("maps with non-string keys are not supported") + } + elem := util.NativeType(t.Elem) + switch elem.Kind { + case types.Pointer: + return fmt.Errorf("maps of pointers are not supported") + case types.Map: + return fmt.Errorf("maps of maps are not supported") + } + default: + return fmt.Errorf("kind %v is not supported", t.Kind) + } + + return nil +} + // discoverStruct walks a struct type recursively. func (td *typeDiscoverer) discoverStruct(thisNode *typeNode, fldPath *field.Path) error { var fields []*childNode @@ -589,11 +594,7 @@ func (td *typeDiscoverer) discoverStruct(thisNode *typeNode, fldPath *field.Path klog.V(6).InfoS("no field-attached validations", "field", childPath) } else { klog.V(5).InfoS("found field-attached validations", "n", validations.Len(), "field", childPath) - // TODO: This check is placed here to allow map-of-slices fields to exist in the type - // system, while preventing validation on them since that functionality is not yet - // implemented. Once validation support for map-of-slices is added, this check should - // be removed. - if util.NativeType(childType).Kind == types.Map && util.NativeType(childType).Elem.Kind == types.Slice { + if util.NonPointer(util.NativeType(childType)).Kind == types.Map && util.NonPointer(util.NativeType(childType)).Elem.Kind == types.Slice { return fmt.Errorf("field %s: validation for map of slices is not supported", childPath) } child.fieldValidations.Add(validations) @@ -603,7 +604,7 @@ func (td *typeDiscoverer) discoverStruct(thisNode *typeNode, fldPath *field.Path } // Handle non-included types. - switch nonPtrType(childType).Kind { + switch util.NonPointer(childType).Kind { case types.Struct, types.Alias: if child.node == nil { // a non-included type if !child.fieldValidations.OpaqueType { @@ -728,14 +729,6 @@ func (td *typeDiscoverer) discoverStruct(thisNode *typeNode, fldPath *field.Path return nil } -// nonPtrType removes any pointerness from the type. -func nonPtrType(t *types.Type) *types.Type { - for t.Kind == types.Pointer { - t = t.Elem - } - return t -} - // getValidationFunctionName looks up the name of the specified type's // validation function. // @@ -1009,8 +1002,6 @@ func (g *genValidations) emitValidationForChild(c *generator.Context, thisChild bufsw := sw.Dup(buf) validations := fld.fieldValidations - - // fldRatchetingChecked is used to avoid emitting the ratcheting check multiple times. fldRatchetingChecked := false if !validations.Empty() { emitComments(validations.Comments, bufsw) @@ -1146,9 +1137,15 @@ func emitRatchetingCheck(c *generator.Context, t *types.Type, sw *generator.Snip } // If the type is a builtin, we can use a simpler equality check when they are not nil. if util.IsDirectComparable(util.NonPointer(util.NativeType(t))) { - _, exprPfx, _ := getLeafTypeAndPrefixes(t) - targs["exprPfx"] = exprPfx - sw.Do("if op.Type == $.operation.Update|raw$ && (obj == oldObj || (obj != nil && oldObj != nil && $.exprPfx$obj == $.exprPfx$oldObj)) {\n", targs) + // We should never get anything but pointers here, since every other + // nilable type is not Comparable. + // + // This condition looks overly complex, but each case is needed: + // - obj == oldObj : handle pointers which are nil in old and new + // - obj != nil : handle optional fields which are updated to nil + // - oldObj != nil : handle optional fields which are updated from nil + // - *obj == *oldObj : compare values + sw.Do("if op.Type == $.operation.Update|raw$ && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) {\n", targs) } else { targs["equality"] = mkSymbolArgs(c, equalityPkgSymbols) sw.Do("if op.Type == $.operation.Update|raw$ && $.equality.Semantic|raw$.DeepEqual(obj, oldObj) {\n", targs) @@ -1341,6 +1338,8 @@ func toGolangSourceDataLiteral(sw *generator.SnippetWriter, c *generator.Context sw.Do("$.|raw$", v) case types.Member: sw.Do("obj."+v.Name, nil) + case *types.Member: + sw.Do("obj."+v.Name, nil) case validators.Identifier: sw.Do("$.|raw$", c.Universe.Type(types.Name(v))) case *validators.Identifier: diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/validation_test.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/validation_test.go index 0d93ccb4ecf..5debd0856e8 100644 --- a/staging/src/k8s.io/code-generator/cmd/validation-gen/validation_test.go +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/validation_test.go @@ -22,59 +22,53 @@ import ( "k8s.io/gengo/v2/types" ) -func TestGetLeafTypeAndPrefixes(t *testing.T) { - stringType := &types.Type{ +// gengo has `PointerTo()` but not the rest, so keep this here for consistency. +func ptrTo(t *types.Type) *types.Type { + return &types.Type{ Name: types.Name{ Package: "", - Name: "string", + Name: "*" + t.Name.String(), }, - Kind: types.Builtin, + Kind: types.Pointer, + Elem: t, } +} - ptrTo := func(t *types.Type) *types.Type { - return &types.Type{ - Name: types.Name{ - Package: "", - Name: "*" + t.Name.String(), - }, - Kind: types.Pointer, - Elem: t, - } +func sliceOf(t *types.Type) *types.Type { + return &types.Type{ + Name: types.Name{ + Package: "", + Name: "[]" + t.Name.String(), + }, + Kind: types.Slice, + Elem: t, } +} - sliceOf := func(t *types.Type) *types.Type { - return &types.Type{ - Name: types.Name{ - Package: "", - Name: "[]" + t.Name.String(), - }, - Kind: types.Slice, - Elem: t, - } +func mapOf(t *types.Type) *types.Type { + return &types.Type{ + Name: types.Name{ + Package: "", + Name: "map[string]" + t.Name.String(), + }, + Kind: types.Map, + Key: types.String, + Elem: t, } +} - mapOf := func(t *types.Type) *types.Type { - return &types.Type{ - Name: types.Name{ - Package: "", - Name: "map[string]" + t.Name.String(), - }, - Kind: types.Map, - Key: stringType, - Elem: t, - } +func aliasOf(name string, t *types.Type) *types.Type { + return &types.Type{ + Name: types.Name{ + Package: "", + Name: "Alias_" + name, + }, + Kind: types.Alias, + Underlying: t, } +} - aliasOf := func(name string, t *types.Type) *types.Type { - return &types.Type{ - Name: types.Name{ - Package: "", - Name: "Alias_" + name, - }, - Kind: types.Alias, - Underlying: t, - } - } +func TestGetLeafTypeAndPrefixes(t *testing.T) { cases := []struct { in *types.Type @@ -83,278 +77,278 @@ func TestGetLeafTypeAndPrefixes(t *testing.T) { expectedExprPfx string }{{ // string - in: stringType, - expectedType: stringType, + in: types.String, + expectedType: types.String, expectedTypePfx: "*", expectedExprPfx: "&", }, { // *string - in: ptrTo(stringType), - expectedType: stringType, + in: ptrTo(types.String), + expectedType: types.String, expectedTypePfx: "*", expectedExprPfx: "", }, { // **string - in: ptrTo(ptrTo(stringType)), - expectedType: stringType, + in: ptrTo(ptrTo(types.String)), + expectedType: types.String, expectedTypePfx: "*", expectedExprPfx: "*", }, { // ***string - in: ptrTo(ptrTo(ptrTo(stringType))), - expectedType: stringType, + in: ptrTo(ptrTo(ptrTo(types.String))), + expectedType: types.String, expectedTypePfx: "*", expectedExprPfx: "**", }, { // []string - in: sliceOf(stringType), - expectedType: sliceOf(stringType), + in: sliceOf(types.String), + expectedType: sliceOf(types.String), expectedTypePfx: "", expectedExprPfx: "", }, { // *[]string - in: ptrTo(sliceOf(stringType)), - expectedType: sliceOf(stringType), + in: ptrTo(sliceOf(types.String)), + expectedType: sliceOf(types.String), expectedTypePfx: "", expectedExprPfx: "*", }, { // **[]string - in: ptrTo(ptrTo(sliceOf(stringType))), - expectedType: sliceOf(stringType), + in: ptrTo(ptrTo(sliceOf(types.String))), + expectedType: sliceOf(types.String), expectedTypePfx: "", expectedExprPfx: "**", }, { // ***[]string - in: ptrTo(ptrTo(ptrTo(sliceOf(stringType)))), - expectedType: sliceOf(stringType), + in: ptrTo(ptrTo(ptrTo(sliceOf(types.String)))), + expectedType: sliceOf(types.String), expectedTypePfx: "", expectedExprPfx: "***", }, { // map[string]string - in: mapOf(stringType), - expectedType: mapOf(stringType), + in: mapOf(types.String), + expectedType: mapOf(types.String), expectedTypePfx: "", expectedExprPfx: "", }, { // *map[string]string - in: ptrTo(mapOf(stringType)), - expectedType: mapOf(stringType), + in: ptrTo(mapOf(types.String)), + expectedType: mapOf(types.String), expectedTypePfx: "", expectedExprPfx: "*", }, { // **map[string]string - in: ptrTo(ptrTo(mapOf(stringType))), - expectedType: mapOf(stringType), + in: ptrTo(ptrTo(mapOf(types.String))), + expectedType: mapOf(types.String), expectedTypePfx: "", expectedExprPfx: "**", }, { // ***map[string]string - in: ptrTo(ptrTo(ptrTo(mapOf(stringType)))), - expectedType: mapOf(stringType), + in: ptrTo(ptrTo(ptrTo(mapOf(types.String)))), + expectedType: mapOf(types.String), expectedTypePfx: "", expectedExprPfx: "***", }, { // alias of string - in: aliasOf("s", stringType), - expectedType: aliasOf("s", stringType), + in: aliasOf("s", types.String), + expectedType: aliasOf("s", types.String), expectedTypePfx: "*", expectedExprPfx: "&", }, { // alias of *string - in: aliasOf("ps", ptrTo(stringType)), - expectedType: aliasOf("ps", stringType), + in: aliasOf("ps", ptrTo(types.String)), + expectedType: aliasOf("ps", types.String), expectedTypePfx: "", expectedExprPfx: "", }, { // alias of **string - in: aliasOf("pps", ptrTo(ptrTo(stringType))), - expectedType: aliasOf("pps", stringType), + in: aliasOf("pps", ptrTo(ptrTo(types.String))), + expectedType: aliasOf("pps", types.String), expectedTypePfx: "", expectedExprPfx: "", }, { // alias of ***string - in: aliasOf("ppps", ptrTo(ptrTo(ptrTo(stringType)))), - expectedType: aliasOf("ppps", stringType), + in: aliasOf("ppps", ptrTo(ptrTo(ptrTo(types.String)))), + expectedType: aliasOf("ppps", types.String), expectedTypePfx: "", expectedExprPfx: "", }, { // alias of []string - in: aliasOf("ls", sliceOf(stringType)), - expectedType: aliasOf("ls", sliceOf(stringType)), + in: aliasOf("ls", sliceOf(types.String)), + expectedType: aliasOf("ls", sliceOf(types.String)), expectedTypePfx: "", expectedExprPfx: "", }, { // alias of *[]string - in: aliasOf("pls", ptrTo(sliceOf(stringType))), - expectedType: aliasOf("pls", sliceOf(stringType)), + in: aliasOf("pls", ptrTo(sliceOf(types.String))), + expectedType: aliasOf("pls", sliceOf(types.String)), expectedTypePfx: "", expectedExprPfx: "", }, { // alias of **[]string - in: aliasOf("ppls", ptrTo(ptrTo(sliceOf(stringType)))), - expectedType: aliasOf("ppls", sliceOf(stringType)), + in: aliasOf("ppls", ptrTo(ptrTo(sliceOf(types.String)))), + expectedType: aliasOf("ppls", sliceOf(types.String)), expectedTypePfx: "", expectedExprPfx: "", }, { // alias of ***[]string - in: aliasOf("pppls", ptrTo(ptrTo(ptrTo(sliceOf(stringType))))), - expectedType: aliasOf("pppls", sliceOf(stringType)), + in: aliasOf("pppls", ptrTo(ptrTo(ptrTo(sliceOf(types.String))))), + expectedType: aliasOf("pppls", sliceOf(types.String)), expectedTypePfx: "", expectedExprPfx: "", }, { // alias of map[string]string - in: aliasOf("ms", mapOf(stringType)), - expectedType: aliasOf("ms", mapOf(stringType)), + in: aliasOf("ms", mapOf(types.String)), + expectedType: aliasOf("ms", mapOf(types.String)), expectedTypePfx: "", expectedExprPfx: "", }, { // alias of *map[string]string - in: aliasOf("pms", ptrTo(mapOf(stringType))), - expectedType: aliasOf("pms", mapOf(stringType)), + in: aliasOf("pms", ptrTo(mapOf(types.String))), + expectedType: aliasOf("pms", mapOf(types.String)), expectedTypePfx: "", expectedExprPfx: "", }, { // alias of **map[string]string - in: aliasOf("ppms", ptrTo(ptrTo(mapOf(stringType)))), - expectedType: aliasOf("ppms", mapOf(stringType)), + in: aliasOf("ppms", ptrTo(ptrTo(mapOf(types.String)))), + expectedType: aliasOf("ppms", mapOf(types.String)), expectedTypePfx: "", expectedExprPfx: "", }, { // alias of ***map[string]string - in: aliasOf("pppms", ptrTo(ptrTo(ptrTo(mapOf(stringType))))), - expectedType: aliasOf("pppms", mapOf(stringType)), + in: aliasOf("pppms", ptrTo(ptrTo(ptrTo(mapOf(types.String))))), + expectedType: aliasOf("pppms", mapOf(types.String)), expectedTypePfx: "", expectedExprPfx: "", }, { // *alias-of-string - in: ptrTo(aliasOf("s", stringType)), - expectedType: aliasOf("s", stringType), + in: ptrTo(aliasOf("s", types.String)), + expectedType: aliasOf("s", types.String), expectedTypePfx: "*", expectedExprPfx: "", }, { // **alias-of-string - in: ptrTo(ptrTo(aliasOf("s", stringType))), - expectedType: aliasOf("s", stringType), + in: ptrTo(ptrTo(aliasOf("s", types.String))), + expectedType: aliasOf("s", types.String), expectedTypePfx: "*", expectedExprPfx: "*", }, { // ***alias-of-string - in: ptrTo(ptrTo(ptrTo(aliasOf("s", stringType)))), - expectedType: aliasOf("s", stringType), + in: ptrTo(ptrTo(ptrTo(aliasOf("s", types.String)))), + expectedType: aliasOf("s", types.String), expectedTypePfx: "*", expectedExprPfx: "**", }, { // []alias-of-string - in: sliceOf(aliasOf("s", stringType)), - expectedType: sliceOf(aliasOf("s", stringType)), + in: sliceOf(aliasOf("s", types.String)), + expectedType: sliceOf(aliasOf("s", types.String)), expectedTypePfx: "", expectedExprPfx: "", }, { // *[]alias-of-string - in: ptrTo(sliceOf(aliasOf("s", stringType))), - expectedType: sliceOf(aliasOf("s", stringType)), + in: ptrTo(sliceOf(aliasOf("s", types.String))), + expectedType: sliceOf(aliasOf("s", types.String)), expectedTypePfx: "", expectedExprPfx: "*", }, { // **[]alias-of-string - in: ptrTo(ptrTo(sliceOf(aliasOf("s", stringType)))), - expectedType: sliceOf(aliasOf("s", stringType)), + in: ptrTo(ptrTo(sliceOf(aliasOf("s", types.String)))), + expectedType: sliceOf(aliasOf("s", types.String)), expectedTypePfx: "", expectedExprPfx: "**", }, { // ***[]alias-of-string - in: ptrTo(ptrTo(ptrTo(sliceOf(aliasOf("s", stringType))))), - expectedType: sliceOf(aliasOf("s", stringType)), + in: ptrTo(ptrTo(ptrTo(sliceOf(aliasOf("s", types.String))))), + expectedType: sliceOf(aliasOf("s", types.String)), expectedTypePfx: "", expectedExprPfx: "***", }, { // map[string]alias-of-string - in: mapOf(aliasOf("s", stringType)), - expectedType: mapOf(aliasOf("s", stringType)), + in: mapOf(aliasOf("s", types.String)), + expectedType: mapOf(aliasOf("s", types.String)), expectedTypePfx: "", expectedExprPfx: "", }, { // *map[string]alias-of-string - in: ptrTo(mapOf(aliasOf("s", stringType))), - expectedType: mapOf(aliasOf("s", stringType)), + in: ptrTo(mapOf(aliasOf("s", types.String))), + expectedType: mapOf(aliasOf("s", types.String)), expectedTypePfx: "", expectedExprPfx: "*", }, { // **map[string]alias-of-string - in: ptrTo(ptrTo(mapOf(aliasOf("s", stringType)))), - expectedType: mapOf(aliasOf("s", stringType)), + in: ptrTo(ptrTo(mapOf(aliasOf("s", types.String)))), + expectedType: mapOf(aliasOf("s", types.String)), expectedTypePfx: "", expectedExprPfx: "**", }, { // ***map[string]alias-of-string - in: ptrTo(ptrTo(ptrTo(mapOf(aliasOf("s", stringType))))), - expectedType: mapOf(aliasOf("s", stringType)), + in: ptrTo(ptrTo(ptrTo(mapOf(aliasOf("s", types.String))))), + expectedType: mapOf(aliasOf("s", types.String)), expectedTypePfx: "", expectedExprPfx: "***", }, { // *alias-of-*string - in: ptrTo(aliasOf("ps", ptrTo(stringType))), - expectedType: aliasOf("ps", ptrTo(stringType)), + in: ptrTo(aliasOf("ps", ptrTo(types.String))), + expectedType: aliasOf("ps", ptrTo(types.String)), expectedTypePfx: "", expectedExprPfx: "*", }, { // **alias-of-*string - in: ptrTo(ptrTo(aliasOf("ps", ptrTo(stringType)))), - expectedType: aliasOf("ps", ptrTo(stringType)), + in: ptrTo(ptrTo(aliasOf("ps", ptrTo(types.String)))), + expectedType: aliasOf("ps", ptrTo(types.String)), expectedTypePfx: "", expectedExprPfx: "**", }, { // ***alias-of-*string - in: ptrTo(ptrTo(ptrTo(aliasOf("ps", ptrTo(stringType))))), - expectedType: aliasOf("ps", ptrTo(stringType)), + in: ptrTo(ptrTo(ptrTo(aliasOf("ps", ptrTo(types.String))))), + expectedType: aliasOf("ps", ptrTo(types.String)), expectedTypePfx: "", expectedExprPfx: "***", }, { // []alias-of-*string - in: sliceOf(aliasOf("ps", ptrTo(stringType))), - expectedType: sliceOf(aliasOf("ps", ptrTo(stringType))), + in: sliceOf(aliasOf("ps", ptrTo(types.String))), + expectedType: sliceOf(aliasOf("ps", ptrTo(types.String))), expectedTypePfx: "", expectedExprPfx: "", }, { // *[]alias-of-*string - in: ptrTo(sliceOf(aliasOf("ps", ptrTo(stringType)))), - expectedType: sliceOf(aliasOf("ps", ptrTo(stringType))), + in: ptrTo(sliceOf(aliasOf("ps", ptrTo(types.String)))), + expectedType: sliceOf(aliasOf("ps", ptrTo(types.String))), expectedTypePfx: "", expectedExprPfx: "*", }, { // **[]alias-of-*string - in: ptrTo(ptrTo(sliceOf(aliasOf("ps", ptrTo(stringType))))), - expectedType: sliceOf(aliasOf("ps", ptrTo(stringType))), + in: ptrTo(ptrTo(sliceOf(aliasOf("ps", ptrTo(types.String))))), + expectedType: sliceOf(aliasOf("ps", ptrTo(types.String))), expectedTypePfx: "", expectedExprPfx: "**", }, { // ***[]alias-of-*string - in: ptrTo(ptrTo(ptrTo(sliceOf(aliasOf("ps", ptrTo(stringType)))))), - expectedType: sliceOf(aliasOf("ps", ptrTo(stringType))), + in: ptrTo(ptrTo(ptrTo(sliceOf(aliasOf("ps", ptrTo(types.String)))))), + expectedType: sliceOf(aliasOf("ps", ptrTo(types.String))), expectedTypePfx: "", expectedExprPfx: "***", }, { // map[string]alias-of-*string - in: mapOf(aliasOf("ps", ptrTo(stringType))), - expectedType: mapOf(aliasOf("ps", ptrTo(stringType))), + in: mapOf(aliasOf("ps", ptrTo(types.String))), + expectedType: mapOf(aliasOf("ps", ptrTo(types.String))), expectedTypePfx: "", expectedExprPfx: "", }, { // *map[string]alias-of-*string - in: ptrTo(mapOf(aliasOf("ps", ptrTo(stringType)))), - expectedType: mapOf(aliasOf("ps", ptrTo(stringType))), + in: ptrTo(mapOf(aliasOf("ps", ptrTo(types.String)))), + expectedType: mapOf(aliasOf("ps", ptrTo(types.String))), expectedTypePfx: "", expectedExprPfx: "*", }, { // **map[string]alias-of-*string - in: ptrTo(ptrTo(mapOf(aliasOf("ps", ptrTo(stringType))))), - expectedType: mapOf(aliasOf("ps", ptrTo(stringType))), + in: ptrTo(ptrTo(mapOf(aliasOf("ps", ptrTo(types.String))))), + expectedType: mapOf(aliasOf("ps", ptrTo(types.String))), expectedTypePfx: "", expectedExprPfx: "**", }, { // ***map[string]alias-of-*string - in: ptrTo(ptrTo(ptrTo(mapOf(aliasOf("ps", ptrTo(stringType)))))), - expectedType: mapOf(aliasOf("ps", ptrTo(stringType))), + in: ptrTo(ptrTo(ptrTo(mapOf(aliasOf("ps", ptrTo(types.String)))))), + expectedType: mapOf(aliasOf("ps", ptrTo(types.String))), expectedTypePfx: "", expectedExprPfx: "***", }}