1
0
mirror of https://github.com/golang/go synced 2024-11-26 07:38:00 -07:00

[dev.typeparams] go/types: import changes to types.Info from dev.go2go

Import changes related to tracking type inferences and sanitizing
types.Info from the dev.go2go branch. Notably, the following were all
intentionally omitted from this import:
 + types.Error.Full is not imported, due to it being a public API that
   requires some further thought.
 + The Config.AcceptMethodTypeParams, InferFromConstraints, and Trace
   flag are not imported. The expectation is that we will not accept
   method type parameters for now, will always infer from constraints,
   and will continue to use the trace constant to guard tracing.
 + Some trace annotations are not imported to from the checking pass. We
   can add them back later, but for now they seemed verbose.
 + Checker.useBrackets is removed. This is no longer configurable.

Change-Id: I7f6315d66b200c92ffd1e55c9fd425a5d99149ed
Reviewed-on: https://go-review.googlesource.com/c/go/+/278312
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Robert Findley <rfindley@google.com>
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Rob Findley 2020-12-15 09:49:10 -05:00 committed by Robert Findley
parent 6b18081d01
commit 1306435103
5 changed files with 187 additions and 7 deletions

View File

@ -177,6 +177,12 @@ type Info struct {
// qualified identifiers are collected in the Uses map. // qualified identifiers are collected in the Uses map.
Types map[ast.Expr]TypeAndValue Types map[ast.Expr]TypeAndValue
// Inferred maps calls of parameterized functions that use
// type inference to the inferred type arguments and signature
// of the function called. The recorded "call" expression may be
// an *ast.CallExpr (as in f(x)), or an *ast.IndexExpr (s in f[T]).
Inferred map[ast.Expr]Inferred
// Defs maps identifiers to the objects they define (including // Defs maps identifiers to the objects they define (including
// package names, dots "." of dot-imports, and blank "_" identifiers). // package names, dots "." of dot-imports, and blank "_" identifiers).
// For identifiers that do not denote objects (e.g., the package name // For identifiers that do not denote objects (e.g., the package name
@ -333,6 +339,13 @@ func (tv TypeAndValue) HasOk() bool {
return tv.mode == commaok || tv.mode == mapindex return tv.mode == commaok || tv.mode == mapindex
} }
// Inferred reports the inferred type arguments and signature
// for a parameterized function call that uses type inference.
type Inferred struct {
Targs []Type
Sig *Signature
}
// An Initializer describes a package-level variable, or a list of variables in case // An Initializer describes a package-level variable, or a list of variables in case
// of a multi-valued initialization expression, and the corresponding initialization // of a multi-valued initialization expression, and the corresponding initialization
// expression. // expression.

View File

@ -19,18 +19,18 @@ const (
trace = false // turn on for detailed type resolution traces trace = false // turn on for detailed type resolution traces
) )
// If Strict is set, the type-checker enforces additional // If forceStrict is set, the type-checker enforces additional
// rules not specified by the Go 1 spec, but which will // rules not specified by the Go 1 spec, but which will
// catch guaranteed run-time errors if the respective // catch guaranteed run-time errors if the respective
// code is executed. In other words, programs passing in // code is executed. In other words, programs passing in
// Strict mode are Go 1 compliant, but not all Go 1 programs // strict mode are Go 1 compliant, but not all Go 1 programs
// will pass in Strict mode. The additional rules are: // will pass in strict mode. The additional rules are:
// //
// - A type assertion x.(T) where T is an interface type // - A type assertion x.(T) where T is an interface type
// is invalid if any (statically known) method that exists // is invalid if any (statically known) method that exists
// for both x and T have different signatures. // for both x and T have different signatures.
// //
const strict = false const forceStrict = false
// exprInfo stores information about an untyped expression. // exprInfo stores information about an untyped expression.
type exprInfo struct { type exprInfo struct {
@ -192,6 +192,7 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch
fset: fset, fset: fset,
pkg: pkg, pkg: pkg,
Info: info, Info: info,
nextId: 1,
objMap: make(map[Object]*declInfo), objMap: make(map[Object]*declInfo),
impMap: make(map[importKey]*Package), impMap: make(map[importKey]*Package),
posMap: make(map[*Interface][]token.Pos), posMap: make(map[*Interface][]token.Pos),
@ -278,6 +279,10 @@ func (check *Checker) checkFiles(files []*ast.File) (err error) {
check.recordUntyped() check.recordUntyped()
if check.Info != nil {
sanitizeInfo(check.Info)
}
check.pkg.complete = true check.pkg.complete = true
return return
} }
@ -380,6 +385,14 @@ func (check *Checker) recordCommaOkTypes(x ast.Expr, a [2]Type) {
} }
} }
func (check *Checker) recordInferred(call ast.Expr, targs []Type, sig *Signature) {
assert(call != nil)
assert(sig != nil)
if m := check.Inferred; m != nil {
m[call] = Inferred{targs, sig}
}
}
func (check *Checker) recordDef(id *ast.Ident, obj Object) { func (check *Checker) recordDef(id *ast.Ident, obj Object) {
assert(id != nil) assert(id != nil)
if m := check.Defs; m != nil { if m := check.Defs; m != nil {

View File

@ -343,7 +343,7 @@ func (check *Checker) assertableTo(V *Interface, T Type) (method, wrongType *Fun
// no static check is required if T is an interface // no static check is required if T is an interface
// spec: "If T is an interface type, x.(T) asserts that the // spec: "If T is an interface type, x.(T) asserts that the
// dynamic type of x implements the interface T." // dynamic type of x implements the interface T."
if _, ok := T.Underlying().(*Interface); ok && !strict { if _, ok := T.Underlying().(*Interface); ok && !forceStrict {
return return
} }
return check.missingMethod(T, V, false) return check.missingMethod(T, V, false)

View File

@ -36,6 +36,9 @@ type Object interface {
// color returns the object's color. // color returns the object's color.
color() color color() color
// setType sets the type of the object.
setType(Type)
// setOrder sets the order number of the object. It must be > 0. // setOrder sets the order number of the object. It must be > 0.
setOrder(uint32) setOrder(uint32)
@ -149,6 +152,7 @@ func (obj *object) color() color { return obj.color_ }
func (obj *object) scopePos() token.Pos { return obj.scopePos_ } func (obj *object) scopePos() token.Pos { return obj.scopePos_ }
func (obj *object) setParent(parent *Scope) { obj.parent = parent } func (obj *object) setParent(parent *Scope) { obj.parent = parent }
func (obj *object) setType(typ Type) { obj.typ = typ }
func (obj *object) setOrder(order uint32) { assert(order > 0); obj.order_ = order } func (obj *object) setOrder(order uint32) { assert(order > 0); obj.order_ = order }
func (obj *object) setColor(color color) { assert(color != white); obj.color_ = color } func (obj *object) setColor(color color) { assert(color != white); obj.color_ = color }
func (obj *object) setScopePos(pos token.Pos) { obj.scopePos_ = pos } func (obj *object) setScopePos(pos token.Pos) { obj.scopePos_ = pos }
@ -299,7 +303,7 @@ type Func struct {
// NewFunc returns a new function with the given signature, representing // NewFunc returns a new function with the given signature, representing
// the function's type. // the function's type.
func NewFunc(pos token.Pos, pkg *Package, name string, sig *Signature) *Func { func NewFunc(pos token.Pos, pkg *Package, name string, sig *Signature) *Func {
// don't store a nil signature // don't store a (typed) nil signature
var typ Type var typ Type
if sig != nil { if sig != nil {
typ = sig typ = sig
@ -420,7 +424,7 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
if tname.IsAlias() { if tname.IsAlias() {
buf.WriteString(" =") buf.WriteString(" =")
} else { } else {
typ = typ.Underlying() typ = under(typ)
} }
} }

150
src/go/types/sanitize.go Normal file
View File

@ -0,0 +1,150 @@
// Copyright 2020 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 types
// sanitizeInfo walks the types contained in info to ensure that all instances
// are expanded.
func sanitizeInfo(info *Info) {
var s sanitizer = make(map[Type]Type)
// Note: Some map entries are not references.
// If modified, they must be assigned back.
for e, tv := range info.Types {
tv.Type = s.typ(tv.Type)
info.Types[e] = tv
}
for e, inf := range info.Inferred {
for i, targ := range inf.Targs {
inf.Targs[i] = s.typ(targ)
}
inf.Sig = s.typ(inf.Sig).(*Signature)
info.Inferred[e] = inf
}
for _, obj := range info.Defs {
if obj != nil {
obj.setType(s.typ(obj.Type()))
}
}
for _, obj := range info.Uses {
if obj != nil {
obj.setType(s.typ(obj.Type()))
}
}
// TODO(gri) sanitize as needed
// - info.Implicits
// - info.Selections
// - info.Scopes
// - info.InitOrder
}
type sanitizer map[Type]Type
func (s sanitizer) typ(typ Type) Type {
if t, found := s[typ]; found {
return t
}
s[typ] = typ
switch t := typ.(type) {
case nil, *Basic, *bottom, *top:
// nothing to do
case *Array:
t.elem = s.typ(t.elem)
case *Slice:
t.elem = s.typ(t.elem)
case *Struct:
s.varList(t.fields)
case *Pointer:
t.base = s.typ(t.base)
case *Tuple:
s.tuple(t)
case *Signature:
s.var_(t.recv)
s.tuple(t.params)
s.tuple(t.results)
case *Sum:
s.typeList(t.types)
case *Interface:
s.funcList(t.methods)
s.typ(t.types)
s.typeList(t.embeddeds)
s.funcList(t.allMethods)
s.typ(t.allTypes)
case *Map:
t.key = s.typ(t.key)
t.elem = s.typ(t.elem)
case *Chan:
t.elem = s.typ(t.elem)
case *Named:
t.orig = s.typ(t.orig)
t.underlying = s.typ(t.underlying)
s.typeList(t.targs)
s.funcList(t.methods)
case *TypeParam:
t.bound = s.typ(t.bound)
case *instance:
typ = t.expand()
s[t] = typ
default:
panic("unimplemented")
}
return typ
}
func (s sanitizer) var_(v *Var) {
if v != nil {
v.typ = s.typ(v.typ)
}
}
func (s sanitizer) varList(list []*Var) {
for _, v := range list {
s.var_(v)
}
}
func (s sanitizer) tuple(t *Tuple) {
if t != nil {
s.varList(t.vars)
}
}
func (s sanitizer) func_(f *Func) {
if f != nil {
f.typ = s.typ(f.typ)
}
}
func (s sanitizer) funcList(list []*Func) {
for _, f := range list {
s.func_(f)
}
}
func (s sanitizer) typeList(list []Type) {
for i, t := range list {
list[i] = s.typ(t)
}
}