diff --git a/go/types/assignments.go b/go/types/assignments.go index 7eacaeb520..e5db6d20ab 100644 --- a/go/types/assignments.go +++ b/go/types/assignments.go @@ -89,7 +89,7 @@ func (check *checker) assignMulti(lhs []Object, rhs []ast.Expr) { if len(lhs) == len(rhs) { var x operand for i, e := range rhs { - check.expr(&x, e, nil, -1) + check.expr(&x, e, -1) if x.mode == invalid { goto Error } @@ -106,7 +106,7 @@ func (check *checker) assignMulti(lhs []Object, rhs []ast.Expr) { // Start with rhs so we have expression types // for declarations with implicit types. var x operand - check.expr(&x, rhs[0], nil, -1) + check.expr(&x, rhs[0], -1) if x.mode == invalid { goto Error } diff --git a/go/types/builtins.go b/go/types/builtins.go index d38de4d253..ba10262746 100644 --- a/go/types/builtins.go +++ b/go/types/builtins.go @@ -50,7 +50,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota // respective cases below do the work default: // argument must be an expression - check.expr(x, arg0, nil, iota) + check.expr(x, arg0, iota) if x.mode == invalid { goto Error } @@ -65,7 +65,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota } resultTyp := x.typ for _, arg := range args[1:] { - check.expr(x, arg, nil, iota) + check.expr(x, arg, iota) if x.mode == invalid { goto Error } @@ -134,7 +134,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota } var y operand - check.expr(&y, args[1], nil, iota) + check.expr(&y, args[1], iota) if y.mode == invalid { goto Error } @@ -196,7 +196,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota case _Copy: var y operand - check.expr(&y, args[1], nil, iota) + check.expr(&y, args[1], iota) if y.mode == invalid { goto Error } @@ -233,7 +233,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota check.invalidArg(x.pos(), "%s is not a map", x) goto Error } - check.expr(x, args[1], nil, iota) + check.expr(x, args[1], iota) if x.mode == invalid { goto Error } @@ -271,7 +271,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota x.typ = Typ[k] case _Make: - resultTyp := check.typ(arg0, false) + resultTyp := check.typ(arg0, iota, nil, false) if resultTyp == Typ[Invalid] { goto Error } @@ -303,7 +303,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota x.typ = resultTyp case _New: - resultTyp := check.typ(arg0, false) + resultTyp := check.typ(arg0, iota, nil, false) if resultTyp == Typ[Invalid] { goto Error } @@ -315,7 +315,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota case _Print, _Println: for _, arg := range args { - check.expr(x, arg, nil, -1) + check.expr(x, arg, iota) if x.mode == invalid { goto Error } @@ -337,7 +337,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota check.invalidArg(arg0.Pos(), "%s is not a selector expression", arg0) goto Error } - check.expr(x, arg.X, nil, -1) + check.expr(x, arg.X, iota) if x.mode == invalid { goto Error } @@ -397,7 +397,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota var t operand x1 := x for _, arg := range args { - check.rawExpr(x1, arg, nil, iota, true) // permit trace for types, e.g.: new(trace(T)) + check.rawExpr(x1, arg, nil, iota) // permit trace for types, e.g.: new(trace(T)) check.dump("%s: %s", x1.pos(), x1) x1 = &t // use incoming x only for first argument } diff --git a/go/types/call.go b/go/types/call.go index f226092f58..e85cf7bc13 100644 --- a/go/types/call.go +++ b/go/types/call.go @@ -12,13 +12,13 @@ import ( ) func (check *checker) call(x *operand, e *ast.CallExpr, iota int) { - check.exprOrType(x, e.Fun, iota, false) + check.exprOrType(x, e.Fun, iota) if x.mode == invalid { // We don't have a valid call or conversion but we have list of arguments. // Typecheck them independently for better partial type information in // the presence of type errors. for _, arg := range e.Args { - check.expr(x, arg, nil, iota) + check.expr(x, arg, iota) } goto Error @@ -52,7 +52,7 @@ func (check *checker) call(x *operand, e *ast.CallExpr, iota int) { n := 0 // parameter count if call != nil { // We have a single argument that is a function call. - check.expr(x, call, nil, -1) + check.expr(x, call, iota) if x.mode == invalid { goto Error // TODO(gri): we can do better } @@ -153,7 +153,7 @@ func (check *checker) argument(sig *Signature, i int, arg ast.Expr, x *operand, z.typ = par.typ if arg != nil { - check.expr(x, arg, z.typ, -1) + check.expr(x, arg, -1) } if x.mode == invalid { return // ignore this argument @@ -230,7 +230,7 @@ func (check *checker) selector(x *operand, e *ast.SelectorExpr, iota int) { } } - check.exprOrType(x, e.X, iota, false) + check.exprOrType(x, e.X, iota) if x.mode == invalid { goto Error } diff --git a/go/types/conversions.go b/go/types/conversions.go index 3fa8f5a067..87fe9342be 100644 --- a/go/types/conversions.go +++ b/go/types/conversions.go @@ -25,7 +25,7 @@ func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type, iota } // evaluate argument - check.expr(x, conv.Args[0], nil, iota) + check.expr(x, conv.Args[0], iota) if x.mode == invalid { goto Error } diff --git a/go/types/expr.go b/go/types/expr.go index 5ffc03e1a2..9ae85c12ed 100644 --- a/go/types/expr.go +++ b/go/types/expr.go @@ -9,7 +9,6 @@ package types import ( "go/ast" "go/token" - "strconv" "code.google.com/p/go.tools/go/exact" ) @@ -69,175 +68,6 @@ on the way down in updateExprType, or at the end of the type checker run, if present the Context.Expr method is invoked to notify a go/types client. */ -func (check *checker) collectParams(scope *Scope, list *ast.FieldList, variadicOk bool) (params []*Var, isVariadic bool) { - if list == nil { - return - } - var last *Var - for i, field := range list.List { - ftype := field.Type - if t, _ := ftype.(*ast.Ellipsis); t != nil { - ftype = t.Elt - if variadicOk && i == len(list.List)-1 { - isVariadic = true - } else { - check.invalidAST(field.Pos(), "... not permitted") - // ok to continue - } - } - // the parser ensures that f.Tag is nil and we don't - // care if a constructed AST contains a non-nil tag - typ := check.typ(ftype, true) - if len(field.Names) > 0 { - // named parameter - for _, name := range field.Names { - par := NewVar(name.Pos(), check.pkg, name.Name, typ) - check.declare(scope, name, par) - - last = par - copy := *par - params = append(params, ©) - } - } else { - // anonymous parameter - par := NewVar(ftype.Pos(), check.pkg, "", typ) - check.callImplicitObj(field, par) - - last = nil // not accessible inside function - params = append(params, par) - } - } - // For a variadic function, change the last parameter's object type - // from T to []T (this is the type used inside the function), but - // keep the params list unchanged (this is the externally visible type). - if isVariadic && last != nil { - last.typ = &Slice{elt: last.typ} - } - return -} - -func (check *checker) collectMethods(list *ast.FieldList, cycleOk bool) (methods []*Func) { - if list == nil { - return nil - } - scope := NewScope(nil) - for _, f := range list.List { - typ := check.typ(f.Type, cycleOk) - // the parser ensures that f.Tag is nil and we don't - // care if a constructed AST contains a non-nil tag - if len(f.Names) > 0 { - // methods (the parser ensures that there's only one - // and we don't care if a constructed AST has more) - sig, ok := typ.(*Signature) - if !ok { - check.invalidAST(f.Type.Pos(), "%s is not a method signature", typ) - continue - } - for _, name := range f.Names { - m := NewFunc(name.Pos(), check.pkg, name.Name, sig) - check.declare(scope, name, m) - methods = append(methods, m) - } - } else { - // embedded interface - switch t := typ.Underlying().(type) { - case nil: - // The underlying type is in the process of being defined - // but we need it in order to complete this type. For now - // complain with an "unimplemented" error. This requires - // a bit more work. - // TODO(gri) finish this. - check.errorf(f.Type.Pos(), "reference to incomplete type %s - unimplemented", f.Type) - case *Interface: - for _, m := range t.methods { - check.declare(scope, nil, m) - methods = append(methods, m) - } - default: - if t != Typ[Invalid] { - check.errorf(f.Type.Pos(), "%s is not an interface type", typ) - } - } - } - } - return -} - -func (check *checker) tag(t *ast.BasicLit) string { - if t != nil { - if t.Kind == token.STRING { - if val, err := strconv.Unquote(t.Value); err == nil { - return val - } - } - check.invalidAST(t.Pos(), "incorrect tag syntax: %q", t.Value) - } - return "" -} - -func (check *checker) collectFields(list *ast.FieldList, cycleOk bool) (fields []*Field, tags []string) { - if list == nil { - return - } - - scope := NewScope(nil) - - var typ Type // current field typ - var tag string // current field tag - add := func(field *ast.Field, ident *ast.Ident, name string, anonymous bool, pos token.Pos) { - if tag != "" && tags == nil { - tags = make([]string, len(fields)) - } - if tags != nil { - tags = append(tags, tag) - } - - fld := NewField(pos, check.pkg, name, typ, anonymous) - check.declare(scope, ident, fld) - fields = append(fields, fld) - } - - for _, f := range list.List { - typ = check.typ(f.Type, cycleOk) - tag = check.tag(f.Tag) - if len(f.Names) > 0 { - // named fields - for _, name := range f.Names { - add(f, name, name.Name, false, name.Pos()) - } - } else { - // anonymous field - pos := f.Type.Pos() - t, isPtr := deref(typ) - switch t := t.(type) { - case *Basic: - add(f, nil, t.name, true, pos) - case *Named: - // spec: "An embedded type must be specified as a type name - // T or as a pointer to a non-interface type name *T, and T - // itself may not be a pointer type." - switch t.underlying.(type) { - case *Pointer: - check.errorf(pos, "anonymous field type cannot be a pointer") - continue // ignore this field - case *Interface: - if isPtr { - check.errorf(pos, "anonymous field type cannot be a pointer to an interface") - continue // ignore this field - } - } - add(f, nil, t.obj.name, true, pos) - default: - if typ != Typ[Invalid] { - check.invalidAST(pos, "anonymous field type %s must be named", typ) - } - } - } - } - - return -} - type opPredicates map[token.Token]func(Type) bool var unaryOpPredicates = opPredicates{ @@ -784,8 +614,8 @@ var binaryOpPredicates = opPredicates{ func (check *checker) binary(x *operand, lhs, rhs ast.Expr, op token.Token, iota int) { var y operand - check.expr(x, lhs, nil, iota) - check.expr(&y, rhs, nil, iota) + check.expr(x, lhs, iota) + check.expr(&y, rhs, iota) if x.mode == invalid { return @@ -859,7 +689,7 @@ func (check *checker) binary(x *operand, lhs, rhs ast.Expr, op token.Token, iota // TODO(gri): Do we need iota? func (check *checker) index(arg ast.Expr, length int64, iota int) (i int64, ok bool) { var x operand - check.expr(&x, arg, nil, iota) + check.expr(&x, arg, iota) // an untyped constant must be representable as Int check.convertUntyped(&x, Typ[Int]) @@ -931,7 +761,7 @@ func (check *checker) indexedElts(elts []ast.Expr, typ Type, length int64, iota // check element against composite literal element type var x operand - check.expr(&x, eval, typ, iota) + check.exprWithHint(&x, eval, typ, iota) if !check.assignment(&x, typ) && x.mode != invalid { check.errorf(x.pos(), "cannot use %s as %s value in array or slice literal", &x, typ) } @@ -939,7 +769,11 @@ func (check *checker) indexedElts(elts []ast.Expr, typ Type, length int64, iota return max } -func (check *checker) callExpr(x *operand) { +func (check *checker) callExpr(x *operand, ignore *bool) { + if *ignore { + return + } + // convert x into a user-friendly set of values var typ Type var val exact.Value @@ -977,86 +811,28 @@ func (check *checker) callExpr(x *operand) { // value or type. If an error occurred, x.mode is set to invalid. // If hint != nil, it is the type of a composite literal element. // iota >= 0 indicates that the expression is part of a constant declaration. -// cycleOk indicates whether it is ok for a type expression to refer to itself. // -func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycleOk bool) { +func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int) { // make sure x has a valid state for deferred functions in case of bailout // (was issue 5770) x.mode = invalid x.typ = Typ[Invalid] if trace { - c := "" - if cycleOk { - c = " ⨁" - } - check.trace(e.Pos(), "%s%s", e, c) + check.trace(e.Pos(), "%s", e) defer check.untrace("=> %s", x) } // record final type of x if untyped, notify clients of type otherwise - defer check.callExpr(x) + ignore := false // if set, don't do anything in the deferred call + defer check.callExpr(x, &ignore) switch e := e.(type) { case *ast.BadExpr: goto Error // error was reported before case *ast.Ident: - obj := check.topScope.LookupParent(e.Name) - check.callIdent(e, obj) - if obj == nil { - if e.Name == "_" { - check.errorf(e.Pos(), "cannot use _ as value or type") - } else { - check.errorf(e.Pos(), "undeclared name: %s", e.Name) - } - goto Error // error was reported before - } - - typ := obj.Type() - if check.objMap == nil { - if typ == nil { - check.dump("%s: %s not declared?", e.Pos(), e) - } - assert(typ != nil) - } else if typ == nil { - check.declareObject(obj, cycleOk) - } - - switch obj := obj.(type) { - case *Package: - check.errorf(e.Pos(), "use of package %s not in selector", obj.name) - goto Error - case *Const: - if obj.typ == Typ[Invalid] { - goto Error - } - x.mode = constant - if obj == universeIota { - if iota < 0 { - check.invalidAST(e.Pos(), "cannot use iota outside constant declaration") - goto Error - } - x.val = exact.MakeInt64(int64(iota)) - } else { - x.val = obj.val // may be nil if we don't know the constant value - } - case *TypeName: - x.mode = typexpr - if !cycleOk && obj.typ.Underlying() == nil { - check.errorf(obj.pos, "illegal cycle in declaration of %s", obj.name) - x.expr = e - x.typ = Typ[Invalid] - return // don't goto Error - want x.mode == typexpr - } - case *Var: - x.mode = variable - case *Func: - x.mode = value - default: - unreachable() - } - x.typ = obj.Type() + check.ident(x, e, iota, nil, false) case *ast.Ellipsis: // ellipses are handled explicitly where they are legal @@ -1072,7 +848,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle } case *ast.FuncLit: - if sig, ok := check.typ(e.Type, false).(*Signature); ok { + if sig, ok := check.typ(e.Type, iota, nil, false).(*Signature); ok { x.mode = value x.typ = sig check.later(nil, sig, e.Body) @@ -1093,12 +869,12 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle // We have an "open" [...]T array type. // Create a new ArrayType with unknown length (-1) // and finish setting it up after analyzing the literal. - typ = &Array{len: -1, elt: check.typ(atyp.Elt, cycleOk)} + typ = &Array{len: -1, elt: check.typ(atyp.Elt, iota, nil, false)} openArray = true } } if typ == nil { - typ = check.typ(e.Type, false) + typ = check.typ(e.Type, iota, nil, false) } } if typ == nil { @@ -1139,7 +915,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle continue } visited[i] = true - check.expr(x, kv.Value, nil, iota) + check.expr(x, kv.Value, iota) etyp := fld.typ if !check.assignment(x, etyp) { if x.mode != invalid { @@ -1155,7 +931,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle check.errorf(kv.Pos(), "mixture of field:value and value elements in struct literal") continue } - check.expr(x, e, nil, iota) + check.expr(x, e, iota) if i >= len(fields) { check.errorf(x.pos(), "too many values in struct literal") break // cannot continue @@ -1193,7 +969,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle check.errorf(e.Pos(), "missing key in map literal") continue } - check.expr(x, kv.Key, nil, iota) + check.expr(x, kv.Key, iota) if !check.assignment(x, utyp.key) { if x.mode != invalid { check.errorf(x.pos(), "cannot use %s as %s key in map literal", x, utyp.key) @@ -1207,7 +983,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle } visited[x.val] = true } - check.expr(x, kv.Value, utyp.elt, iota) + check.exprWithHint(x, kv.Value, utyp.elt, iota) if !check.assignment(x, utyp.elt) { if x.mode != invalid { check.errorf(x.pos(), "cannot use %s as %s value in map literal", x, utyp.elt) @@ -1225,13 +1001,13 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle x.typ = typ case *ast.ParenExpr: - check.rawExpr(x, e.X, nil, iota, cycleOk) + check.rawExpr(x, e.X, nil, iota) case *ast.SelectorExpr: check.selector(x, e, iota) case *ast.IndexExpr: - check.expr(x, e.X, nil, iota) + check.expr(x, e.X, iota) if x.mode == invalid { goto Error } @@ -1275,7 +1051,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle case *Map: var key operand - check.expr(&key, e.Index, nil, iota) + check.expr(&key, e.Index, iota) if !check.assignment(&key, typ.key) { if key.mode != invalid { check.invalidOp(key.pos(), "cannot use %s as map index of type %s", &key, typ.key) @@ -1302,7 +1078,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle // ok to continue case *ast.SliceExpr: - check.expr(x, e.X, nil, iota) + check.expr(x, e.X, iota) if x.mode == invalid { goto Error } @@ -1378,7 +1154,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle } case *ast.TypeAssertExpr: - check.expr(x, e.X, nil, iota) + check.expr(x, e.X, iota) if x.mode == invalid { goto Error } @@ -1392,7 +1168,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle check.invalidAST(e.Pos(), "use of .(type) outside type switch") goto Error } - typ := check.typ(e.Type, false) + typ := check.typ(e.Type, iota, nil, false) if typ == Typ[Invalid] { goto Error } @@ -1419,7 +1195,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle check.call(x, e, iota) case *ast.StarExpr: - check.exprOrType(x, e.X, iota, true) + check.exprOrType(x, e.X, iota) switch x.mode { case invalid: goto Error @@ -1436,7 +1212,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle } case *ast.UnaryExpr: - check.expr(x, e.X, nil, iota) + check.expr(x, e.X, iota) if x.mode == invalid { goto Error } @@ -1456,58 +1232,13 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle check.invalidAST(e.Pos(), "no key:value expected") goto Error - case *ast.ArrayType: - if e.Len != nil { - check.expr(x, e.Len, nil, iota) - if x.mode == invalid { - goto Error - } - if x.mode != constant { - if x.mode != invalid { - check.errorf(x.pos(), "array length %s must be constant", x) - } - goto Error - } - if !x.isInteger() { - check.errorf(x.pos(), "array length %s must be integer", x) - goto Error - } - n, ok := exact.Int64Val(x.val) - if !ok || n < 0 { - check.errorf(x.pos(), "invalid array length %s", x) - goto Error - } - x.typ = &Array{len: n, elt: check.typ(e.Elt, cycleOk)} - } else { - x.typ = &Slice{elt: check.typ(e.Elt, true)} - } + case *ast.ArrayType, *ast.StructType, *ast.FuncType, + *ast.InterfaceType, *ast.MapType, *ast.ChanType: x.mode = typexpr - - case *ast.StructType: - x.mode = typexpr - x.typ = NewStruct(check.collectFields(e.Fields, cycleOk)) - - case *ast.FuncType: - scope := NewScope(check.topScope) - if retainASTLinks { - scope.node = e - } - params, isVariadic := check.collectParams(scope, e.Params, true) - results, _ := check.collectParams(scope, e.Results, false) - x.mode = typexpr - x.typ = &Signature{scope: scope, recv: nil, params: NewTuple(params...), results: NewTuple(results...), isVariadic: isVariadic} - - case *ast.InterfaceType: - x.mode = typexpr - x.typ = NewInterface(check.collectMethods(e.Methods, cycleOk)) - - case *ast.MapType: - x.mode = typexpr - x.typ = &Map{key: check.typ(e.Key, true), elt: check.typ(e.Value, true)} - - case *ast.ChanType: - x.mode = typexpr - x.typ = &Chan{dir: e.Dir, elt: check.typ(e.Value, true)} + x.typ = check.typ(e, iota, nil, false) + // check.typ is already notifying clients + // of e's type; don't do it a 2nd time + ignore = true default: if debug { @@ -1525,18 +1256,12 @@ Error: x.expr = e } -// exprOrType is like rawExpr but reports an error if e doesn't represents a value or type. -func (check *checker) exprOrType(x *operand, e ast.Expr, iota int, cycleOk bool) { - check.rawExpr(x, e, nil, iota, cycleOk) - if x.mode == novalue { - check.errorf(x.pos(), "%s used as value or type", x) - x.mode = invalid - } -} - -// expr is like rawExpr but reports an error if e doesn't represents a value. -func (check *checker) expr(x *operand, e ast.Expr, hint Type, iota int) { - check.rawExpr(x, e, hint, iota, false) +// expr typechecks expression e and initializes x with the expression value. +// If an error occurred, x.mode is set to invalid. +// iota >= 0 indicates that the expression is part of a constant declaration. +// +func (check *checker) expr(x *operand, e ast.Expr, iota int) { + check.rawExpr(x, e, nil, iota) switch x.mode { case novalue: check.errorf(x.pos(), "%s used as value", x) @@ -1547,37 +1272,32 @@ func (check *checker) expr(x *operand, e ast.Expr, hint Type, iota int) { } } -func (check *checker) rawTyp(e ast.Expr, cycleOk, nilOk bool) Type { - var x operand - check.rawExpr(&x, e, nil, -1, cycleOk) +// exprWithHint typechecks expression e and initializes x with the expression value. +// If an error occurred, x.mode is set to invalid. +// If hint != nil, it is the type of a composite literal element. +// iota >= 0 indicates that the expression is part of a constant declaration. +// +func (check *checker) exprWithHint(x *operand, e ast.Expr, hint Type, iota int) { + assert(hint != nil) + check.rawExpr(x, e, hint, iota) switch x.mode { - case invalid: - // ignore - error reported before case novalue: - check.errorf(x.pos(), "%s used as type", &x) + check.errorf(x.pos(), "%s used as value", x) + x.mode = invalid case typexpr: - return x.typ - case constant: - if nilOk && x.isNil() { - return nil - } - fallthrough - default: - check.errorf(x.pos(), "%s is not a type", &x) + check.errorf(x.pos(), "%s is not an expression", x) + x.mode = invalid } - return Typ[Invalid] } -// typOrNil is like rawExpr but reports an error if e doesn't represents a type or the predeclared value nil. -// It returns e's type, nil, or Typ[Invalid] if an error occurred. +// exprOrType typechecks expression or type e and initializes x with the expression value or type. +// If an error occurred, x.mode is set to invalid. +// iota >= 0 indicates that the expression is part of a constant declaration. // -func (check *checker) typOrNil(e ast.Expr, cycleOk bool) Type { - return check.rawTyp(e, cycleOk, true) -} - -// typ is like rawExpr but reports an error if e doesn't represents a type. -// It returns e's type, or Typ[Invalid] if an error occurred. -// -func (check *checker) typ(e ast.Expr, cycleOk bool) Type { - return check.rawTyp(e, cycleOk, false) +func (check *checker) exprOrType(x *operand, e ast.Expr, iota int) { + check.rawExpr(x, e, nil, iota) + if x.mode == novalue { + check.errorf(x.pos(), "%s used as value or type", x) + x.mode = invalid + } } diff --git a/go/types/resolver.go b/go/types/resolver.go index fbe354fc1a..26ba012995 100644 --- a/go/types/resolver.go +++ b/go/types/resolver.go @@ -326,7 +326,7 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) { check.topScope = pkg.scope for _, obj := range objList { if obj.Type() == nil { - check.declareObject(obj, false) + check.declareObject(obj, nil, false) } } check.objMap = nil // done with global declarations @@ -335,7 +335,9 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) { // - done by the caller for now } -func (check *checker) declareObject(obj Object, cycleOk bool) { +// declareObject declares obj in the top-most scope. +// See declareType for the details on def and cycleOk. +func (check *checker) declareObject(obj Object, def *Named, cycleOk bool) { d := check.objMap[obj] // adjust file scope for current object @@ -348,7 +350,7 @@ func (check *checker) declareObject(obj Object, cycleOk bool) { case *Var: check.declareVar(obj, d.typ, d.init) case *TypeName: - check.declareType(obj, d.typ, cycleOk) + check.declareType(obj, d.typ, def, cycleOk) case *Func: check.declareFunc(obj) default: @@ -367,11 +369,10 @@ func (check *checker) declareConst(obj *Const, typ, init ast.Expr) { obj.visited = true iota, ok := exact.Int64Val(obj.val) // set in phase 1 assert(ok) - // obj.val = exact.MakeUnknown() //do we need this? should we set val to nil? // determine type, if any if typ != nil { - obj.typ = check.typ(typ, false) + obj.typ = check.typ(typ, int(iota), nil, false) } var x operand @@ -380,7 +381,7 @@ func (check *checker) declareConst(obj *Const, typ, init ast.Expr) { goto Error // error reported before } - check.expr(&x, init, nil, int(iota)) + check.expr(&x, init, int(iota)) if x.mode == invalid { goto Error } @@ -406,7 +407,7 @@ func (check *checker) declareVar(obj *Var, typ, init ast.Expr) { // determine type, if any if typ != nil { - obj.typ = check.typ(typ, false) + obj.typ = check.typ(typ, -1, nil, false) } if init == nil { @@ -423,7 +424,7 @@ func (check *checker) declareVar(obj *Var, typ, init ast.Expr) { } var x operand - check.expr(&x, init, nil, -1) + check.expr(&x, init, -1) if x.mode == invalid { goto Error } @@ -473,10 +474,46 @@ Error: return } -func (check *checker) declareType(obj *TypeName, typ ast.Expr, cycleOk bool) { +func (check *checker) declareType(obj *TypeName, typ ast.Expr, def *Named, cycleOk bool) { + assert(obj.Type() == nil) + named := &Named{obj: obj} - obj.typ = named // mark object so recursion terminates in case of cycles - named.underlying = check.typ(typ, cycleOk).Underlying() + obj.typ = named // make sure recursive type declarations terminate + + // If this type (named) defines the type of another (def) type declaration, + // set def's underlying type to this type so that we can resolve the true + // underlying of def later. + if def != nil { + def.underlying = named + } + + // Typecheck typ - it may be a named type that is not yet complete. + // For instance, consider: + // + // type ( + // A B + // B *C + // C A + // ) + // + // When we declare obj = C, typ is the identifier A which is incomplete. + u := check.typ(typ, -1, named, cycleOk) + + // Determine the unnamed underlying type. + // In the above example, the underlying type of A was (temporarily) set + // to B whose underlying type was set to *C. Such "forward chains" always + // end in an unnamed type (cycles are terminated with an invalid type). + for { + n, _ := u.(*Named) + if n == nil { + break + } + u = n.underlying + } + named.underlying = u + + // the underlying type has been determined + named.complete = true // typecheck associated method signatures if scope := check.methods[obj]; scope != nil { @@ -512,7 +549,7 @@ func (check *checker) declareType(obj *TypeName, typ ast.Expr, cycleOk bool) { oldScope := check.topScope check.topScope = fileScope - sig := check.typ(m.decl.Type, cycleOk).(*Signature) + sig := check.typ(m.decl.Type, -1, nil, cycleOk).(*Signature) params, _ := check.collectParams(sig.scope, m.decl.Recv, false) check.topScope = oldScope // reset topScope @@ -534,7 +571,7 @@ func (check *checker) declareFunc(obj *Func) { // TODO(gri) there is no reason to make this a special case: receivers are simply parameters if fdecl.Recv == nil { obj.typ = Typ[Invalid] // guard against cycles - sig := check.typ(fdecl.Type, false).(*Signature) + sig := check.typ(fdecl.Type, -1, nil, false).(*Signature) if obj.name == "init" && (sig.params.Len() > 0 || sig.results.Len() > 0) { check.errorf(fdecl.Pos(), "func init must have no arguments and no return values") // ok to continue @@ -643,7 +680,7 @@ func (check *checker) declStmt(decl ast.Decl) { case *ast.TypeSpec: obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil) check.declare(check.topScope, s.Name, obj) - check.declareType(obj, s.Type, false) + check.declareType(obj, s.Type, nil, false) default: check.invalidAST(s.Pos(), "const, type, or var declaration expected") diff --git a/go/types/stmt.go b/go/types/stmt.go index 95625a87ba..2ff5c995b1 100644 --- a/go/types/stmt.go +++ b/go/types/stmt.go @@ -48,7 +48,7 @@ func (check *checker) assign1to1(lhs, rhs ast.Expr, x *operand, decl bool, iota // for declarations with implicit type. if x == nil { x = new(operand) - check.expr(x, rhs, nil, iota) + check.expr(x, rhs, iota) // don't exit for declarations - we need the lhs first if x.mode == invalid && !decl { return @@ -70,7 +70,7 @@ func (check *checker) assign1to1(lhs, rhs ast.Expr, x *operand, decl bool, iota } var z operand - check.expr(&z, lhs, nil, -1) + check.expr(&z, lhs, -1) if z.mode == invalid || z.typ == Typ[Invalid] { return } @@ -195,7 +195,7 @@ func (check *checker) assignNtoM(lhs, rhs []ast.Expr, decl bool, iota int, isCon // Start with rhs so we have expression types // for declarations with implicit types. var x operand - check.expr(&x, rhs[0], nil, iota) + check.expr(&x, rhs[0], iota) if x.mode == invalid { goto Error } @@ -335,7 +335,7 @@ func (check *checker) stmt(s ast.Stmt) { // (Caution: This evaluates e.Fun twice, once here and once // below as part of s.X. This has consequences for // check.callIdent. Perhaps this can be avoided.) - check.expr(&x, e.Fun, nil, -1) + check.expr(&x, e.Fun, -1) if x.mode != invalid { if b, ok := x.typ.(*Builtin); ok && !b.isStatement { used = false @@ -351,15 +351,15 @@ func (check *checker) stmt(s ast.Stmt) { check.errorf(s.Pos(), "%s not used", s.X) // ok to continue } - check.rawExpr(&x, s.X, nil, -1, false) + check.rawExpr(&x, s.X, nil, -1) if x.mode == typexpr { check.errorf(x.pos(), "%s is not an expression", &x) } case *ast.SendStmt: var ch, x operand - check.expr(&ch, s.Chan, nil, -1) - check.expr(&x, s.Value, nil, -1) + check.expr(&ch, s.Chan, -1) + check.expr(&x, s.Value, -1) if ch.mode == invalid || x.mode == invalid { return } @@ -526,7 +526,7 @@ func (check *checker) stmt(s ast.Stmt) { check.openScope(s) check.optionalStmt(s.Init) var x operand - check.expr(&x, s.Cond, nil, -1) + check.expr(&x, s.Cond, -1) if x.mode != invalid && !isBoolean(x.typ) { check.errorf(s.Cond.Pos(), "non-boolean condition in if statement") } @@ -545,7 +545,7 @@ func (check *checker) stmt(s ast.Stmt) { check.callIdent(ident, Universe.Lookup(nil, "true")) tag = ident } - check.expr(&x, tag, nil, -1) + check.expr(&x, tag, -1) check.multipleDefaults(s.Body.List) // TODO(gri) check also correct use of fallthrough @@ -559,7 +559,7 @@ func (check *checker) stmt(s ast.Stmt) { for _, expr := range clause.List { x := x // copy of x (don't modify original) var y operand - check.expr(&y, expr, nil, -1) + check.expr(&y, expr, -1) if y.mode == invalid { continue // error reported before } @@ -645,7 +645,7 @@ func (check *checker) stmt(s ast.Stmt) { return } var x operand - check.expr(&x, expr.X, nil, -1) + check.expr(&x, expr.X, -1) if x.mode == invalid { return } @@ -670,7 +670,7 @@ func (check *checker) stmt(s ast.Stmt) { // Check each type in this type switch case. var typ Type for _, expr := range clause.List { - typ = check.typOrNil(expr, false) + typ = check.typOrNil(expr) if typ != nil && typ != Typ[Invalid] { if method, wrongType := MissingMethod(typ, T); method != nil { var msg string @@ -717,7 +717,7 @@ func (check *checker) stmt(s ast.Stmt) { check.optionalStmt(s.Init) if s.Cond != nil { var x operand - check.expr(&x, s.Cond, nil, -1) + check.expr(&x, s.Cond, -1) if x.mode != invalid && !isBoolean(x.typ) { check.errorf(s.Cond.Pos(), "non-boolean condition in for statement") } @@ -731,7 +731,7 @@ func (check *checker) stmt(s ast.Stmt) { // check expression to iterate over decl := s.Tok == token.DEFINE var x operand - check.expr(&x, s.X, nil, -1) + check.expr(&x, s.X, -1) if x.mode == invalid { // if we don't have a declaration, we can still check the loop's body if !decl { diff --git a/go/types/testdata/const0.src b/go/types/testdata/const0.src index 1eb46e234d..66224baf2a 100644 --- a/go/types/testdata/const0.src +++ b/go/types/testdata/const0.src @@ -224,10 +224,15 @@ const ( const ( _b0 = iota _b1 = assert(iota + iota2 == 5) + _b2 = len([iota]int{}) // iota may appear in a type! + _b3 = assert(_b2 == 2) + _b4 = len(A /* ERROR "not a valid composite literal" */ {}) ) +type A [iota /* ERROR "cannot use iota" */ ]int + // special cases const ( _n0 = nil /* ERROR "invalid constant type" */ _n1 = [ /* ERROR "not constant" */ ]int{} -) \ No newline at end of file +) diff --git a/go/types/testdata/cycles.src b/go/types/testdata/cycles.src index 3e10873d01..a043bc37cf 100644 --- a/go/types/testdata/cycles.src +++ b/go/types/testdata/cycles.src @@ -59,9 +59,8 @@ type ( I4 interface{ f(I4) } // testcase for issue 5090 - // TODO(gri) fix this I5 interface{ f(I6) } - I6 interface{ I5 /* ERROR "unimplemented" */ } + I6 interface{ I5 } // maps M0 map[M0]M0 diff --git a/go/types/testdata/decls0.src b/go/types/testdata/decls0.src index d2a1b6be41..c39fa51125 100644 --- a/go/types/testdata/decls0.src +++ b/go/types/testdata/decls0.src @@ -188,9 +188,9 @@ type ( // cycles in function/method declarations // (test cases for issue 5217 and variants) func f1(x f1 /* ERROR "not a type" */ ) {} -func f2(x *f2 /* ERROR "cannot indirect" */ ) {} +func f2(x *f2 /* ERROR "not a type" */ ) {} func f3() (x f3 /* ERROR "not a type" */ ) { return } -func f4() (x *f4 /* ERROR "cannot indirect" */ ) { return } +func f4() (x *f4 /* ERROR "not a type" */ ) { return } func (S0) m1(x S0 /* ERROR "field or method" */ .m1) {} func (S0) m2(x *S0 /* ERROR "field or method" */ .m2) {} diff --git a/go/types/types.go b/go/types/types.go index fa8789557e..d0c375296a 100644 --- a/go/types/types.go +++ b/go/types/types.go @@ -326,7 +326,8 @@ func (c *Chan) Elem() Type { return c.elt } // A Named represents a named type. type Named struct { obj *TypeName // corresponding declared object - underlying Type // nil if not fully declared yet; never a *Named + underlying Type // possibly a *Named if !complete; never a *Named if complete + complete bool // if set, the underlying type has been determined methods []*Func // methods declared for this type (not the method set of this type) } @@ -337,7 +338,7 @@ func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named { if _, ok := underlying.(*Named); ok { panic("types.NewNamed: underlying type must not be *Named") } - typ := &Named{obj, underlying, methods} + typ := &Named{obj, underlying, true, methods} if obj.typ == nil { obj.typ = typ } diff --git a/go/types/typexpr.go b/go/types/typexpr.go new file mode 100644 index 0000000000..891afb4a5f --- /dev/null +++ b/go/types/typexpr.go @@ -0,0 +1,454 @@ +// Copyright 2013 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. + +// This file implements typechecking of identifiers and type expressions. + +package types + +import ( + "go/ast" + "go/token" + "strconv" + + "code.google.com/p/go.tools/go/exact" +) + +// ident typechecks identifier e and initializes x with the value or type of e. +// If an error occurred, x.mode is set to invalid. +// iota >= 0 indicates that the expression is part of a constant declaration. +// For the meaning of def and cycleOk, see check.typ, below. +// +func (check *checker) ident(x *operand, e *ast.Ident, iota int, def *Named, cycleOk bool) { + x.mode = invalid + x.expr = e + + obj := check.topScope.LookupParent(e.Name) + check.callIdent(e, obj) + if obj == nil { + if e.Name == "_" { + check.errorf(e.Pos(), "cannot use _ as value or type") + } else { + check.errorf(e.Pos(), "undeclared name: %s", e.Name) + } + return + } + + typ := obj.Type() + if typ == nil { + // object not yet declared + if check.objMap == nil { + check.dump("%s: %s should have been declared (we are inside a function)", e.Pos(), e) + unreachable() + } + check.declareObject(obj, def, cycleOk) + typ = obj.Type() + } + assert(typ != nil) + + switch obj := obj.(type) { + case *Package: + check.errorf(e.Pos(), "use of package %s not in selector", obj.name) + return + + case *Const: + if typ == Typ[Invalid] { + return + } + if obj == universeIota { + if iota < 0 { + check.invalidAST(e.Pos(), "cannot use iota outside constant declaration") + return + } + x.val = exact.MakeInt64(int64(iota)) + } else { + x.val = obj.val // may be nil if we don't know the constant value + } + x.mode = constant + + case *TypeName: + x.mode = typexpr + named, _ := typ.(*Named) + if !cycleOk && named != nil && !named.complete { + check.errorf(obj.pos, "illegal cycle in declaration of %s", obj.name) + // maintain x.mode == typexpr despite error + typ = Typ[Invalid] + } + if def != nil { + def.underlying = typ + } + + case *Var: + x.mode = variable + + case *Func: + x.mode = value + + default: + unreachable() + } + + x.typ = typ +} + +// typ typechecks the type expression e and initializes x with the type of e. +// If an error occurred, x.mode is set to invalid. +// iota >= 0 indicates that the expression is part of a constant declaration. +// If def != nil, e is the type specification for the named type def, declared +// in a type declaration, and def.underlying will be set to the type of e before +// any components of e are typechecked. +// If cycleOk is set, e (or elements of e) may refer to a named type that is not +// yet completely set up. +// +func (check *checker) typ(e ast.Expr, iota int, def *Named, cycleOk bool) (res Type) { + if trace { + check.trace(e.Pos(), "%s", e) + defer check.untrace("=> %s", res) + } + + // notify clients of type + if f := check.ctxt.Expr; f != nil { + defer func() { + assert(e != nil && res != nil && !isUntyped(res)) + f(e, res, nil) + }() + } + + switch e := e.(type) { + case *ast.Ident: + var x operand + check.ident(&x, e, iota, def, cycleOk) + + switch x.mode { + case typexpr: + return x.typ + case invalid: + // ignore - error reported before + case novalue: + check.errorf(x.pos(), "%s used as type", &x) + default: + check.errorf(x.pos(), "%s is not a type", &x) + } + + case *ast.SelectorExpr: + var x operand + check.selector(&x, e, iota) + + switch x.mode { + case typexpr: + return x.typ + case invalid: + // ignore - error reported before + case novalue: + check.errorf(x.pos(), "%s used as type", &x) + default: + check.errorf(x.pos(), "%s is not a type", &x) + } + + case *ast.ParenExpr: + return check.typ(e.X, iota, def, cycleOk) + + case *ast.ArrayType: + if e.Len != nil { + var x operand + check.expr(&x, e.Len, iota) + if x.mode != constant { + if x.mode != invalid { + check.errorf(x.pos(), "array length %s must be constant", &x) + } + break + } + if !x.isInteger() { + check.errorf(x.pos(), "array length %s must be integer", &x) + break + } + n, ok := exact.Int64Val(x.val) + if !ok || n < 0 { + check.errorf(x.pos(), "invalid array length %s", &x) + break + } + + typ := new(Array) + if def != nil { + def.underlying = typ + } + + typ.len = n + typ.elt = check.typ(e.Elt, iota, nil, cycleOk) + return typ + + } else { + typ := new(Slice) + if def != nil { + def.underlying = typ + } + + typ.elt = check.typ(e.Elt, iota, nil, true) + return typ + } + + case *ast.StructType: + typ := new(Struct) + if def != nil { + def.underlying = typ + } + + typ.fields, typ.tags = check.collectFields(e.Fields, cycleOk) + return typ + + case *ast.StarExpr: + typ := new(Pointer) + if def != nil { + def.underlying = typ + } + + typ.base = check.typ(e.X, iota, nil, true) + return typ + + case *ast.FuncType: + typ := new(Signature) + if def != nil { + def.underlying = typ + } + + scope := NewScope(check.topScope) + if retainASTLinks { + scope.node = e + } + typ.scope = scope + params, isVariadic := check.collectParams(scope, e.Params, true) + results, _ := check.collectParams(scope, e.Results, false) + typ.params = NewTuple(params...) + typ.results = NewTuple(results...) + typ.isVariadic = isVariadic + return typ + + case *ast.InterfaceType: + typ := new(Interface) + if def != nil { + def.underlying = typ + } + + typ.methods = check.collectMethods(e.Methods, cycleOk) + return typ + + case *ast.MapType: + typ := new(Map) + if def != nil { + def.underlying = typ + } + + typ.key = check.typ(e.Key, iota, nil, true) + typ.elt = check.typ(e.Value, iota, nil, true) + return typ + + case *ast.ChanType: + typ := new(Chan) + if def != nil { + def.underlying = typ + } + + typ.dir = e.Dir + typ.elt = check.typ(e.Value, iota, nil, true) + return typ + + default: + check.errorf(e.Pos(), "%s is not a type", e) + } + + return Typ[Invalid] +} + +// typeOrNil typechecks the type expression (or nil value) e +// and returns the typ of e, or nil. +// If e is neither a type nor nil, typOrNil returns Typ[Invalid]. +// +func (check *checker) typOrNil(e ast.Expr) Type { + var x operand + check.rawExpr(&x, e, nil, -1) + switch x.mode { + case invalid: + // ignore - error reported before + case novalue: + check.errorf(x.pos(), "%s used as type", &x) + case typexpr: + return x.typ + case constant: + if x.isNil() { + return nil + } + fallthrough + default: + check.errorf(x.pos(), "%s is not a type", &x) + } + return Typ[Invalid] +} + +func (check *checker) collectParams(scope *Scope, list *ast.FieldList, variadicOk bool) (params []*Var, isVariadic bool) { + if list == nil { + return + } + var last *Var + for i, field := range list.List { + ftype := field.Type + if t, _ := ftype.(*ast.Ellipsis); t != nil { + ftype = t.Elt + if variadicOk && i == len(list.List)-1 { + isVariadic = true + } else { + check.invalidAST(field.Pos(), "... not permitted") + // ok to continue + } + } + // the parser ensures that f.Tag is nil and we don't + // care if a constructed AST contains a non-nil tag + typ := check.typ(ftype, -1, nil, true) + if len(field.Names) > 0 { + // named parameter + for _, name := range field.Names { + par := NewVar(name.Pos(), check.pkg, name.Name, typ) + check.declare(scope, name, par) + + last = par + copy := *par + params = append(params, ©) + } + } else { + // anonymous parameter + par := NewVar(ftype.Pos(), check.pkg, "", typ) + check.callImplicitObj(field, par) + + last = nil // not accessible inside function + params = append(params, par) + } + } + // For a variadic function, change the last parameter's object type + // from T to []T (this is the type used inside the function), but + // keep the params list unchanged (this is the externally visible type). + if isVariadic && last != nil { + last.typ = &Slice{elt: last.typ} + } + return +} + +func (check *checker) collectMethods(list *ast.FieldList, cycleOk bool) (methods []*Func) { + if list == nil { + return nil + } + scope := NewScope(nil) + for _, f := range list.List { + typ := check.typ(f.Type, -1, nil, cycleOk) + // the parser ensures that f.Tag is nil and we don't + // care if a constructed AST contains a non-nil tag + if len(f.Names) > 0 { + // methods (the parser ensures that there's only one + // and we don't care if a constructed AST has more) + sig, ok := typ.(*Signature) + if !ok { + check.invalidAST(f.Type.Pos(), "%s is not a method signature", typ) + continue + } + for _, name := range f.Names { + m := NewFunc(name.Pos(), check.pkg, name.Name, sig) + check.declare(scope, name, m) + methods = append(methods, m) + } + } else { + // embedded interface + switch t := typ.Underlying().(type) { + case nil: + // The underlying type is in the process of being defined + // but we need it in order to complete this type. For now + // complain with an "unimplemented" error. This requires + // a bit more work. + // TODO(gri) finish this. + check.errorf(f.Type.Pos(), "reference to incomplete type %s - unimplemented", f.Type) + case *Interface: + for _, m := range t.methods { + check.declare(scope, nil, m) + methods = append(methods, m) + } + default: + if t != Typ[Invalid] { + check.errorf(f.Type.Pos(), "%s is not an interface type", typ) + } + } + } + } + return +} + +func (check *checker) tag(t *ast.BasicLit) string { + if t != nil { + if t.Kind == token.STRING { + if val, err := strconv.Unquote(t.Value); err == nil { + return val + } + } + check.invalidAST(t.Pos(), "incorrect tag syntax: %q", t.Value) + } + return "" +} + +func (check *checker) collectFields(list *ast.FieldList, cycleOk bool) (fields []*Field, tags []string) { + if list == nil { + return + } + + scope := NewScope(nil) + + var typ Type // current field typ + var tag string // current field tag + add := func(field *ast.Field, ident *ast.Ident, name string, anonymous bool, pos token.Pos) { + if tag != "" && tags == nil { + tags = make([]string, len(fields)) + } + if tags != nil { + tags = append(tags, tag) + } + + fld := NewField(pos, check.pkg, name, typ, anonymous) + check.declare(scope, ident, fld) + fields = append(fields, fld) + } + + for _, f := range list.List { + typ = check.typ(f.Type, -1, nil, cycleOk) + tag = check.tag(f.Tag) + if len(f.Names) > 0 { + // named fields + for _, name := range f.Names { + add(f, name, name.Name, false, name.Pos()) + } + } else { + // anonymous field + pos := f.Type.Pos() + t, isPtr := deref(typ) + switch t := t.(type) { + case *Basic: + add(f, nil, t.name, true, pos) + case *Named: + // spec: "An embedded type must be specified as a type name + // T or as a pointer to a non-interface type name *T, and T + // itself may not be a pointer type." + switch t.Underlying().(type) { + case *Pointer: + check.errorf(pos, "anonymous field type cannot be a pointer") + continue // ignore this field + case *Interface: + if isPtr { + check.errorf(pos, "anonymous field type cannot be a pointer to an interface") + continue // ignore this field + } + } + add(f, nil, t.obj.name, true, pos) + default: + if typ != Typ[Invalid] { + check.invalidAST(pos, "anonymous field type %s must be named", typ) + } + } + } + } + + return +} diff --git a/go/types/universe.go b/go/types/universe.go index ab274dbf56..45b10a424f 100644 --- a/go/types/universe.go +++ b/go/types/universe.go @@ -103,7 +103,7 @@ func init() { // Error has a nil package in its qualified name since it is in no package sig := &Signature{results: NewTuple(NewVar(token.NoPos, nil, "", Typ[String]))} methods := []*Func{NewFunc(token.NoPos, nil, "Error", sig)} - def(NewTypeName(token.NoPos, nil, "error", &Named{underlying: NewInterface(methods)})) + def(NewTypeName(token.NoPos, nil, "error", &Named{underlying: NewInterface(methods), complete: true})) } for _, c := range predeclaredConstants {