forked from golang/tools
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
internal/typeparams: a new helper library for working with generic code
Tools like gopls will want to add additional features to support working with generic code, but need to continue to compile at older Go versions that don't support type parameters. This CL contains an initial draft of a helper library that may be used to interrogate generic type information from go/ast and go/types without having to guard the calling code with a build constraint. I will use this library to implement some generics features for gopls. Once we're confident in the API, it could potentially be exported as x/tools/go/typeparams. Change-Id: I0ad3050b57cf8d8e8dda7d350d18f5e50f4105ff Reviewed-on: https://go-review.googlesource.com/c/tools/+/317451 Trust: Robert Findley <[email protected]> Trust: Robert Griesemer <[email protected]> Run-TryBot: Robert Findley <[email protected]> gopls-CI: kokoro <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Robert Griesemer <[email protected]>
- Loading branch information
Showing
3 changed files
with
206 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// Copyright 2021 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. | ||
|
||
// Package typeparams provides functions to work indirectly with type parameter | ||
// data stored in go/ast and go/types objects, while these API are guarded by a | ||
// build constraint. | ||
// | ||
// This package exists to make it easier for tools to work with generic code, | ||
// while also compiling against older Go versions. | ||
package typeparams |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
// Copyright 2021 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. | ||
|
||
//go:build !typeparams || !go1.17 | ||
// +build !typeparams !go1.17 | ||
|
||
package typeparams | ||
|
||
import ( | ||
"go/ast" | ||
"go/types" | ||
) | ||
|
||
// NOTE: doc comments must be kept in sync with typeparams.go. | ||
|
||
// Enabled reports whether type parameters are enabled in the current build | ||
// environment. | ||
const Enabled = false | ||
|
||
// UnpackIndex extracts all index expressions from e. For non-generic code this | ||
// is always one expression: e.Index, but may be more than one expression for | ||
// generic type instantiation. | ||
func UnpackIndex(e *ast.IndexExpr) []ast.Expr { | ||
return []ast.Expr{e.Index} | ||
} | ||
|
||
// IsListExpr reports whether n is an *ast.ListExpr, which is a new node type | ||
// introduced to hold type arguments for generic type instantiation. | ||
func IsListExpr(n ast.Node) bool { | ||
return false | ||
} | ||
|
||
// ForTypeDecl extracts the (possibly nil) type parameter node list from n. | ||
func ForTypeDecl(*ast.TypeSpec) *ast.FieldList { | ||
return nil | ||
} | ||
|
||
// ForFuncDecl extracts the (possibly nil) type parameter node list from n. | ||
func ForFuncDecl(*ast.FuncDecl) *ast.FieldList { | ||
return nil | ||
} | ||
|
||
// ForSignature extracts the (possibly empty) type parameter object list from | ||
// sig. | ||
func ForSignature(*types.Signature) []*types.TypeName { | ||
return nil | ||
} | ||
|
||
// HasTypeSet reports if iface has a type set. | ||
func HasTypeSet(*types.Interface) bool { | ||
return false | ||
} | ||
|
||
// IsComparable reports if iface is the comparable interface. | ||
func IsComparable(*types.Interface) bool { | ||
return false | ||
} | ||
|
||
// IsConstraint reports whether iface may only be used as a type parameter | ||
// constraint (i.e. has a type set or is the comparable interface). | ||
func IsConstraint(*types.Interface) bool { | ||
return false | ||
} | ||
|
||
// ForNamed extracts the (possibly empty) type parameter object list from | ||
// named. | ||
func ForNamed(*types.Named) []*types.TypeName { | ||
return nil | ||
} | ||
|
||
// NamedTArgs extracts the (possibly empty) type argument list from named. | ||
func NamedTArgs(*types.Named) []types.Type { | ||
return nil | ||
} | ||
|
||
// InitInferred initializes info to record inferred type information. | ||
func InitInferred(*types.Info) { | ||
} | ||
|
||
// GetInferred extracts inferred type information from info for e. | ||
// | ||
// The expression e may have an inferred type if it is an *ast.IndexExpr | ||
// representing partial instantiation of a generic function type for which type | ||
// arguments have been inferred using constraint type inference, or if it is an | ||
// *ast.CallExpr for which type type arguments have be inferred using both | ||
// constraint type inference and function argument inference. | ||
func GetInferred(*types.Info, ast.Expr) ([]types.Type, *types.Signature) { | ||
return nil, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
// Copyright 2021 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. | ||
|
||
//go:build typeparams && go1.17 | ||
// +build typeparams,go1.17 | ||
|
||
package typeparams | ||
|
||
import ( | ||
"go/ast" | ||
"go/types" | ||
) | ||
|
||
// NOTE: doc comments must be kept in sync with notypeparams.go. | ||
|
||
// Enabled reports whether type parameters are enabled in the current build | ||
// environment. | ||
const Enabled = true | ||
|
||
// UnpackIndex extracts all index expressions from e. For non-generic code this | ||
// is always one expression: e.Index, but may be more than one expression for | ||
// generic type instantiation. | ||
func UnpackIndex(e *ast.IndexExpr) []ast.Expr { | ||
if x, _ := e.Index.(*ast.ListExpr); x != nil { | ||
return x.ElemList | ||
} | ||
if e.Index != nil { | ||
return []ast.Expr{e.Index} | ||
} | ||
return nil | ||
} | ||
|
||
// IsListExpr reports whether n is an *ast.ListExpr, which is a new node type | ||
// introduced to hold type arguments for generic type instantiation. | ||
func IsListExpr(n ast.Node) bool { | ||
_, ok := n.(*ast.ListExpr) | ||
return ok | ||
} | ||
|
||
// ForTypeDecl extracts the (possibly nil) type parameter node list from n. | ||
func ForTypeDecl(n *ast.TypeSpec) *ast.FieldList { | ||
return n.TParams | ||
} | ||
|
||
// ForFuncDecl extracts the (possibly nil) type parameter node list from n. | ||
func ForFuncDecl(n *ast.FuncDecl) *ast.FieldList { | ||
if n.Type != nil { | ||
return n.Type.TParams | ||
} | ||
return nil | ||
} | ||
|
||
// ForSignature extracts the (possibly empty) type parameter object list from | ||
// sig. | ||
func ForSignature(sig *types.Signature) []*types.TypeName { | ||
return sig.TParams() | ||
} | ||
|
||
// HasTypeSet reports if iface has a type set. | ||
func HasTypeSet(iface *types.Interface) bool { | ||
return iface.HasTypeList() | ||
} | ||
|
||
// IsComparable reports if iface is the comparable interface. | ||
func IsComparable(iface *types.Interface) bool { | ||
return iface.IsComparable() | ||
} | ||
|
||
// IsConstraint reports whether iface may only be used as a type parameter | ||
// constraint (i.e. has a type set or is the comparable interface). | ||
func IsConstraint(iface *types.Interface) bool { | ||
return iface.IsConstraint() | ||
} | ||
|
||
// ForNamed extracts the (possibly empty) type parameter object list from | ||
// named. | ||
func ForNamed(named *types.Named) []*types.TypeName { | ||
return named.TParams() | ||
} | ||
|
||
// NamedTArgs extracts the (possibly empty) type argument list from named. | ||
func NamedTArgs(named *types.Named) []types.Type { | ||
return named.TArgs() | ||
} | ||
|
||
// InitInferred initializes info to record inferred type information. | ||
func InitInferred(info *types.Info) { | ||
info.Inferred = make(map[ast.Expr]types.Inferred) | ||
} | ||
|
||
// GetInferred extracts inferred type information from info for e. | ||
// | ||
// The expression e may have an inferred type if it is an *ast.IndexExpr | ||
// representing partial instantiation of a generic function type for which type | ||
// arguments have been inferred using constraint type inference, or if it is an | ||
// *ast.CallExpr for which type type arguments have be inferred using both | ||
// constraint type inference and function argument inference. | ||
func GetInferred(info *types.Info, e ast.Expr) ([]types.Type, *types.Signature) { | ||
if info.Inferred == nil { | ||
return nil, nil | ||
} | ||
inf := info.Inferred[e] | ||
return inf.Targs, inf.Sig | ||
} |