blob: cce3334a1b7dd93119f478df58e2307ba05842f7 [file] [log] [blame]
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test that StructuralType() calculates the correct value of structural type for
// unusual cases.
package types_test
import (
"cmd/compile/internal/ir"
. "cmd/compile/internal/types"
"cmd/internal/src"
"testing"
)
type test struct {
typ *Type
structuralType *Type
}
func TestStructuralType(t *testing.T) {
// These are the few constants that need to be initialized in order to use
// the types package without using the typecheck package by calling
// typecheck.InitUniverse() (the normal way to initialize the types package).
PtrSize = 8
RegSize = 8
MaxWidth = 1 << 50
InitTypes(func(sym *Sym, typ *Type) Object {
obj := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, sym)
obj.SetType(typ)
sym.Def = obj
return obj
})
// type intType = int
intType := Types[TINT]
// type structf = struct { f int }
structf := NewStruct(nil, []*Field{
NewField(src.NoXPos, LocalPkg.Lookup("f"), intType),
})
defNamed := func(name string, underlying *Type) *Type {
sym := LocalPkg.Lookup(name)
obj := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, sym)
typ := NewNamed(obj)
typ.SetUnderlying(underlying)
return typ
}
Sf := defNamed("Sf", structf) // type Sf structf
A := defNamed("A", intType) // type A int
B := defNamed("B", intType) // type B int
any := AnyType
// The tests marked NONE have no structural type; all the others have a
// structural type of structf - "struct { f int }"
tests := []*test{
{
// interface { struct { f int } }
embed(structf),
structf,
},
{
// interface { struct { f int }; any }
embed(structf, any),
structf,
},
{
// interface { Sf }
embed(Sf),
structf,
},
{
// interface { any; Sf }
embed(any, Sf),
structf,
},
{
// interface { struct { f int }; Sf } - NONE
embed(structf, Sf),
nil,
},
{
// interface { struct { f int } | ~struct { f int } }
embed(NewUnion([]*Type{structf, structf}, []bool{false, true})),
structf,
},
{
// interface { ~struct { f int } ; Sf }
embed(NewUnion([]*Type{structf}, []bool{true}), Sf),
structf,
},
{
// interface { struct { f int } ; Sf } - NONE
embed(NewUnion([]*Type{structf}, []bool{false}), Sf),
nil,
},
{
// interface { Sf | A; B | Sf}
embed(NewUnion([]*Type{Sf, A}, []bool{false, false}),
NewUnion([]*Type{B, Sf}, []bool{false, false})),
structf,
},
{
// interface { Sf | A; A | Sf } - NONE
embed(NewUnion([]*Type{Sf, A}, []bool{false, false}),
NewUnion([]*Type{A, Sf}, []bool{false, false})),
nil,
},
{
// interface { Sf | any } - NONE
embed(NewUnion([]*Type{Sf, any}, []bool{false, false})),
nil,
},
{
// interface { Sf | any; Sf }
embed(NewUnion([]*Type{Sf, any}, []bool{false, false}), Sf),
structf,
},
}
for i, tst := range tests {
if got, want := tst.typ.StructuralType(), tst.structuralType; got != want {
t.Errorf("#%v: StructuralType(%v) = %v, wanted %v",
i, tst.typ, got, want)
}
}
}
func embed(types ...*Type) *Type {
fields := make([]*Field, len(types))
for i, t := range types {
fields[i] = NewField(src.NoXPos, nil, t)
}
return NewInterface(LocalPkg, fields, false)
}