Skip to content

Commit a6eeb4a

Browse files
committed
go/parser,go/types: hide API changes related to type parameters
While the dev.typeparams branch was merged, the type parameter API is slated for go1.18. Hide these changes to the go/parser and go/types API. This was done as follows: + For APIs that will probably not be needed for go1.18, simply unexport them. + For APIs that we expect to export in go1.18, prefix symbols with '_', so that the planned (upper-cased) symbol name is apparent. + For APIs that must be exported for testing, move both API and tests to files guarded by the go1.18 build constraint. + parser.ParseTypeParams is unexported and copied wherever it is needed. + The -G flag is removed from gofmt, replaced by enabling type parameters if built with the go1.18 build constraint. Notably, changes related to type parameters in go/ast are currently left exported. We're looking at the AST API separately. The new API diff from 1.16 is: +pkg go/ast, method (*FuncDecl) IsMethod() bool +pkg go/ast, method (*ListExpr) End() token.Pos +pkg go/ast, method (*ListExpr) Pos() token.Pos +pkg go/ast, type FuncType struct, TParams *FieldList +pkg go/ast, type ListExpr struct +pkg go/ast, type ListExpr struct, ElemList []Expr +pkg go/ast, type TypeSpec struct, TParams *FieldList +pkg go/types, type Config struct, GoVersion string Change-Id: I1baf67e26279b49092e774309a836c460979774a Reviewed-on: https://go-review.googlesource.com/c/go/+/295929 Trust: Robert Findley <[email protected]> Trust: Robert Griesemer <[email protected]> Run-TryBot: Robert Findley <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Robert Griesemer <[email protected]>
1 parent ff5cf4c commit a6eeb4a

31 files changed

+370
-304
lines changed

src/cmd/gofmt/gofmt.go

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,16 @@ import (
2626

2727
var (
2828
// main operation modes
29-
list = flag.Bool("l", false, "list files whose formatting differs from gofmt's")
30-
write = flag.Bool("w", false, "write result to (source) file instead of stdout")
31-
rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'a[b:len(a)] -> a[b:]')")
32-
simplifyAST = flag.Bool("s", false, "simplify code")
33-
doDiff = flag.Bool("d", false, "display diffs instead of rewriting files")
34-
allErrors = flag.Bool("e", false, "report all errors (not just the first 10 on different lines)")
35-
allowTypeParams = flag.Bool("G", false, "allow generic code")
29+
list = flag.Bool("l", false, "list files whose formatting differs from gofmt's")
30+
write = flag.Bool("w", false, "write result to (source) file instead of stdout")
31+
rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'a[b:len(a)] -> a[b:]')")
32+
simplifyAST = flag.Bool("s", false, "simplify code")
33+
doDiff = flag.Bool("d", false, "display diffs instead of rewriting files")
34+
allErrors = flag.Bool("e", false, "report all errors (not just the first 10 on different lines)")
35+
36+
// allowTypeParams controls whether type parameters are allowed in the code
37+
// being formatted. It is enabled for go1.18 in gofmt_go1.18.go.
38+
allowTypeParams = false
3639

3740
// debugging
3841
cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file")
@@ -48,6 +51,10 @@ const (
4851
//
4952
// This value is defined in go/printer specifically for go/format and cmd/gofmt.
5053
printerNormalizeNumbers = 1 << 30
54+
55+
// parseTypeParams tells go/parser to parse type parameters. Must be kept in
56+
// sync with go/parser/interface.go.
57+
parseTypeParams parser.Mode = 1 << 30
5158
)
5259

5360
var (
@@ -72,8 +79,8 @@ func initParserMode() {
7279
if *allErrors {
7380
parserMode |= parser.AllErrors
7481
}
75-
if *allowTypeParams {
76-
parserMode |= parser.ParseTypeParams
82+
if allowTypeParams {
83+
parserMode |= parseTypeParams
7784
}
7885
}
7986

src/cmd/gofmt/gofmt_go1.18.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright 2021 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build go1.18
6+
// +build go1.18
7+
8+
package main
9+
10+
func init() {
11+
allowTypeParams = true
12+
}

src/cmd/gofmt/gofmt_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ func runTest(t *testing.T, in, out string) {
7878
// fake flag - pretend input is from stdin
7979
stdin = true
8080
case "-G":
81-
*allowTypeParams = true
81+
// fake flag - allow parsing type parameters
82+
allowTypeParams = true
8283
default:
8384
t.Errorf("unrecognized flag name: %s", name)
8485
}

src/go/parser/error_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ func TestErrors(t *testing.T) {
188188
if !d.IsDir() && !strings.HasPrefix(name, ".") && (strings.HasSuffix(name, ".src") || strings.HasSuffix(name, ".go2")) {
189189
mode := DeclarationErrors | AllErrors
190190
if strings.HasSuffix(name, ".go2") {
191-
mode |= ParseTypeParams
191+
mode |= parseTypeParams
192192
}
193193
checkErrors(t, filepath.Join(testdata, name), nil, mode, true)
194194
}

src/go/parser/interface.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,14 @@ const (
5555
Trace // print a trace of parsed productions
5656
DeclarationErrors // report declaration errors
5757
SpuriousErrors // same as AllErrors, for backward-compatibility
58-
ParseTypeParams // Placeholder. Will control the parsing of type parameters.
5958
AllErrors = SpuriousErrors // report all errors (not just the first 10 on different lines)
59+
60+
// parseTypeParams controls the parsing of type parameters. Must be
61+
// kept in sync with:
62+
// go/printer/printer_test.go
63+
// go/types/check_test.go
64+
// cmd/gofmt/gofmt.go
65+
parseTypeParams = 1 << 30
6066
)
6167

6268
// ParseFile parses the source code of a single Go source file and returns

src/go/parser/parser.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,7 @@ func (p *parser) parseQualifiedIdent(ident *ast.Ident) ast.Expr {
651651
}
652652

653653
typ := p.parseTypeName(ident)
654-
if p.tok == token.LBRACK && p.mode&ParseTypeParams != 0 {
654+
if p.tok == token.LBRACK && p.mode&parseTypeParams != 0 {
655655
typ = p.parseTypeInstance(typ)
656656
}
657657

@@ -712,7 +712,7 @@ func (p *parser) parseArrayFieldOrTypeInstance(x *ast.Ident) (*ast.Ident, ast.Ex
712712
// TODO(rfindley): consider changing parseRhsOrType so that this function variable
713713
// is not needed.
714714
argparser := p.parseRhsOrType
715-
if p.mode&ParseTypeParams == 0 {
715+
if p.mode&parseTypeParams == 0 {
716716
argparser = p.parseRhs
717717
}
718718
if p.tok != token.RBRACK {
@@ -742,13 +742,13 @@ func (p *parser) parseArrayFieldOrTypeInstance(x *ast.Ident) (*ast.Ident, ast.Ex
742742
// x [P]E
743743
return x, &ast.ArrayType{Lbrack: lbrack, Len: args[0], Elt: elt}
744744
}
745-
if p.mode&ParseTypeParams == 0 {
745+
if p.mode&parseTypeParams == 0 {
746746
p.error(rbrack, "missing element type in array type expression")
747747
return nil, &ast.BadExpr{From: args[0].Pos(), To: args[0].End()}
748748
}
749749
}
750750

751-
if p.mode&ParseTypeParams == 0 {
751+
if p.mode&parseTypeParams == 0 {
752752
p.error(firstComma, "expected ']', found ','")
753753
return x, &ast.BadExpr{From: args[0].Pos(), To: args[len(args)-1].End()}
754754
}
@@ -1045,7 +1045,7 @@ func (p *parser) parseParameters(scope *ast.Scope, acceptTParams bool) (tparams,
10451045
defer un(trace(p, "Parameters"))
10461046
}
10471047

1048-
if p.mode&ParseTypeParams != 0 && acceptTParams && p.tok == token.LBRACK {
1048+
if p.mode&parseTypeParams != 0 && acceptTParams && p.tok == token.LBRACK {
10491049
opening := p.pos
10501050
p.next()
10511051
// [T any](params) syntax
@@ -1119,7 +1119,7 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
11191119
x := p.parseTypeName(nil)
11201120
if ident, _ := x.(*ast.Ident); ident != nil {
11211121
switch {
1122-
case p.tok == token.LBRACK && p.mode&ParseTypeParams != 0:
1122+
case p.tok == token.LBRACK && p.mode&parseTypeParams != 0:
11231123
// generic method or embedded instantiated type
11241124
lbrack := p.pos
11251125
p.next()
@@ -1171,7 +1171,7 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
11711171
} else {
11721172
// embedded, possibly instantiated type
11731173
typ = x
1174-
if p.tok == token.LBRACK && p.mode&ParseTypeParams != 0 {
1174+
if p.tok == token.LBRACK && p.mode&parseTypeParams != 0 {
11751175
// embedded instantiated interface
11761176
typ = p.parseTypeInstance(typ)
11771177
}
@@ -1193,7 +1193,7 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
11931193
lbrace := p.expect(token.LBRACE)
11941194
scope := ast.NewScope(nil) // interface scope
11951195
var list []*ast.Field
1196-
for p.tok == token.IDENT || p.mode&ParseTypeParams != 0 && p.tok == token.TYPE {
1196+
for p.tok == token.IDENT || p.mode&parseTypeParams != 0 && p.tok == token.TYPE {
11971197
if p.tok == token.IDENT {
11981198
list = append(list, p.parseMethodSpec(scope))
11991199
} else {
@@ -1289,7 +1289,7 @@ func (p *parser) tryIdentOrType() ast.Expr {
12891289
switch p.tok {
12901290
case token.IDENT:
12911291
typ := p.parseTypeName(nil)
1292-
if p.tok == token.LBRACK && p.mode&ParseTypeParams != 0 {
1292+
if p.tok == token.LBRACK && p.mode&parseTypeParams != 0 {
12931293
typ = p.parseTypeInstance(typ)
12941294
}
12951295
return typ
@@ -1552,7 +1552,7 @@ func (p *parser) parseIndexOrSliceOrInstance(x ast.Expr) ast.Expr {
15521552
return &ast.IndexExpr{X: x, Lbrack: lbrack, Index: index[0], Rbrack: rbrack}
15531553
}
15541554

1555-
if p.mode&ParseTypeParams == 0 {
1555+
if p.mode&parseTypeParams == 0 {
15561556
p.error(firstComma, "expected ']' or ':', found ','")
15571557
return &ast.BadExpr{From: args[0].Pos(), To: args[len(args)-1].End()}
15581558
}
@@ -2696,7 +2696,7 @@ func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Pos, _ token.Token
26962696
p.exprLev++
26972697
x := p.parseExpr(true) // we don't know yet if we're a lhs or rhs expr
26982698
p.exprLev--
2699-
if name0, _ := x.(*ast.Ident); p.mode&ParseTypeParams != 0 && name0 != nil && p.tok != token.RBRACK {
2699+
if name0, _ := x.(*ast.Ident); p.mode&parseTypeParams != 0 && name0 != nil && p.tok != token.RBRACK {
27002700
// generic type [T any];
27012701
p.parseGenericType(spec, lbrack, name0, token.RBRACK)
27022702
} else {

src/go/parser/short_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ var valids = []string{
6464
}
6565

6666
// validWithTParamsOnly holds source code examples that are valid if
67-
// ParseTypeParams is set, but invalid if not. When checking with the
68-
// ParseTypeParams set, errors are ignored.
67+
// parseTypeParams is set, but invalid if not. When checking with the
68+
// parseTypeParams set, errors are ignored.
6969
var validWithTParamsOnly = []string{
7070
`package p; type _ []T[ /* ERROR "expected ';', found '\['" */ int]`,
7171
`package p; type T[P any /* ERROR "expected ']', found any" */ ] struct { P }`,
@@ -131,18 +131,18 @@ func TestValid(t *testing.T) {
131131
})
132132
t.Run("tparams", func(t *testing.T) {
133133
for _, src := range valids {
134-
checkErrors(t, src, src, DeclarationErrors|AllErrors|ParseTypeParams, false)
134+
checkErrors(t, src, src, DeclarationErrors|AllErrors|parseTypeParams, false)
135135
}
136136
for _, src := range validWithTParamsOnly {
137-
checkErrors(t, src, src, DeclarationErrors|AllErrors|ParseTypeParams, false)
137+
checkErrors(t, src, src, DeclarationErrors|AllErrors|parseTypeParams, false)
138138
}
139139
})
140140
}
141141

142142
// TestSingle is useful to track down a problem with a single short test program.
143143
func TestSingle(t *testing.T) {
144144
const src = `package p; var _ = T[P]{}`
145-
checkErrors(t, src, src, DeclarationErrors|AllErrors|ParseTypeParams, true)
145+
checkErrors(t, src, src, DeclarationErrors|AllErrors|parseTypeParams, true)
146146
}
147147

148148
var invalids = []string{
@@ -261,10 +261,10 @@ func TestInvalid(t *testing.T) {
261261
})
262262
t.Run("tparams", func(t *testing.T) {
263263
for _, src := range invalids {
264-
checkErrors(t, src, src, DeclarationErrors|AllErrors|ParseTypeParams, true)
264+
checkErrors(t, src, src, DeclarationErrors|AllErrors|parseTypeParams, true)
265265
}
266266
for _, src := range invalidTParamErrs {
267-
checkErrors(t, src, src, DeclarationErrors|AllErrors|ParseTypeParams, true)
267+
checkErrors(t, src, src, DeclarationErrors|AllErrors|parseTypeParams, true)
268268
}
269269
})
270270
}

src/go/printer/printer_test.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ import (
1919
"time"
2020
)
2121

22+
// parseTypeParams tells go/parser to parse type parameters. Must be kept in
23+
// sync with go/parser/interface.go.
24+
const parseTypeParams parser.Mode = 1 << 30
25+
2226
const (
2327
dataDir = "testdata"
2428
tabwidth = 8
@@ -35,14 +39,19 @@ const (
3539
rawFormat
3640
normNumber
3741
idempotent
42+
allowTypeParams
3843
)
3944

4045
// format parses src, prints the corresponding AST, verifies the resulting
4146
// src is syntactically correct, and returns the resulting src or an error
4247
// if any.
4348
func format(src []byte, mode checkMode) ([]byte, error) {
4449
// parse src
45-
f, err := parser.ParseFile(fset, "", src, parser.ParseComments|parser.ParseTypeParams)
50+
parseMode := parser.ParseComments
51+
if mode&allowTypeParams != 0 {
52+
parseMode |= parseTypeParams
53+
}
54+
f, err := parser.ParseFile(fset, "", src, parseMode)
4655
if err != nil {
4756
return nil, fmt.Errorf("parse: %s\n%s", err, src)
4857
}
@@ -70,7 +79,7 @@ func format(src []byte, mode checkMode) ([]byte, error) {
7079

7180
// make sure formatted output is syntactically correct
7281
res := buf.Bytes()
73-
if _, err := parser.ParseFile(fset, "", res, parser.ParseTypeParams); err != nil {
82+
if _, err := parser.ParseFile(fset, "", res, parseTypeParams); err != nil {
7483
return nil, fmt.Errorf("re-parse: %s\n%s", err, buf.Bytes())
7584
}
7685

@@ -201,13 +210,13 @@ var data = []entry{
201210
{"linebreaks.input", "linebreaks.golden", idempotent},
202211
{"expressions.input", "expressions.golden", idempotent},
203212
{"expressions.input", "expressions.raw", rawFormat | idempotent},
204-
{"declarations.input", "declarations.golden", 0},
213+
{"declarations.input", "declarations.golden", allowTypeParams},
205214
{"statements.input", "statements.golden", 0},
206215
{"slow.input", "slow.golden", idempotent},
207216
{"complit.input", "complit.x", export},
208217
{"go2numbers.input", "go2numbers.golden", idempotent},
209218
{"go2numbers.input", "go2numbers.norm", normNumber | idempotent},
210-
{"generics.input", "generics.golden", idempotent},
219+
{"generics.input", "generics.golden", idempotent | allowTypeParams},
211220
{"gobuild1.input", "gobuild1.golden", idempotent},
212221
{"gobuild2.input", "gobuild2.golden", idempotent},
213222
{"gobuild3.input", "gobuild3.golden", idempotent},

src/go/types/api.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -184,11 +184,11 @@ type Info struct {
184184
// qualified identifiers are collected in the Uses map.
185185
Types map[ast.Expr]TypeAndValue
186186

187-
// Inferred maps calls of parameterized functions that use
188-
// type inference to the inferred type arguments and signature
187+
// _Inferred maps calls of parameterized functions that use
188+
// type inference to the _Inferred type arguments and signature
189189
// of the function called. The recorded "call" expression may be
190190
// an *ast.CallExpr (as in f(x)), or an *ast.IndexExpr (s in f[T]).
191-
Inferred map[ast.Expr]Inferred
191+
_Inferred map[ast.Expr]_Inferred
192192

193193
// Defs maps identifiers to the objects they define (including
194194
// package names, dots "." of dot-imports, and blank "_" identifiers).
@@ -346,9 +346,9 @@ func (tv TypeAndValue) HasOk() bool {
346346
return tv.mode == commaok || tv.mode == mapindex
347347
}
348348

349-
// Inferred reports the inferred type arguments and signature
349+
// _Inferred reports the _Inferred type arguments and signature
350350
// for a parameterized function call that uses type inference.
351-
type Inferred struct {
351+
type _Inferred struct {
352352
Targs []Type
353353
Sig *Signature
354354
}

src/go/types/api_go1.18.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2021 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build go1.18
6+
// +build go1.18
7+
8+
package types
9+
10+
import (
11+
"go/ast"
12+
)
13+
14+
type Inferred = _Inferred
15+
16+
func GetInferred(info *Info) map[ast.Expr]Inferred {
17+
return info._Inferred
18+
}
19+
20+
func SetInferred(info *Info, inferred map[ast.Expr]Inferred) {
21+
info._Inferred = inferred
22+
}

0 commit comments

Comments
 (0)