]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.regabi] go/types: type alias decl requires go1.9
authorRob Findley <rfindley@google.com>
Thu, 11 Feb 2021 15:45:49 +0000 (10:45 -0500)
committerRobert Findley <rfindley@google.com>
Tue, 16 Feb 2021 21:01:14 +0000 (21:01 +0000)
This is a port of CL 289570 to go/types. It has some notable differences
with that CL:
 + A new _BadDecl error code is added, to indicate declarations with bad
   syntax.
 + declInfo is updated hold not an 'alias' bool, but an aliasPos
   token.Pos to identify the location of the type aliasing '=' token.
   This allows for error messages to be accurately placed on the '='

For #31793

Change-Id: Ib15969f9cd5be30228b7a4c6406f978d6fc58018
Reviewed-on: https://go-review.googlesource.com/c/go/+/291318
Trust: Robert Findley <rfindley@google.com>
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/go/types/decl.go
src/go/types/errorcodes.go
src/go/types/resolver.go
src/go/types/testdata/go1_8.src [new file with mode: 0644]

index 571e172351befb77219e544052cd7c00d6d5fb79..b861cde496490095c71cc9b08d1e6152b37ca0f8 100644 (file)
@@ -189,7 +189,7 @@ func (check *Checker) objDecl(obj Object, def *Named) {
                check.varDecl(obj, d.lhs, d.typ, d.init)
        case *TypeName:
                // invalid recursive types are detected via path
-               check.typeDecl(obj, d.typ, def, d.alias)
+               check.typeDecl(obj, d.typ, def, d.aliasPos)
        case *Func:
                // functions may be recursive - no need to track dependencies
                check.funcDecl(obj, d)
@@ -234,7 +234,7 @@ func (check *Checker) cycle(obj Object) (isCycle bool) {
                        // this information explicitly in the object.
                        var alias bool
                        if d := check.objMap[obj]; d != nil {
-                               alias = d.alias // package-level object
+                               alias = d.aliasPos.IsValid() // package-level object
                        } else {
                                alias = obj.IsAlias() // function local object
                        }
@@ -640,14 +640,17 @@ func (n *Named) setUnderlying(typ Type) {
        }
 }
 
-func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, alias bool) {
+func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, aliasPos token.Pos) {
        assert(obj.typ == nil)
 
        check.later(func() {
                check.validType(obj.typ, nil)
        })
 
-       if alias {
+       if aliasPos.IsValid() {
+               if !check.allowVersion(obj.pkg, 1, 9) {
+                       check.errorf(atPos(aliasPos), _BadDecl, "type aliases requires go1.9 or later")
+               }
 
                obj.typ = Typ[Invalid]
                obj.typ = check.typ(typ)
@@ -678,9 +681,12 @@ func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, alias bo
 
        }
 
+       // TODO(rFindley): move to the callsite, as this is only needed for top-level
+       //                 decls.
        check.addMethodDecls(obj)
 }
 
+// TODO(rFindley): rename to collectMethods, to be consistent with types2.
 func (check *Checker) addMethodDecls(obj *TypeName) {
        // get associated methods
        // (Checker.collectObjects only collects methods with non-blank names;
@@ -691,7 +697,7 @@ func (check *Checker) addMethodDecls(obj *TypeName) {
                return
        }
        delete(check.methods, obj)
-       assert(!check.objMap[obj].alias) // don't use TypeName.IsAlias (requires fully set up object)
+       assert(!check.objMap[obj].aliasPos.IsValid()) // don't use TypeName.IsAlias (requires fully set up object)
 
        // use an objset to check for name conflicts
        var mset objset
@@ -864,7 +870,7 @@ func (check *Checker) declStmt(d ast.Decl) {
                        check.declare(check.scope, d.spec.Name, obj, scopePos)
                        // mark and unmark type before calling typeDecl; its type is still nil (see Checker.objDecl)
                        obj.setColor(grey + color(check.push(obj)))
-                       check.typeDecl(obj, d.spec.Type, nil, d.spec.Assign.IsValid())
+                       check.typeDecl(obj, d.spec.Type, nil, d.spec.Assign)
                        check.pop().setColor(black)
                default:
                        check.invalidAST(d.node(), "unknown ast.Decl node %T", d.node())
index d27abdf4d48bf144e48a2fe45e771df81669b212..ac28c3bd13443d65e3db53b41086a92e5751f315 100644 (file)
@@ -1366,4 +1366,7 @@ const (
        //      return i
        //  }
        _InvalidGo
+
+       // _BadDecl occurs when a declaration has invalid syntax.
+       _BadDecl
 )
index 47e165db368a14d14cfbe77f6094c7a7e9b48dc9..e4411592e82a0ae6c77ce570d8106a7828ceb155 100644 (file)
@@ -23,7 +23,7 @@ type declInfo struct {
        init      ast.Expr      // init/orig expression, or nil
        inherited bool          // if set, the init expression is inherited from a previous constant declaration
        fdecl     *ast.FuncDecl // func declaration, or nil
-       alias     bool          // type alias declaration
+       aliasPos  token.Pos     // If valid, the decl is a type alias and aliasPos is the position of '='.
 
        // The deps field tracks initialization expression dependencies.
        deps map[Object]bool // lazily initialized
@@ -366,7 +366,7 @@ func (check *Checker) collectObjects() {
                                }
                        case typeDecl:
                                obj := NewTypeName(d.spec.Name.Pos(), pkg, d.spec.Name.Name, nil)
-                               check.declarePkgObj(d.spec.Name, obj, &declInfo{file: fileScope, typ: d.spec.Type, alias: d.spec.Assign.IsValid()})
+                               check.declarePkgObj(d.spec.Name, obj, &declInfo{file: fileScope, typ: d.spec.Type, aliasPos: d.spec.Assign})
                        case funcDecl:
                                info := &declInfo{file: fileScope, fdecl: d.decl}
                                name := d.decl.Name.Name
@@ -493,7 +493,7 @@ func (check *Checker) resolveBaseTypeName(typ ast.Expr) (ptr bool, base *TypeNam
                // we're done if tdecl defined tname as a new type
                // (rather than an alias)
                tdecl := check.objMap[tname] // must exist for objects in package scope
-               if !tdecl.alias {
+               if !tdecl.aliasPos.IsValid() {
                        return ptr, tname
                }
 
@@ -534,7 +534,7 @@ func (check *Checker) packageObjects() {
        // phase 1
        for _, obj := range objList {
                // If we have a type alias, collect it for the 2nd phase.
-               if tname, _ := obj.(*TypeName); tname != nil && check.objMap[tname].alias {
+               if tname, _ := obj.(*TypeName); tname != nil && check.objMap[tname].aliasPos.IsValid() {
                        aliasList = append(aliasList, tname)
                        continue
                }
diff --git a/src/go/types/testdata/go1_8.src b/src/go/types/testdata/go1_8.src
new file mode 100644 (file)
index 0000000..3ead1e9
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check Go language version-specific errors.
+
+package go1_8 // go1.8
+
+// type alias declarations
+type any = /* ERROR type aliases requires go1.9 or later */ interface{}
+