mirror of https://github.com/golang/go.git
go/parser, go/types: various minor fixes around printing and tracing
- set correct token position for ast.ContractType - print "best effort" interface position in "complete interface" traces - don't print trace output for types that are already set up - print contract "signtature" when printing Contract type Also: rebased on top of today's master branch Change-Id: I6a528ce51a4152c25ad5d83ad52e01df8e89d283
This commit is contained in:
parent
234ccd01f3
commit
6db0b6d33a
|
|
@ -1288,7 +1288,7 @@ func (p *parser) parseChanType(typeContext bool) *ast.ChanType {
|
|||
|
||||
// ContractType = "(" [ IdentList [ "," ] ] ")" "{" { Constraint ";" } "}" .
|
||||
// (The "contract" keyword is already consumed.)
|
||||
func (p *parser) parseContractType() *ast.ContractType {
|
||||
func (p *parser) parseContractType(pos token.Pos) *ast.ContractType {
|
||||
if p.trace {
|
||||
defer un(trace(p, "ContractType"))
|
||||
}
|
||||
|
|
@ -1314,7 +1314,7 @@ func (p *parser) parseContractType() *ast.ContractType {
|
|||
}
|
||||
rbrace := p.expect(token.RBRACE)
|
||||
|
||||
return &ast.ContractType{TParams: params, Lbrace: lbrace, Constraints: constraints, Rbrace: rbrace}
|
||||
return &ast.ContractType{Contract: pos, TParams: params, Lbrace: lbrace, Constraints: constraints, Rbrace: rbrace}
|
||||
}
|
||||
|
||||
// Constraint = TypeParam TypeOrMethod { "," TypeOrMethod } | ContractTypeName "(" [ TypeList [ "," ] ] ")" .
|
||||
|
|
@ -1408,8 +1408,7 @@ func (p *parser) tryIdentOrType(typeContext bool) ast.Expr {
|
|||
if p.lit == "contract" {
|
||||
pos := p.pos
|
||||
p.next()
|
||||
typ := p.parseContractType()
|
||||
typ.Contract = pos // set keyword position
|
||||
typ := p.parseContractType(pos)
|
||||
return typ
|
||||
}
|
||||
typ := p.parseTypeName(nil)
|
||||
|
|
@ -2655,7 +2654,7 @@ func (p *parser) parseStmt() (s ast.Stmt) {
|
|||
// ----------------------------------------------------------------------------
|
||||
// Declarations
|
||||
|
||||
type parseSpecFunction func(doc *ast.CommentGroup, keyword token.Token, iota int) ast.Spec
|
||||
type parseSpecFunction func(doc *ast.CommentGroup, pos token.Pos, keyword token.Token, iota int) ast.Spec
|
||||
|
||||
func isValidImport(lit string) bool {
|
||||
const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
|
||||
|
|
@ -2668,7 +2667,7 @@ func isValidImport(lit string) bool {
|
|||
return s != ""
|
||||
}
|
||||
|
||||
func (p *parser) parseImportSpec(doc *ast.CommentGroup, _ token.Token, _ int) ast.Spec {
|
||||
func (p *parser) parseImportSpec(doc *ast.CommentGroup, _ token.Pos, _ token.Token, _ int) ast.Spec {
|
||||
if p.trace {
|
||||
defer un(trace(p, "ImportSpec"))
|
||||
}
|
||||
|
|
@ -2707,7 +2706,7 @@ func (p *parser) parseImportSpec(doc *ast.CommentGroup, _ token.Token, _ int) as
|
|||
return spec
|
||||
}
|
||||
|
||||
func (p *parser) parseValueSpec(doc *ast.CommentGroup, keyword token.Token, iota int) ast.Spec {
|
||||
func (p *parser) parseValueSpec(doc *ast.CommentGroup, _ token.Pos, keyword token.Token, iota int) ast.Spec {
|
||||
if p.trace {
|
||||
defer un(trace(p, keyword.String()+"Spec"))
|
||||
}
|
||||
|
|
@ -2754,7 +2753,7 @@ func (p *parser) parseValueSpec(doc *ast.CommentGroup, keyword token.Token, iota
|
|||
return spec
|
||||
}
|
||||
|
||||
func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Token, _ int) ast.Spec {
|
||||
func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Pos, _ token.Token, _ int) ast.Spec {
|
||||
if p.trace {
|
||||
defer un(trace(p, "TypeSpec"))
|
||||
}
|
||||
|
|
@ -2835,7 +2834,7 @@ func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Token, _ int) ast.
|
|||
return spec
|
||||
}
|
||||
|
||||
func (p *parser) parseContractSpec(doc *ast.CommentGroup, _ token.Token, _ int) ast.Spec {
|
||||
func (p *parser) parseContractSpec(doc *ast.CommentGroup, pos token.Pos, _ token.Token, _ int) ast.Spec {
|
||||
if p.trace {
|
||||
defer un(trace(p, "ContractSpec"))
|
||||
}
|
||||
|
|
@ -2843,7 +2842,7 @@ func (p *parser) parseContractSpec(doc *ast.CommentGroup, _ token.Token, _ int)
|
|||
// For now we represent a contract specification like a type representation.
|
||||
// They cannot have "outer" type parameters, though.
|
||||
ident := p.parseIdent()
|
||||
typ := p.parseContractType()
|
||||
typ := p.parseContractType(pos)
|
||||
spec := &ast.TypeSpec{Doc: doc, Name: ident, Type: typ}
|
||||
p.declare(spec, nil, p.topScope, ast.Typ, ident)
|
||||
p.expectSemi() // call before accessing p.linecomment
|
||||
|
|
@ -2865,12 +2864,12 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.Gen
|
|||
lparen = p.pos
|
||||
p.next()
|
||||
for iota := 0; p.tok != token.RPAREN && p.tok != token.EOF; iota++ {
|
||||
list = append(list, f(p.leadComment, keyword, iota))
|
||||
list = append(list, f(p.leadComment, pos, keyword, iota))
|
||||
}
|
||||
rparen = p.expect(token.RPAREN)
|
||||
p.expectSemi()
|
||||
} else {
|
||||
list = append(list, f(nil, keyword, 0))
|
||||
list = append(list, f(nil, pos, keyword, 0))
|
||||
}
|
||||
|
||||
return &ast.GenDecl{
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@ func (check *Checker) checkFiles(files []*ast.File) (err error) {
|
|||
print("== collectObjects ==")
|
||||
check.collectObjects()
|
||||
|
||||
print("== packagetObjects ==")
|
||||
print("== packageObjects ==")
|
||||
check.packageObjects()
|
||||
|
||||
print("== processDelayed ==")
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ func (check *Checker) contractType(contr *Contract, e *ast.ContractType) {
|
|||
if iface == nil {
|
||||
ifaces[tpar] = &emptyInterface
|
||||
} else {
|
||||
check.completeInterface(iface)
|
||||
check.completeInterface(e.Pos(), iface)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ func pathString(path []Object) string {
|
|||
// objDecl type-checks the declaration of obj in its respective (file) context.
|
||||
// For the meaning of def, see Checker.definedType, in typexpr.go.
|
||||
func (check *Checker) objDecl(obj Object, def *Named) {
|
||||
if check.conf.Trace {
|
||||
if check.conf.Trace && obj.Type() == nil {
|
||||
check.trace(obj.Pos(), "-- checking %s (%s, objPath = %s)", obj, obj.color(), pathString(check.objPath))
|
||||
check.indent++
|
||||
defer func() {
|
||||
|
|
|
|||
|
|
@ -558,7 +558,7 @@ func (check *Checker) convertUntyped(x *operand, target Type) {
|
|||
target = Typ[UntypedNil]
|
||||
} else {
|
||||
// cannot assign untyped values to non-empty interfaces
|
||||
check.completeInterface(t)
|
||||
check.completeInterface(token.NoPos, t)
|
||||
if !t.Empty() {
|
||||
goto Error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ func WriteExpr(buf *bytes.Buffer, x ast.Expr) {
|
|||
|
||||
switch x := x.(type) {
|
||||
default:
|
||||
buf.WriteString("(bad expr)") // nil, ast.BadExpr, ast.KeyValueExpr
|
||||
buf.WriteString("(ast: bad expr)") // nil, ast.BadExpr, ast.KeyValueExpr
|
||||
|
||||
case *ast.Ident:
|
||||
buf.WriteString(x.Name)
|
||||
|
|
@ -164,6 +164,12 @@ func WriteExpr(buf *bytes.Buffer, x ast.Expr) {
|
|||
}
|
||||
buf.WriteString(s)
|
||||
WriteExpr(buf, x.Value)
|
||||
|
||||
case *ast.ContractType:
|
||||
buf.WriteString("contract(")
|
||||
writeIdentList(buf, x.TParams)
|
||||
buf.WriteString("){...}")
|
||||
// TODO(gri) fill in the rest
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -199,12 +205,7 @@ func writeFieldList(buf *bytes.Buffer, fields *ast.FieldList, sep string, iface
|
|||
}
|
||||
|
||||
// field list names
|
||||
for i, name := range f.Names {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
buf.WriteString(name.Name)
|
||||
}
|
||||
writeIdentList(buf, f.Names)
|
||||
|
||||
// types of interface methods consist of signatures only
|
||||
if sig, _ := f.Type.(*ast.FuncType); sig != nil && iface {
|
||||
|
|
@ -222,3 +223,12 @@ func writeFieldList(buf *bytes.Buffer, fields *ast.FieldList, sep string, iface
|
|||
// ignore tag
|
||||
}
|
||||
}
|
||||
|
||||
func writeIdentList(buf *bytes.Buffer, list []*ast.Ident) {
|
||||
for i, x := range list {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
buf.WriteString(x.Name)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
package types
|
||||
|
||||
import "go/token"
|
||||
|
||||
// LookupFieldOrMethod looks up a field or method with given package and name
|
||||
// in T and returns the corresponding *Var or *Func, an index sequence, and a
|
||||
// bool indicating if there were any pointer indirections on the path to the
|
||||
|
|
@ -175,7 +177,7 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack
|
|||
case *Interface:
|
||||
// look for a matching method
|
||||
// TODO(gri) t.allMethods is sorted - use binary search
|
||||
check.completeInterface(t)
|
||||
check.completeInterface(token.NoPos, t)
|
||||
if i, m := lookupMethod(t.allMethods, pkg, name); m != nil {
|
||||
assert(m.typ != nil)
|
||||
index = concat(e.index, i)
|
||||
|
|
@ -276,7 +278,7 @@ func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType b
|
|||
// To improve error messages, also report the wrong signature
|
||||
// when the method exists on *V instead of V.
|
||||
func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, wrongType *Func) {
|
||||
check.completeInterface(T)
|
||||
check.completeInterface(token.NoPos, T)
|
||||
|
||||
// fast path for common case
|
||||
if T.Empty() {
|
||||
|
|
@ -284,7 +286,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
|
|||
}
|
||||
|
||||
if ityp, _ := V.Underlying().(*Interface); ityp != nil {
|
||||
check.completeInterface(ityp)
|
||||
check.completeInterface(token.NoPos, ityp)
|
||||
// TODO(gri) allMethods is sorted - can do this more efficiently
|
||||
for _, m := range T.allMethods {
|
||||
_, obj := lookupMethod(ityp.allMethods, m.pkg, m.name)
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) bool {
|
|||
return Vb.kind == UntypedBool && isBoolean(Tu)
|
||||
}
|
||||
case *Interface:
|
||||
check.completeInterface(t)
|
||||
check.completeInterface(token.NoPos, t)
|
||||
return x.isNil() || t.Empty()
|
||||
case *Pointer, *Signature, *Slice, *Map, *Chan:
|
||||
return x.isNil()
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@
|
|||
|
||||
package types
|
||||
|
||||
import "sort"
|
||||
import (
|
||||
"go/token"
|
||||
"sort"
|
||||
)
|
||||
|
||||
func isNamed(typ Type) bool {
|
||||
if _, ok := typ.(*Basic); ok {
|
||||
|
|
@ -212,8 +215,8 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair, tparams
|
|||
// that case, interfaces are expected to be complete and lazy completion
|
||||
// here is not needed.
|
||||
if check != nil {
|
||||
check.completeInterface(x)
|
||||
check.completeInterface(y)
|
||||
check.completeInterface(token.NoPos, x)
|
||||
check.completeInterface(token.NoPos, y)
|
||||
}
|
||||
a := x.allMethods
|
||||
b := y.allMethods
|
||||
|
|
|
|||
|
|
@ -307,22 +307,6 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) Type {
|
|||
def.setUnderlying(typ)
|
||||
return typ
|
||||
|
||||
/*
|
||||
// We may have a parameterized type or an "instantiated" contract.
|
||||
typ := new(Parameterized)
|
||||
def.setUnderlying(typ)
|
||||
if check.parameterizedType(typ, e) {
|
||||
if IsParameterizedList(typ.targs) {
|
||||
return typ
|
||||
}
|
||||
typ := check.inst(typ.tname, typ.targs)
|
||||
def.setUnderlying(typ) // TODO(gri) do we need this?
|
||||
return typ
|
||||
}
|
||||
// TODO(gri) If we have a cycle and we reach here, "leafs" of
|
||||
// the cycle may refer to a not fully set up Parameterized typ.
|
||||
*/
|
||||
|
||||
case *ast.ParenExpr:
|
||||
return check.definedType(e.X, def)
|
||||
|
||||
|
|
@ -649,10 +633,10 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
|
|||
sort.Sort(byUniqueMethodName(ityp.methods))
|
||||
sort.Stable(byUniqueTypeName(ityp.embeddeds))
|
||||
|
||||
check.later(func() { check.completeInterface(ityp) })
|
||||
check.later(func() { check.completeInterface(iface.Pos(), ityp) })
|
||||
}
|
||||
|
||||
func (check *Checker) completeInterface(ityp *Interface) {
|
||||
func (check *Checker) completeInterface(pos token.Pos, ityp *Interface) {
|
||||
if ityp.allMethods != nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -666,11 +650,18 @@ func (check *Checker) completeInterface(ityp *Interface) {
|
|||
}
|
||||
|
||||
if check.conf.Trace {
|
||||
check.trace(token.NoPos, "complete %s", ityp)
|
||||
// Types don't generally have position information.
|
||||
// If we don't have a valid pos provided, try to use
|
||||
// one close enough.
|
||||
if !pos.IsValid() && len(ityp.methods) > 0 {
|
||||
pos = ityp.methods[0].pos
|
||||
}
|
||||
|
||||
check.trace(pos, "complete %s", ityp)
|
||||
check.indent++
|
||||
defer func() {
|
||||
check.indent--
|
||||
check.trace(token.NoPos, "=> %s", ityp)
|
||||
check.trace(pos, "=> %s", ityp)
|
||||
}()
|
||||
}
|
||||
|
||||
|
|
@ -729,7 +720,7 @@ func (check *Checker) completeInterface(ityp *Interface) {
|
|||
// Ignore it.
|
||||
continue
|
||||
}
|
||||
check.completeInterface(typ)
|
||||
check.completeInterface(pos, typ)
|
||||
for _, m := range typ.allMethods {
|
||||
addMethod(pos, m, false) // use embedding position pos rather than m.pos
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue