]> Cypherpunks repositories - gostls13.git/commitdiff
go/types: add Var.Kind() VarKind method
authorAlan Donovan <adonovan@google.com>
Tue, 28 Jan 2025 18:44:41 +0000 (13:44 -0500)
committerAlan Donovan <adonovan@google.com>
Wed, 5 Mar 2025 18:21:15 +0000 (10:21 -0800)
This CL adds an enum type, VarKind, that discriminates among
the various kinds of Var, and adds setter/getter methods
for Var's kind field.

Beware: NewVar has a weaker postcondition: the Var objects it
returns are not completely initialized and require a call to
Var.SetKind. This should only affect importers.

No changes are needed to the export data, since the kind can
always be deduced from the context when decoding.

See CL 645656 for the corresponding x/tools changes.

+ test, relnote, API

Updates golang/go#70250

Change-Id: Icde86ad22a880cde6f50bc12bf38004a5c6a1025
Reviewed-on: https://go-review.googlesource.com/c/go/+/645115
Reviewed-by: Robert Griesemer <gri@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Findley <rfindley@google.com>
33 files changed:
api/go1.25.txt [new file with mode: 0644]
doc/initial/6-stdlib/99-minor/0-heading.md
src/cmd/compile/internal/types2/api_test.go
src/cmd/compile/internal/types2/assignments.go
src/cmd/compile/internal/types2/builtins.go
src/cmd/compile/internal/types2/call.go
src/cmd/compile/internal/types2/check.go
src/cmd/compile/internal/types2/context_test.go
src/cmd/compile/internal/types2/decl.go
src/cmd/compile/internal/types2/interface.go
src/cmd/compile/internal/types2/issues_test.go
src/cmd/compile/internal/types2/object.go
src/cmd/compile/internal/types2/recording.go
src/cmd/compile/internal/types2/resolver.go
src/cmd/compile/internal/types2/signature.go
src/cmd/compile/internal/types2/stmt.go
src/cmd/compile/internal/types2/universe.go
src/go/internal/gccgoimporter/parser.go
src/go/internal/gcimporter/ureader.go
src/go/types/api_test.go
src/go/types/assignments.go
src/go/types/builtins.go
src/go/types/call.go
src/go/types/context_test.go
src/go/types/decl.go
src/go/types/interface.go
src/go/types/issues_test.go
src/go/types/object.go
src/go/types/recording.go
src/go/types/resolver.go
src/go/types/signature.go
src/go/types/stmt.go
src/go/types/universe.go

diff --git a/api/go1.25.txt b/api/go1.25.txt
new file mode 100644 (file)
index 0000000..8cd7b1d
--- /dev/null
@@ -0,0 +1,16 @@
+pkg go/types, const FieldVar = 6 #70250
+pkg go/types, const FieldVar VarKind #70250
+pkg go/types, const LocalVar = 2 #70250
+pkg go/types, const LocalVar VarKind #70250
+pkg go/types, const PackageVar = 1 #70250
+pkg go/types, const PackageVar VarKind #70250
+pkg go/types, const ParamVar = 4 #70250
+pkg go/types, const ParamVar VarKind #70250
+pkg go/types, const RecvVar = 3 #70250
+pkg go/types, const RecvVar VarKind #70250
+pkg go/types, const ResultVar = 5 #70250
+pkg go/types, const ResultVar VarKind #70250
+pkg go/types, method (*Var) Kind() VarKind #70250
+pkg go/types, method (*Var) SetKind(VarKind) #70250
+pkg go/types, method (VarKind) String() string #70250
+pkg go/types, type VarKind uint8 #70250
index a98105e8ccba7f64a0fd77d1b85cf46545ba2d2b..e80ebc64c380fd517487018a8fd5fcff792b5f41 100644 (file)
@@ -1,3 +1,10 @@
 ### Minor changes to the library {#minor_library_changes}
 
+#### go/types
 
+The `Var.Kind` method returns an enumeration of type `VarKind` that
+classifies the variable (package-level, local, receiver, parameter,
+result, or struct field). See issue #70250.
+
+Callers of `NewVar` or `NewParam` are encouraged to call `Var.SetKind`
+to ensure that this attribute is set correctly in all cases.
index c43f33bcddcc0ce5de2b9ac4e7c21f7fbcebc094..44fb6afe9858ab5e2bcfe2f0118bce4b6b764309 100644 (file)
@@ -11,6 +11,7 @@ import (
        "internal/goversion"
        "internal/testenv"
        "slices"
+       "sort"
        "strings"
        "sync"
        "testing"
@@ -3061,3 +3062,48 @@ func TestVersionWithoutPos(t *testing.T) {
                t.Errorf("check error was %q, want substring %q", got, want)
        }
 }
+
+func TestVarKind(t *testing.T) {
+       f := mustParse(`package p
+
+var global int
+
+type T struct { field int }
+
+func (recv T) f(param int) (result int) {
+       var local int
+       local2 := 0
+       switch local3 := any(local).(type) {
+       default:
+               _ = local3
+       }
+       return local2
+}
+`)
+
+       pkg := NewPackage("p", "p")
+       info := &Info{Defs: make(map[*syntax.Name]Object)}
+       check := NewChecker(&Config{}, pkg, info)
+       if err := check.Files([]*syntax.File{f}); err != nil {
+               t.Fatal(err)
+       }
+       var got []string
+       for _, obj := range info.Defs {
+               if v, ok := obj.(*Var); ok {
+                       got = append(got, fmt.Sprintf("%s: %v", v.Name(), v.Kind()))
+               }
+       }
+       sort.Strings(got)
+       want := []string{
+               "field: FieldVar",
+               "global: PackageVar",
+               "local2: LocalVar",
+               "local: LocalVar",
+               "param: ParamVar",
+               "recv: RecvVar",
+               "result: ResultVar",
+       }
+       if !slices.Equal(got, want) {
+               t.Errorf("got:\n%s\nwant:\n%s", got, want)
+       }
+}
index ebe9ef11cb30b83a9b0b5facad6336722d21d865..33810643cb3f89eaede3a3518bdeede475712740 100644 (file)
@@ -566,7 +566,7 @@ func (check *Checker) shortVarDecl(pos poser, lhs, rhs []syntax.Expr) {
                }
 
                // declare new variable
-               obj := NewVar(ident.Pos(), check.pkg, name, nil)
+               obj := newVar(LocalVar, ident.Pos(), check.pkg, name, nil)
                lhsVars[i] = obj
                if name != "_" {
                        newVars = append(newVars, obj)
@@ -577,7 +577,7 @@ func (check *Checker) shortVarDecl(pos poser, lhs, rhs []syntax.Expr) {
        // create dummy variables where the lhs is invalid
        for i, obj := range lhsVars {
                if obj == nil {
-                       lhsVars[i] = NewVar(lhs[i].Pos(), check.pkg, "_", nil)
+                       lhsVars[i] = newVar(LocalVar, lhs[i].Pos(), check.pkg, "_", nil)
                }
        }
 
index 7160efec896f0045d7a29e6f4f971dba786aa09a..1e2a9a28f88dca0da75bd3e17b0636567a5b96f5 100644 (file)
@@ -1032,13 +1032,13 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x *operand, id builtinId)
 func makeSig(res Type, args ...Type) *Signature {
        list := make([]*Var, len(args))
        for i, param := range args {
-               list[i] = NewVar(nopos, nil, "", Default(param))
+               list[i] = NewParam(nopos, nil, "", Default(param))
        }
        params := NewTuple(list...)
        var result *Tuple
        if res != nil {
                assert(!isUntyped(res))
-               result = NewTuple(NewVar(nopos, nil, "", res))
+               result = NewTuple(newVar(ResultVar, nopos, nil, "", res))
        }
        return &Signature{params: params, results: result}
 }
index 17291b20637d2c78db192c7596d3a2bf6ec76fc4..9294afcea92b7ebeb8c8643ae131e7ce27fd2bf2 100644 (file)
@@ -94,7 +94,7 @@ func (check *Checker) funcInst(T *target, pos syntax.Pos, x *operand, inst *synt
                                }
                        }
                        gsig := NewSignatureType(nil, nil, nil, sig.params, sig.results, sig.variadic)
-                       params = []*Var{NewVar(x.Pos(), check.pkg, "", gsig)}
+                       params = []*Var{NewParam(x.Pos(), check.pkg, "", gsig)}
                        // The type of the argument operand is tsig, which is the type of the LHS in an assignment
                        // or the result type in a return statement. Create a pseudo-expression for that operand
                        // that makes sense when reported in error messages from infer, below.
@@ -875,7 +875,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *TypeName
                                name = "_"
                        }
                }
-               params = append([]*Var{NewVar(sig.recv.pos, sig.recv.pkg, name, x.typ)}, params...)
+               params = append([]*Var{NewParam(sig.recv.pos, sig.recv.pkg, name, x.typ)}, params...)
                x.mode = value
                x.typ = &Signature{
                        tparams:  sig.tparams,
index 52ff2ea032fa92a474d26783025834797b5e5492..a158f5558584d34f37541a03cef19fb5c38871c5 100644 (file)
@@ -568,8 +568,8 @@ func (check *Checker) recordCommaOkTypesInSyntax(x syntax.Expr, t0, t1 Type) {
                        assert(tv.Type != nil) // should have been recorded already
                        pos := x.Pos()
                        tv.Type = NewTuple(
-                               NewVar(pos, check.pkg, "", t0),
-                               NewVar(pos, check.pkg, "", t1),
+                               NewParam(pos, check.pkg, "", t0),
+                               NewParam(pos, check.pkg, "", t1),
                        )
                        x.SetTypeInfo(tv)
                        p, _ := x.(*syntax.ParenExpr)
index aa649b14481f76100988eef817ff1720a9ebd540..2c5c0d8ef3424ad6a3311f2d3fca2232b410db7b 100644 (file)
@@ -38,7 +38,7 @@ func TestContextHashCollisions(t *testing.T) {
        {
                // type unaryP = func[P any](_ P)
                tparam := NewTypeParam(NewTypeName(nopos, nil, "P", nil), &emptyInterface)
-               params := NewTuple(NewVar(nopos, nil, "_", tparam))
+               params := NewTuple(NewParam(nopos, nil, "_", tparam))
                unaryP = NewSignatureType(nil, nil, []*TypeParam{tparam}, params, nil, false)
        }
 
index 517a3d3def8f79bec1e27f73dadfe86eeff14148..823d940d9bca0d41ded1e557e3d6d05d1dca06f4 100644 (file)
@@ -844,7 +844,7 @@ func (check *Checker) declStmt(list []syntax.Decl) {
 
                        lhs0 := make([]*Var, len(s.NameList))
                        for i, name := range s.NameList {
-                               lhs0[i] = NewVar(name.Pos(), pkg, name.Value, nil)
+                               lhs0[i] = newVar(LocalVar, name.Pos(), pkg, name.Value, nil)
                        }
 
                        // initialize all variables
index 67f5b98a835cd9b82286f907301e3b94448f156e..b32e5c21fe250c20d02fb58c468adb0df5b39475 100644 (file)
@@ -42,7 +42,7 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface {
        typ := (*Checker)(nil).newInterface()
        for _, m := range methods {
                if sig := m.typ.(*Signature); sig.recv == nil {
-                       sig.recv = NewVar(m.pos, m.pkg, "", typ)
+                       sig.recv = newVar(RecvVar, m.pos, m.pkg, "", typ)
                }
        }
 
@@ -158,7 +158,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType
                                recvTyp = named
                        }
                }
-               sig.recv = NewVar(f.Name.Pos(), check.pkg, "", recvTyp)
+               sig.recv = newVar(RecvVar, f.Name.Pos(), check.pkg, "", recvTyp)
 
                m := NewFunc(f.Name.Pos(), check.pkg, name, sig)
                check.recordDef(f.Name, m)
index 60b28c4bf859725ac0d6dda823c0bc4a1e7d685c..51014d8d8248d3ed95d7eebcec2d4d9ba88ff80e 100644 (file)
@@ -628,7 +628,7 @@ func TestIssue50646(t *testing.T) {
 func TestIssue55030(t *testing.T) {
        // makeSig makes the signature func(typ...)
        makeSig := func(typ Type) {
-               par := NewVar(nopos, nil, "", typ)
+               par := NewParam(nopos, nil, "", typ)
                params := NewTuple(par)
                NewSignatureType(nil, nil, nil, params, nil, true)
        }
index f968f652aac3802e3f11f0ca8e661765c678f8e9..2eef5b5dae11307cda98e8da96104796f722da4b 100644 (file)
@@ -331,28 +331,81 @@ func (obj *TypeName) IsAlias() bool {
 // A Variable represents a declared variable (including function parameters and results, and struct fields).
 type Var struct {
        object
+       kind     VarKind
        embedded bool // if set, the variable is an embedded struct field, and name is the type name
-       isField  bool // var is struct field
        used     bool // set if the variable was used
        origin   *Var // if non-nil, the Var from which this one was instantiated
 }
 
+// A VarKind discriminates the various kinds of variables.
+type VarKind uint8
+
+const (
+       _          VarKind = iota // (not meaningful)
+       PackageVar                // a package-level variable
+       LocalVar                  // a local variable
+       RecvVar                   // a method receiver variable
+       ParamVar                  // a function parameter variable
+       ResultVar                 // a function result variable
+       FieldVar                  // a struct field
+)
+
+var varKindNames = [...]string{
+       0:          "VarKind(0)",
+       PackageVar: "PackageVar",
+       LocalVar:   "LocalVar",
+       RecvVar:    "RecvVar",
+       ParamVar:   "ParamVar",
+       ResultVar:  "ResultVar",
+       FieldVar:   "FieldVar",
+}
+
+func (kind VarKind) String() string {
+       if 0 <= kind && int(kind) < len(varKindNames) {
+               return varKindNames[kind]
+       }
+       return fmt.Sprintf("VarKind(%d)", kind)
+}
+
+// Kind reports what kind of variable v is.
+func (v *Var) Kind() VarKind { return v.kind }
+
+// SetKind sets the kind of the variable.
+// It should be used only immediately after [NewVar] or [NewParam].
+func (v *Var) SetKind(kind VarKind) { v.kind = kind }
+
 // NewVar returns a new variable.
 // The arguments set the attributes found with all Objects.
+//
+// The caller must subsequently call [Var.SetKind]
+// if the desired Var is not of kind [PackageVar].
 func NewVar(pos syntax.Pos, pkg *Package, name string, typ Type) *Var {
-       return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}}
+       return newVar(PackageVar, pos, pkg, name, typ)
 }
 
 // NewParam returns a new variable representing a function parameter.
+//
+// The caller must subsequently call [Var.SetKind] if the desired Var
+// is not of kind [ParamVar]: for example, [RecvVar] or [ResultVar].
 func NewParam(pos syntax.Pos, pkg *Package, name string, typ Type) *Var {
-       return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, used: true} // parameters are always 'used'
+       return newVar(ParamVar, pos, pkg, name, typ)
 }
 
 // NewField returns a new variable representing a struct field.
 // For embedded fields, the name is the unqualified type name
 // under which the field is accessible.
 func NewField(pos syntax.Pos, pkg *Package, name string, typ Type, embedded bool) *Var {
-       return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, embedded: embedded, isField: true}
+       v := newVar(FieldVar, pos, pkg, name, typ)
+       v.embedded = embedded
+       return v
+}
+
+// newVar returns a new variable.
+// The arguments set the attributes found with all Objects.
+func newVar(kind VarKind, pos syntax.Pos, pkg *Package, name string, typ Type) *Var {
+       // Function parameters are always 'used'.
+       used := kind == RecvVar || kind == ParamVar || kind == ResultVar
+       return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, kind: kind, used: used}
 }
 
 // Anonymous reports whether the variable is an embedded field.
@@ -363,7 +416,7 @@ func (obj *Var) Anonymous() bool { return obj.embedded }
 func (obj *Var) Embedded() bool { return obj.embedded }
 
 // IsField reports whether the variable is a struct field.
-func (obj *Var) IsField() bool { return obj.isField }
+func (obj *Var) IsField() bool { return obj.kind == FieldVar }
 
 // Origin returns the canonical Var for its receiver, i.e. the Var object
 // recorded in Info.Defs.
@@ -526,7 +579,7 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
                }
 
        case *Var:
-               if obj.isField {
+               if obj.IsField() {
                        buf.WriteString("field")
                } else {
                        buf.WriteString("var")
index 7badd022b19b061d38aec32855c0afeb85d20157..2c83dd2db9df13634a86304c67f3c5b3c7fae237 100644 (file)
@@ -105,8 +105,8 @@ func (check *Checker) recordCommaOkTypes(x syntax.Expr, a []*operand) {
                        assert(tv.Type != nil) // should have been recorded already
                        pos := x.Pos()
                        tv.Type = NewTuple(
-                               NewVar(pos, check.pkg, "", t0),
-                               NewVar(pos, check.pkg, "", t1),
+                               newVar(LocalVar, pos, check.pkg, "", t0),
+                               newVar(LocalVar, pos, check.pkg, "", t1),
                        )
                        m[x] = tv
                        // if x is a parenthesized expression (p.X), update p.X
index 694c035ab5b36b4bd3c9e33673d2970ae8f46042..6a8b270849364124e99171e6b05de254b77a57f4 100644 (file)
@@ -388,7 +388,7 @@ func (check *Checker) collectObjects() {
                                // declare all variables
                                values := syntax.UnpackListExpr(s.Values)
                                for i, name := range s.NameList {
-                                       obj := NewVar(name.Pos(), pkg, name.Value, nil)
+                                       obj := newVar(PackageVar, name.Pos(), pkg, name.Value, nil)
                                        lhs[i] = obj
 
                                        d := d1
index 892fa0e460b21dbc726c35f932589e81949e224a..505997110b8ffe28af0808502b104b7649c90b22 100644 (file)
@@ -117,8 +117,8 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
        }
 
        // collect ordinary and result parameters
-       pnames, params, variadic := check.collectParams(ftyp.ParamList, true)
-       rnames, results, _ := check.collectParams(ftyp.ResultList, false)
+       pnames, params, variadic := check.collectParams(ParamVar, ftyp.ParamList)
+       rnames, results, _ := check.collectParams(ResultVar, ftyp.ResultList)
 
        // declare named receiver, ordinary, and result parameters
        scopePos := syntax.EndPos(ftyp) // all parameter's scopes start after the signature
@@ -258,13 +258,13 @@ func (check *Checker) collectRecv(rparam *syntax.Field, scopePos syntax.Pos) (*V
        var recv *Var
        if rname := rparam.Name; rname != nil && rname.Value != "" {
                // named receiver
-               recv = NewParam(rname.Pos(), check.pkg, rname.Value, recvType)
+               recv = newVar(RecvVar, rname.Pos(), check.pkg, rname.Value, recvType)
                // In this case, the receiver is declared by the caller
                // because it must be declared after any type parameters
                // (otherwise it might shadow one of them).
        } else {
                // anonymous receiver
-               recv = NewParam(rparam.Pos(), check.pkg, "", recvType)
+               recv = newVar(RecvVar, rparam.Pos(), check.pkg, "", recvType)
                check.recordImplicit(rparam, recv)
        }
 
@@ -322,10 +322,11 @@ func (check *Checker) recordParenthesizedRecvTypes(expr syntax.Expr, typ Type) {
        }
 }
 
-// collectParams collects (but does not declare) all parameters of list and returns
-// the list of parameter names, corresponding parameter variables, and whether the
-// parameter list is variadic. Anonymous parameters are recorded with nil names.
-func (check *Checker) collectParams(list []*syntax.Field, variadicOk bool) (names []*syntax.Name, params []*Var, variadic bool) {
+// collectParams collects (but does not declare) all parameter/result
+// variables of list and returns the list of names and corresponding
+// variables, and whether the (parameter) list is variadic.
+// Anonymous parameters are recorded with nil names.
+func (check *Checker) collectParams(kind VarKind, list []*syntax.Field) (names []*syntax.Name, params []*Var, variadic bool) {
        if list == nil {
                return
        }
@@ -341,7 +342,7 @@ func (check *Checker) collectParams(list []*syntax.Field, variadicOk bool) (name
                        prev = ftype
                        if t, _ := ftype.(*syntax.DotsType); t != nil {
                                ftype = t.Elem
-                               if variadicOk && i == len(list)-1 {
+                               if kind == ParamVar && i == len(list)-1 {
                                        variadic = true
                                } else {
                                        check.error(t, InvalidSyntaxTree, "invalid use of ...")
@@ -359,14 +360,14 @@ func (check *Checker) collectParams(list []*syntax.Field, variadicOk bool) (name
                                check.error(field.Name, InvalidSyntaxTree, "anonymous parameter")
                                // ok to continue
                        }
-                       par := NewParam(field.Name.Pos(), check.pkg, name, typ)
+                       par := newVar(kind, field.Name.Pos(), check.pkg, name, typ)
                        // named parameter is declared by caller
                        names = append(names, field.Name)
                        params = append(params, par)
                        named = true
                } else {
                        // anonymous parameter
-                       par := NewParam(field.Pos(), check.pkg, "", typ)
+                       par := newVar(kind, field.Pos(), check.pkg, "", typ)
                        check.recordImplicit(field, par)
                        names = append(names, nil)
                        params = append(params, par)
index 8e5beed3f6bff9fdd212ac779dd7113224025c0e..586ae75b1cc67938355a3ef29562d9c8872ab13e 100644 (file)
@@ -793,7 +793,7 @@ func (check *Checker) typeSwitchStmt(inner stmtContext, s *syntax.SwitchStmt, gu
                check.openScope(clause, "case")
                // If lhs exists, declare a corresponding variable in the case-local scope.
                if lhs != nil {
-                       obj := NewVar(lhs.Pos(), check.pkg, lhs.Value, T)
+                       obj := newVar(LocalVar, lhs.Pos(), check.pkg, lhs.Value, T)
                        check.declare(check.scope, nil, obj, clause.Colon)
                        check.recordImplicit(clause, obj)
                        // For the "declared and not used" error, all lhs variables act as
@@ -904,7 +904,7 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
                        if ident, _ := lhs.(*identType); ident != nil {
                                // declare new variable
                                name := identName(ident)
-                               obj = NewVar(ident.Pos(), check.pkg, name, nil)
+                               obj = newVar(LocalVar, ident.Pos(), check.pkg, name, nil)
                                check.recordDef(ident, obj)
                                // _ variables don't count as new variables
                                if name != "_" {
@@ -912,7 +912,7 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
                                }
                        } else {
                                check.errorf(lhs, InvalidSyntaxTree, "cannot declare %s", lhs)
-                               obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
+                               obj = newVar(LocalVar, lhs.Pos(), check.pkg, "_", nil) // dummy variable
                        }
                        assert(obj.typ == nil)
 
index 7664a53579ab3b3a7e9a7d1e117a936b8e5658a7..c66caebd10cef7347863ce1012dc8f6384132130 100644 (file)
@@ -119,8 +119,8 @@ func defPredeclaredTypes() {
                typ := NewNamed(obj, nil, nil)
 
                // error.Error() string
-               recv := NewVar(nopos, nil, "", typ)
-               res := NewVar(nopos, nil, "", Typ[String])
+               recv := newVar(RecvVar, nopos, nil, "", typ)
+               res := newVar(ResultVar, nopos, nil, "", Typ[String])
                sig := NewSignatureType(recv, nil, nil, nil, NewTuple(res), false)
                err := NewFunc(nopos, nil, "Error", sig)
 
index a2c1033991a1a3a08480c70408a4ae7f5ba89996..4f3e2bb44654383b5f1c41fbce28f1236d5b35b6 100644 (file)
@@ -264,7 +264,7 @@ func (p *parser) parseField(pkg *types.Package) (field *types.Var, tag string) {
 }
 
 // Param = Name ["..."] Type .
-func (p *parser) parseParam(pkg *types.Package) (param *types.Var, isVariadic bool) {
+func (p *parser) parseParam(kind types.VarKind, pkg *types.Package) (param *types.Var, isVariadic bool) {
        name := p.parseName()
        // Ignore names invented for inlinable functions.
        if strings.HasPrefix(name, "p.") || strings.HasPrefix(name, "r.") || strings.HasPrefix(name, "$ret") {
@@ -289,13 +289,14 @@ func (p *parser) parseParam(pkg *types.Package) (param *types.Var, isVariadic bo
                typ = types.NewSlice(typ)
        }
        param = types.NewParam(token.NoPos, pkg, name, typ)
+       param.SetKind(kind)
        return
 }
 
 // Var = Name Type .
 func (p *parser) parseVar(pkg *types.Package) *types.Var {
        name := p.parseName()
-       v := types.NewVar(token.NoPos, pkg, name, p.parseType(pkg))
+       v := types.NewVar(token.NoPos, pkg, name, p.parseType(pkg)) // (types.PackageVar)
        if name[0] == '.' || name[0] == '<' {
                // This is an unexported variable,
                // or a variable defined in a different package.
@@ -589,10 +590,10 @@ func (p *parser) parseNamedType(nlist []any) types.Type {
                                p.expect('/')
                        }
                        p.expect('(')
-                       receiver, _ := p.parseParam(pkg)
+                       receiver, _ := p.parseParam(types.RecvVar, pkg)
                        p.expect(')')
                        name := p.parseName()
-                       params, isVariadic := p.parseParamList(pkg)
+                       params, isVariadic := p.parseParamList(types.ParamVar, pkg)
                        results := p.parseResultList(pkg)
                        p.skipInlineBody()
                        p.expectEOL()
@@ -713,7 +714,7 @@ func (p *parser) parseStructType(pkg *types.Package, nlist []any) types.Type {
 }
 
 // ParamList = "(" [ { Parameter "," } Parameter ] ")" .
-func (p *parser) parseParamList(pkg *types.Package) (*types.Tuple, bool) {
+func (p *parser) parseParamList(kind types.VarKind, pkg *types.Package) (*types.Tuple, bool) {
        var list []*types.Var
        isVariadic := false
 
@@ -722,7 +723,7 @@ func (p *parser) parseParamList(pkg *types.Package) (*types.Tuple, bool) {
                if len(list) > 0 {
                        p.expect(',')
                }
-               par, variadic := p.parseParam(pkg)
+               par, variadic := p.parseParam(kind, pkg)
                list = append(list, par)
                if variadic {
                        if isVariadic {
@@ -745,10 +746,12 @@ func (p *parser) parseResultList(pkg *types.Package) *types.Tuple {
                        return nil
                }
                taa, _ := p.parseTypeAfterAngle(pkg)
-               return types.NewTuple(types.NewParam(token.NoPos, pkg, "", taa))
+               param := types.NewParam(token.NoPos, pkg, "", taa)
+               param.SetKind(types.ResultVar)
+               return types.NewTuple(param)
 
        case '(':
-               params, _ := p.parseParamList(pkg)
+               params, _ := p.parseParamList(types.ResultVar, pkg)
                return params
 
        default:
@@ -761,7 +764,7 @@ func (p *parser) parseFunctionType(pkg *types.Package, nlist []any) *types.Signa
        t := new(types.Signature)
        p.update(t, nlist)
 
-       params, isVariadic := p.parseParamList(pkg)
+       params, isVariadic := p.parseParamList(types.ParamVar, pkg)
        results := p.parseResultList(pkg)
 
        *t = *types.NewSignatureType(nil, nil, nil, params, results, isVariadic)
index 3432f08d85012d35a5338c309c56d5092f9687c4..25039a55adbb525a7b7b42d14ddc0146b46c1156 100644 (file)
@@ -399,32 +399,34 @@ func (r *reader) interfaceType() *types.Interface {
 func (r *reader) signature(recv *types.Var, rtparams, tparams []*types.TypeParam) *types.Signature {
        r.Sync(pkgbits.SyncSignature)
 
-       params := r.params()
-       results := r.params()
+       params := r.params(types.ParamVar)
+       results := r.params(types.ResultVar)
        variadic := r.Bool()
 
        return types.NewSignatureType(recv, rtparams, tparams, params, results, variadic)
 }
 
-func (r *reader) params() *types.Tuple {
+func (r *reader) params(kind types.VarKind) *types.Tuple {
        r.Sync(pkgbits.SyncParams)
 
        params := make([]*types.Var, r.Len())
        for i := range params {
-               params[i] = r.param()
+               params[i] = r.param(kind)
        }
 
        return types.NewTuple(params...)
 }
 
-func (r *reader) param() *types.Var {
+func (r *reader) param(kind types.VarKind) *types.Var {
        r.Sync(pkgbits.SyncParam)
 
        pos := r.pos()
        pkg, name := r.localIdent()
        typ := r.typ()
 
-       return types.NewParam(pos, pkg, name, typ)
+       param := types.NewParam(pos, pkg, name, typ)
+       param.SetKind(kind) // âˆˆ {Recv,Param,Result}Var
+       return param
 }
 
 // @@@ Objects
@@ -528,6 +530,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
                                        sig := fn.Signature()
 
                                        recv := types.NewVar(fn.Pos(), fn.Pkg(), "", named)
+                                       recv.SetKind(types.RecvVar)
                                        methods[i] = types.NewFunc(fn.Pos(), fn.Pkg(), fn.Name(), types.NewSignature(recv, sig.Params(), sig.Results(), sig.Variadic()))
                                }
 
@@ -647,7 +650,7 @@ func (r *reader) method() *types.Func {
        pkg, name := r.selector()
 
        rparams := r.typeParamNames()
-       sig := r.signature(r.param(), rparams, nil)
+       sig := r.signature(r.param(types.RecvVar), rparams, nil)
 
        _ = r.pos() // TODO(mdempsky): Remove; this is a hacker for linker.go.
        return types.NewFunc(pos, pkg, name, sig)
index 27b4ab8ea0041306de7e81dd4cc799d4cee8d554..f5a911306fb4b8e653453ea7d047f1802076d8fc 100644 (file)
@@ -14,6 +14,7 @@ import (
        "internal/goversion"
        "internal/testenv"
        "slices"
+       "sort"
        "strings"
        "sync"
        "testing"
@@ -3124,3 +3125,49 @@ func TestVersionWithoutPos(t *testing.T) {
                t.Errorf("check error was %q, want substring %q", got, want)
        }
 }
+
+func TestVarKind(t *testing.T) {
+       fset := token.NewFileSet()
+       f, _ := parser.ParseFile(fset, "a.go", `package p
+
+var global int
+
+type T struct { field int }
+
+func (recv T) f(param int) (result int) {
+       var local int
+       local2 := 0
+       switch local3 := any(local).(type) {
+       default:
+               _ = local3
+       }
+       return local2
+}
+`, 0)
+
+       pkg := NewPackage("p", "p")
+       info := &Info{Defs: make(map[*ast.Ident]Object)}
+       check := NewChecker(&Config{}, fset, pkg, info)
+       if err := check.Files([]*ast.File{f}); err != nil {
+               t.Fatal(err)
+       }
+       var got []string
+       for _, obj := range info.Defs {
+               if v, ok := obj.(*Var); ok {
+                       got = append(got, fmt.Sprintf("%s: %v", v.Name(), v.Kind()))
+               }
+       }
+       sort.Strings(got)
+       want := []string{
+               "field: FieldVar",
+               "global: PackageVar",
+               "local2: LocalVar",
+               "local: LocalVar",
+               "param: ParamVar",
+               "recv: RecvVar",
+               "result: ResultVar",
+       }
+       if !slices.Equal(got, want) {
+               t.Errorf("got:\n%s\nwant:\n%s", got, want)
+       }
+}
index 20d400bf1e894795fad0845a05d97bf4faaba8f5..39dbcf9bb4aeda03b7b7e7a777921659acf4aec3 100644 (file)
@@ -569,7 +569,7 @@ func (check *Checker) shortVarDecl(pos positioner, lhs, rhs []ast.Expr) {
                }
 
                // declare new variable
-               obj := NewVar(ident.Pos(), check.pkg, name, nil)
+               obj := newVar(LocalVar, ident.Pos(), check.pkg, name, nil)
                lhsVars[i] = obj
                if name != "_" {
                        newVars = append(newVars, obj)
@@ -580,7 +580,7 @@ func (check *Checker) shortVarDecl(pos positioner, lhs, rhs []ast.Expr) {
        // create dummy variables where the lhs is invalid
        for i, obj := range lhsVars {
                if obj == nil {
-                       lhsVars[i] = NewVar(lhs[i].Pos(), check.pkg, "_", nil)
+                       lhsVars[i] = newVar(LocalVar, lhs[i].Pos(), check.pkg, "_", nil)
                }
        }
 
index 802afe35deb2133598ffa12cea44f02c110bc923..c714c1f8b08410ed3703664b0af1e01885a5248b 100644 (file)
@@ -1035,13 +1035,13 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x *operand, id builtinId)
 func makeSig(res Type, args ...Type) *Signature {
        list := make([]*Var, len(args))
        for i, param := range args {
-               list[i] = NewVar(nopos, nil, "", Default(param))
+               list[i] = NewParam(nopos, nil, "", Default(param))
        }
        params := NewTuple(list...)
        var result *Tuple
        if res != nil {
                assert(!isUntyped(res))
-               result = NewTuple(NewVar(nopos, nil, "", res))
+               result = NewTuple(newVar(ResultVar, nopos, nil, "", res))
        }
        return &Signature{params: params, results: result}
 }
index b722c3ea264445387ae3ab0f378b37d211ce57ee..702fe55cbd8b83d2bb4f86267d5066486700198a 100644 (file)
@@ -95,7 +95,7 @@ func (check *Checker) funcInst(T *target, pos token.Pos, x *operand, ix *indexed
                                }
                        }
                        gsig := NewSignatureType(nil, nil, nil, sig.params, sig.results, sig.variadic)
-                       params = []*Var{NewVar(x.Pos(), check.pkg, "", gsig)}
+                       params = []*Var{NewParam(x.Pos(), check.pkg, "", gsig)}
                        // The type of the argument operand is tsig, which is the type of the LHS in an assignment
                        // or the result type in a return statement. Create a pseudo-expression for that operand
                        // that makes sense when reported in error messages from infer, below.
@@ -878,7 +878,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *TypeName, w
                                name = "_"
                        }
                }
-               params = append([]*Var{NewVar(sig.recv.pos, sig.recv.pkg, name, x.typ)}, params...)
+               params = append([]*Var{NewParam(sig.recv.pos, sig.recv.pkg, name, x.typ)}, params...)
                x.mode = value
                x.typ = &Signature{
                        tparams:  sig.tparams,
index cd0a15e8fedef3a3ecfd16870a574b3529ca74ee..e1876f2bd656bf79a6752b80a2fa717822e91656 100644 (file)
@@ -41,7 +41,7 @@ func TestContextHashCollisions(t *testing.T) {
        {
                // type unaryP = func[P any](_ P)
                tparam := NewTypeParam(NewTypeName(nopos, nil, "P", nil), &emptyInterface)
-               params := NewTuple(NewVar(nopos, nil, "_", tparam))
+               params := NewTuple(NewParam(nopos, nil, "_", tparam))
                unaryP = NewSignatureType(nil, nil, []*TypeParam{tparam}, params, nil, false)
        }
 
index 04dfc5af4b3720fcb2af7b9a56a89c6a4a30928d..360cb4deb0ef46465755d84cd4eff6aa86b15dc7 100644 (file)
@@ -909,7 +909,7 @@ func (check *Checker) declStmt(d ast.Decl) {
 
                        lhs0 := make([]*Var, len(d.spec.Names))
                        for i, name := range d.spec.Names {
-                               lhs0[i] = NewVar(name.Pos(), pkg, name.Name, nil)
+                               lhs0[i] = newVar(LocalVar, name.Pos(), pkg, name.Name, nil)
                        }
 
                        // initialize all variables
index e5ca042e7509fc18f166b6b853885e0418c76519..6bcae7aef0e02f0f4b9350761d4c197cca86d59f 100644 (file)
@@ -59,7 +59,7 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface {
        typ := (*Checker)(nil).newInterface()
        for _, m := range methods {
                if sig := m.typ.(*Signature); sig.recv == nil {
-                       sig.recv = NewVar(m.pos, m.pkg, "", typ)
+                       sig.recv = newVar(RecvVar, m.pos, m.pkg, "", typ)
                }
        }
 
@@ -206,7 +206,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
                                recvTyp = named
                        }
                }
-               sig.recv = NewVar(name.Pos(), check.pkg, "", recvTyp)
+               sig.recv = newVar(RecvVar, name.Pos(), check.pkg, "", recvTyp)
 
                m := NewFunc(name.Pos(), check.pkg, name.Name, sig)
                check.recordDef(name, m)
index f2c63f16f9aba6bfedc7dc1c96bbdaebc40041ed..2c1cfb8bfac561776e86031598b32dd7796425c0 100644 (file)
@@ -638,7 +638,7 @@ func TestIssue50646(t *testing.T) {
 func TestIssue55030(t *testing.T) {
        // makeSig makes the signature func(typ...)
        makeSig := func(typ Type) {
-               par := NewVar(nopos, nil, "", typ)
+               par := NewParam(nopos, nil, "", typ)
                params := NewTuple(par)
                NewSignatureType(nil, nil, nil, params, nil, true)
        }
index 80cd650ff154db6e77f25171b8838b2ff625c254..86bd37128fee826510209ffd1604a185daf36280 100644 (file)
@@ -334,28 +334,81 @@ func (obj *TypeName) IsAlias() bool {
 // A Variable represents a declared variable (including function parameters and results, and struct fields).
 type Var struct {
        object
+       kind     VarKind
        embedded bool // if set, the variable is an embedded struct field, and name is the type name
-       isField  bool // var is struct field
        used     bool // set if the variable was used
        origin   *Var // if non-nil, the Var from which this one was instantiated
 }
 
+// A VarKind discriminates the various kinds of variables.
+type VarKind uint8
+
+const (
+       _          VarKind = iota // (not meaningful)
+       PackageVar                // a package-level variable
+       LocalVar                  // a local variable
+       RecvVar                   // a method receiver variable
+       ParamVar                  // a function parameter variable
+       ResultVar                 // a function result variable
+       FieldVar                  // a struct field
+)
+
+var varKindNames = [...]string{
+       0:          "VarKind(0)",
+       PackageVar: "PackageVar",
+       LocalVar:   "LocalVar",
+       RecvVar:    "RecvVar",
+       ParamVar:   "ParamVar",
+       ResultVar:  "ResultVar",
+       FieldVar:   "FieldVar",
+}
+
+func (kind VarKind) String() string {
+       if 0 <= kind && int(kind) < len(varKindNames) {
+               return varKindNames[kind]
+       }
+       return fmt.Sprintf("VarKind(%d)", kind)
+}
+
+// Kind reports what kind of variable v is.
+func (v *Var) Kind() VarKind { return v.kind }
+
+// SetKind sets the kind of the variable.
+// It should be used only immediately after [NewVar] or [NewParam].
+func (v *Var) SetKind(kind VarKind) { v.kind = kind }
+
 // NewVar returns a new variable.
 // The arguments set the attributes found with all Objects.
+//
+// The caller must subsequently call [Var.SetKind]
+// if the desired Var is not of kind [PackageVar].
 func NewVar(pos token.Pos, pkg *Package, name string, typ Type) *Var {
-       return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}}
+       return newVar(PackageVar, pos, pkg, name, typ)
 }
 
 // NewParam returns a new variable representing a function parameter.
+//
+// The caller must subsequently call [Var.SetKind] if the desired Var
+// is not of kind [ParamVar]: for example, [RecvVar] or [ResultVar].
 func NewParam(pos token.Pos, pkg *Package, name string, typ Type) *Var {
-       return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, used: true} // parameters are always 'used'
+       return newVar(ParamVar, pos, pkg, name, typ)
 }
 
 // NewField returns a new variable representing a struct field.
 // For embedded fields, the name is the unqualified type name
 // under which the field is accessible.
 func NewField(pos token.Pos, pkg *Package, name string, typ Type, embedded bool) *Var {
-       return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, embedded: embedded, isField: true}
+       v := newVar(FieldVar, pos, pkg, name, typ)
+       v.embedded = embedded
+       return v
+}
+
+// newVar returns a new variable.
+// The arguments set the attributes found with all Objects.
+func newVar(kind VarKind, pos token.Pos, pkg *Package, name string, typ Type) *Var {
+       // Function parameters are always 'used'.
+       used := kind == RecvVar || kind == ParamVar || kind == ResultVar
+       return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, kind: kind, used: used}
 }
 
 // Anonymous reports whether the variable is an embedded field.
@@ -366,7 +419,7 @@ func (obj *Var) Anonymous() bool { return obj.embedded }
 func (obj *Var) Embedded() bool { return obj.embedded }
 
 // IsField reports whether the variable is a struct field.
-func (obj *Var) IsField() bool { return obj.isField }
+func (obj *Var) IsField() bool { return obj.kind == FieldVar }
 
 // Origin returns the canonical Var for its receiver, i.e. the Var object
 // recorded in Info.Defs.
@@ -529,7 +582,7 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
                }
 
        case *Var:
-               if obj.isField {
+               if obj.IsField() {
                        buf.WriteString("field")
                } else {
                        buf.WriteString("var")
index 8bdc0dfa0e8ec90f502fcc64cb5f898658159901..c6da3357b550ace45d8a3bc646a72b89547bb383 100644 (file)
@@ -108,8 +108,8 @@ func (check *Checker) recordCommaOkTypes(x ast.Expr, a []*operand) {
                        assert(tv.Type != nil) // should have been recorded already
                        pos := x.Pos()
                        tv.Type = NewTuple(
-                               NewVar(pos, check.pkg, "", t0),
-                               NewVar(pos, check.pkg, "", t1),
+                               newVar(LocalVar, pos, check.pkg, "", t0),
+                               newVar(LocalVar, pos, check.pkg, "", t1),
                        )
                        m[x] = tv
                        // if x is a parenthesized expression (p.X), update p.X
index ef9ffb5013e0445aa6a14a5c7376dd4c59a049b9..9e47b85c7f91cc0823f3e2d3657ddec9430da09c 100644 (file)
@@ -379,7 +379,7 @@ func (check *Checker) collectObjects() {
 
                                // declare all variables
                                for i, name := range d.spec.Names {
-                                       obj := NewVar(name.Pos(), pkg, name.Name, nil)
+                                       obj := newVar(PackageVar, name.Pos(), pkg, name.Name, nil)
                                        lhs[i] = obj
 
                                        di := d1
index babb24b0ca6eafbaec14c8383b337ba938c178d4..0bf28f8947c9596f1ece1cab928e589b8d95bf5d 100644 (file)
@@ -140,8 +140,8 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
        }
 
        // collect ordinary and result parameters
-       pnames, params, variadic := check.collectParams(ftyp.Params, true)
-       rnames, results, _ := check.collectParams(ftyp.Results, false)
+       pnames, params, variadic := check.collectParams(ParamVar, ftyp.Params)
+       rnames, results, _ := check.collectParams(ResultVar, ftyp.Results)
 
        // declare named receiver, ordinary, and result parameters
        scopePos := ftyp.End() // all parameter's scopes start after the signature
@@ -290,13 +290,13 @@ func (check *Checker) collectRecv(rparam *ast.Field, scopePos token.Pos) (*Var,
        var recv *Var
        if rname != nil && rname.Name != "" {
                // named receiver
-               recv = NewParam(rname.Pos(), check.pkg, rname.Name, recvType)
+               recv = newVar(RecvVar, rname.Pos(), check.pkg, rname.Name, recvType)
                // In this case, the receiver is declared by the caller
                // because it must be declared after any type parameters
                // (otherwise it might shadow one of them).
        } else {
                // anonymous receiver
-               recv = NewParam(rparam.Pos(), check.pkg, "", recvType)
+               recv = newVar(RecvVar, rparam.Pos(), check.pkg, "", recvType)
                check.recordImplicit(rparam, recv)
        }
 
@@ -350,10 +350,11 @@ func (check *Checker) recordParenthesizedRecvTypes(expr ast.Expr, typ Type) {
        }
 }
 
-// collectParams collects (but does not declare) all parameters of list and returns
-// the list of parameter names, corresponding parameter variables, and whether the
-// parameter list is variadic. Anonymous parameters are recorded with nil names.
-func (check *Checker) collectParams(list *ast.FieldList, variadicOk bool) (names []*ast.Ident, params []*Var, variadic bool) {
+// collectParams collects (but does not declare) all parameter/result
+// variables of list and returns the list of names and corresponding
+// variables, and whether the (parameter) list is variadic.
+// Anonymous parameters are recorded with nil names.
+func (check *Checker) collectParams(kind VarKind, list *ast.FieldList) (names []*ast.Ident, params []*Var, variadic bool) {
        if list == nil {
                return
        }
@@ -363,7 +364,7 @@ func (check *Checker) collectParams(list *ast.FieldList, variadicOk bool) (names
                ftype := field.Type
                if t, _ := ftype.(*ast.Ellipsis); t != nil {
                        ftype = t.Elt
-                       if variadicOk && i == len(list.List)-1 && len(field.Names) <= 1 {
+                       if kind == ParamVar && i == len(list.List)-1 && len(field.Names) <= 1 {
                                variadic = true
                        } else {
                                check.softErrorf(t, InvalidSyntaxTree, "invalid use of ...")
@@ -380,7 +381,7 @@ func (check *Checker) collectParams(list *ast.FieldList, variadicOk bool) (names
                                        check.error(name, InvalidSyntaxTree, "anonymous parameter")
                                        // ok to continue
                                }
-                               par := NewParam(name.Pos(), check.pkg, name.Name, typ)
+                               par := newVar(kind, name.Pos(), check.pkg, name.Name, typ)
                                // named parameter is declared by caller
                                names = append(names, name)
                                params = append(params, par)
@@ -388,7 +389,7 @@ func (check *Checker) collectParams(list *ast.FieldList, variadicOk bool) (names
                        named = true
                } else {
                        // anonymous parameter
-                       par := NewParam(ftype.Pos(), check.pkg, "", typ)
+                       par := newVar(kind, ftype.Pos(), check.pkg, "", typ)
                        check.recordImplicit(field, par)
                        names = append(names, nil)
                        params = append(params, par)
index 297dc3ba06e36543fb6df1a9ace686035e2246a7..76ab2063e2f7579849f152d29365df483088c526 100644 (file)
@@ -752,7 +752,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
                        check.openScope(clause, "case")
                        // If lhs exists, declare a corresponding variable in the case-local scope.
                        if lhs != nil {
-                               obj := NewVar(lhs.Pos(), check.pkg, lhs.Name, T)
+                               obj := newVar(LocalVar, lhs.Pos(), check.pkg, lhs.Name, T)
                                check.declare(check.scope, nil, obj, clause.Colon)
                                check.recordImplicit(clause, obj)
                                // For the "declared and not used" error, all lhs variables act as
@@ -922,7 +922,7 @@ func (check *Checker) rangeStmt(inner stmtContext, s *ast.RangeStmt) {
                        if ident, _ := lhs.(*identType); ident != nil {
                                // declare new variable
                                name := identName(ident)
-                               obj = NewVar(ident.Pos(), check.pkg, name, nil)
+                               obj = newVar(LocalVar, ident.Pos(), check.pkg, name, nil)
                                check.recordDef(ident, obj)
                                // _ variables don't count as new variables
                                if name != "_" {
@@ -930,7 +930,7 @@ func (check *Checker) rangeStmt(inner stmtContext, s *ast.RangeStmt) {
                                }
                        } else {
                                check.errorf(lhs, InvalidSyntaxTree, "cannot declare %s", lhs)
-                               obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
+                               obj = newVar(LocalVar, lhs.Pos(), check.pkg, "_", nil) // dummy variable
                        }
                        assert(obj.typ == nil)
 
index 750a368278ab63a2667335d8d4e962857babea1f..4753111c1181083f523919604a609a948217e839 100644 (file)
@@ -122,8 +122,8 @@ func defPredeclaredTypes() {
                typ := NewNamed(obj, nil, nil)
 
                // error.Error() string
-               recv := NewVar(nopos, nil, "", typ)
-               res := NewVar(nopos, nil, "", Typ[String])
+               recv := newVar(RecvVar, nopos, nil, "", typ)
+               res := newVar(ResultVar, nopos, nil, "", Typ[String])
                sig := NewSignatureType(recv, nil, nil, nil, NewTuple(res), false)
                err := NewFunc(nopos, nil, "Error", sig)