diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go index 1673b9b4af8..ae39f26e4f5 100644 --- a/src/cmd/compile/internal/types2/typeset.go +++ b/src/cmd/compile/internal/types2/typeset.go @@ -77,26 +77,24 @@ func (s *_TypeSet) String() string { var buf bytes.Buffer buf.WriteByte('{') if s.comparable { - buf.WriteString(" comparable") + buf.WriteString("comparable") if hasMethods || hasTerms { - buf.WriteByte(';') + buf.WriteString("; ") } } for i, m := range s.methods { if i > 0 { - buf.WriteByte(';') + buf.WriteString("; ") } - buf.WriteByte(' ') buf.WriteString(m.String()) } if hasMethods && hasTerms { - buf.WriteByte(';') + buf.WriteString("; ") } if hasTerms { buf.WriteString(s.terms.String()) } - buf.WriteString(" }") // there was at least one method or term - + buf.WriteString("}") return buf.String() } diff --git a/src/cmd/compile/internal/types2/typeset_test.go b/src/cmd/compile/internal/types2/typeset_test.go index 0e14d523c8b..7f7cc06db97 100644 --- a/src/cmd/compile/internal/types2/typeset_test.go +++ b/src/cmd/compile/internal/types2/typeset_test.go @@ -4,7 +4,11 @@ package types2 -import "testing" +import ( + "cmd/compile/internal/syntax" + "strings" + "testing" +) func TestInvalidTypeSet(t *testing.T) { if !invalidTypeSet.IsEmpty() { @@ -12,4 +16,65 @@ func TestInvalidTypeSet(t *testing.T) { } } +func TestTypeSetString(t *testing.T) { + for body, want := range map[string]string{ + "{}": "𝓤", + "{int}": "{int}", + "{~int}": "{~int}", + "{int|string}": "{int ∪ string}", + "{int; string}": "∅", + + "{comparable}": "{comparable}", + "{comparable; int}": "{comparable; int}", + "{~int; comparable}": "{comparable; ~int}", + "{int|string; comparable}": "{comparable; int ∪ string}", + "{comparable; int; string}": "∅", + + "{m()}": "{func (p.T).m()}", + "{m1(); m2() int }": "{func (p.T).m1(); func (p.T).m2() int}", + "{error}": "{func (error).Error() string}", + "{m(); comparable}": "{comparable; func (p.T).m()}", + "{m1(); comparable; m2() int }": "{comparable; func (p.T).m1(); func (p.T).m2() int}", + "{comparable; error}": "{comparable; func (error).Error() string}", + + "{m(); comparable; int|float32|string}": "{comparable; func (p.T).m(); int ∪ float32 ∪ string}", + "{m1(); int; m2(); comparable }": "{comparable; func (p.T).m1(); func (p.T).m2(); int}", + + "{E}; type E interface{}": "𝓤", + "{E}; type E interface{int;string}": "∅", + "{E}; type E interface{comparable}": "{comparable}", + } { + // parse + errh := func(error) {} // dummy error handler so that parsing continues in presence of errors + src := "package p; type T interface" + body + file, err := syntax.Parse(nil, strings.NewReader(src), errh, nil, syntax.AllowGenerics) + if err != nil { + t.Fatalf("%s: %v (invalid test case)", body, err) + } + + // type check + var conf Config + pkg, err := conf.Check(file.PkgName.Value, []*syntax.File{file}, nil) + if err != nil { + t.Fatalf("%s: %v (invalid test case)", body, err) + } + + // lookup T + obj := pkg.scope.Lookup("T") + if obj == nil { + t.Fatalf("%s: T not found (invalid test case)", body) + } + T, ok := under(obj.Type()).(*Interface) + if !ok { + t.Fatalf("%s: %v is not an interface (invalid test case)", body, obj) + } + + // verify test case + got := T.typeSet().String() + if got != want { + t.Errorf("%s: got %s; want %s", body, got, want) + } + } +} + // TODO(gri) add more tests