167 lines
5.9 KiB
Go
167 lines
5.9 KiB
Go
//go:build !llgo
|
|
|
|
/*
|
|
* Copyright (c) 2025 The GoPlus Authors (goplus.org). All rights reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package ssa
|
|
|
|
import (
|
|
"go/token"
|
|
"go/types"
|
|
"testing"
|
|
)
|
|
|
|
func TestHasTypeParam(t *testing.T) {
|
|
generic := newGenericNamedType("Box")
|
|
instantiated, err := types.Instantiate(types.NewContext(), generic, []types.Type{types.Typ[types.String]}, true)
|
|
if err != nil {
|
|
t.Fatalf("Instantiate: %v", err)
|
|
}
|
|
partialArg := newTypeParam("PartialArg")
|
|
partialInstance, err := types.Instantiate(types.NewContext(), generic, []types.Type{partialArg}, false)
|
|
if err != nil {
|
|
t.Fatalf("Instantiate partial: %v", err)
|
|
}
|
|
|
|
arrayType := func() types.Type {
|
|
tp := newTypeParam("ArrayElem")
|
|
return types.NewArray(tp, 3)
|
|
}()
|
|
|
|
chanType := types.NewChan(types.SendRecv, newTypeParam("ChanElem"))
|
|
|
|
tupleType := func() types.Type {
|
|
tp := newTypeParam("TupleElem")
|
|
elem := types.NewVar(token.NoPos, nil, "v", tp)
|
|
return types.NewTuple(elem)
|
|
}()
|
|
|
|
structWithParam := func() types.Type {
|
|
tp := newTypeParam("StructElem")
|
|
field := types.NewVar(token.NoPos, nil, "value", tp)
|
|
return types.NewStruct([]*types.Var{field}, nil)
|
|
}()
|
|
|
|
signatureWithParam := func() types.Type {
|
|
tp := newTypeParam("SigParam")
|
|
params := types.NewTuple(types.NewVar(token.NoPos, nil, "x", tp))
|
|
return types.NewSignatureType(nil, nil, []*types.TypeParam{tp}, params, types.NewTuple(), false)
|
|
}()
|
|
|
|
signatureWithResult := func() types.Type {
|
|
tp := newTypeParam("SigResult")
|
|
results := types.NewTuple(types.NewVar(token.NoPos, nil, "res", tp))
|
|
return types.NewSignatureType(nil, nil, []*types.TypeParam{tp}, types.NewTuple(), results, false)
|
|
}()
|
|
signatureParamWithoutDecl := func() types.Type {
|
|
tp := newTypeParam("SigParamExternal")
|
|
params := types.NewTuple(types.NewVar(token.NoPos, nil, "x", tp))
|
|
return types.NewSignatureType(nil, nil, nil, params, types.NewTuple(), false)
|
|
}()
|
|
signatureResultWithoutDecl := func() types.Type {
|
|
tp := newTypeParam("SigResultExternal")
|
|
results := types.NewTuple(types.NewVar(token.NoPos, nil, "res", tp))
|
|
return types.NewSignatureType(nil, nil, nil, types.NewTuple(), results, false)
|
|
}()
|
|
|
|
interfaceWithParam := func() types.Type {
|
|
tp := newTypeParam("IfaceParam")
|
|
params := types.NewTuple(types.NewVar(token.NoPos, nil, "v", tp))
|
|
method := types.NewFunc(token.NoPos, nil, "Do", types.NewSignatureType(nil, nil, []*types.TypeParam{tp}, params, types.NewTuple(), false))
|
|
iface := types.NewInterfaceType([]*types.Func{method}, nil)
|
|
iface.Complete()
|
|
return iface
|
|
}()
|
|
|
|
interfaceWithEmbed := func() types.Type {
|
|
base := interfaceWithParam
|
|
tp := newTypeParam("EmbedParam")
|
|
embedMethod := types.NewFunc(token.NoPos, nil, "Run", types.NewSignatureType(nil, nil, []*types.TypeParam{tp}, types.NewTuple(), types.NewTuple(), false))
|
|
iface := types.NewInterfaceType([]*types.Func{embedMethod}, []types.Type{base})
|
|
iface.Complete()
|
|
return iface
|
|
}()
|
|
interfaceWithEmbeddedOnly := func() types.Type {
|
|
embedded := interfaceWithParam
|
|
iface := types.NewInterfaceType(nil, []types.Type{embedded})
|
|
iface.Complete()
|
|
return iface
|
|
}()
|
|
|
|
selfRecursive := func() types.Type {
|
|
typeName := types.NewTypeName(token.NoPos, nil, "Node", nil)
|
|
placeholder := types.NewStruct(nil, nil)
|
|
named := types.NewNamed(typeName, placeholder, nil)
|
|
field := types.NewVar(token.NoPos, nil, "next", types.NewPointer(named))
|
|
structType := types.NewStruct([]*types.Var{field}, nil)
|
|
named.SetUnderlying(structType)
|
|
return named
|
|
}()
|
|
|
|
tests := []struct {
|
|
name string
|
|
typ types.Type
|
|
want bool
|
|
}{
|
|
{"nilType", nil, false},
|
|
{"basic", types.Typ[types.Int], false},
|
|
{"typeParam", newTypeParam("T"), true},
|
|
{"pointerToTypeParam", types.NewPointer(newTypeParam("PtrT")), true},
|
|
{"sliceOfTypeParam", types.NewSlice(newTypeParam("SliceT")), true},
|
|
{"arrayOfTypeParam", arrayType, true},
|
|
{"mapWithTypeParam", types.NewMap(newTypeParam("MapKey"), types.Typ[types.String]), true},
|
|
{"chanOfTypeParam", chanType, true},
|
|
{"tupleWithTypeParam", tupleType, true},
|
|
{"structWithTypeParam", structWithParam, true},
|
|
{"signatureWithTypeParam", signatureWithParam, true},
|
|
{"signatureWithResultTypeParam", signatureWithResult, true},
|
|
{"signatureParamWithoutDecl", signatureParamWithoutDecl, true},
|
|
{"signatureResultWithoutDecl", signatureResultWithoutDecl, true},
|
|
{"interfaceWithTypeParam", interfaceWithParam, true},
|
|
{"interfaceWithEmbeddedTypeParam", interfaceWithEmbed, true},
|
|
{"interfaceWithEmbeddedOnlyTypeParam", interfaceWithEmbeddedOnly, true},
|
|
{"namedGeneric", generic, true},
|
|
{"pointerToNamedGeneric", types.NewPointer(generic), true},
|
|
{"namedInstanceWithTypeParamArg", partialInstance, true},
|
|
{"namedInstanceNoParam", instantiated, false},
|
|
{"selfRecursiveStruct", selfRecursive, false},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
if got := hasTypeParam(tc.typ); got != tc.want {
|
|
t.Fatalf("hasTypeParam(%s) = %v, want %v", tc.name, got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func newTypeParam(name string) *types.TypeParam {
|
|
iface := types.NewInterfaceType(nil, nil)
|
|
iface.Complete()
|
|
return types.NewTypeParam(types.NewTypeName(token.NoPos, nil, name, nil), iface)
|
|
}
|
|
|
|
func newGenericNamedType(name string) *types.Named {
|
|
tp := newTypeParam("T")
|
|
field := types.NewVar(token.NoPos, nil, "value", tp)
|
|
structType := types.NewStruct([]*types.Var{field}, nil)
|
|
named := types.NewNamed(types.NewTypeName(token.NoPos, nil, name, nil), structType, nil)
|
|
named.SetTypeParams([]*types.TypeParam{tp})
|
|
return named
|
|
}
|