From 7696c9433406c3f5b9f127cb557120b74e3c3952 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 11 Feb 2021 10:45:49 -0500 Subject: [PATCH] [dev.regabi] go/types: type alias decl requires go1.9 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 Trust: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/decl.go | 18 ++++++++++++------ src/go/types/errorcodes.go | 3 +++ src/go/types/resolver.go | 8 ++++---- src/go/types/testdata/go1_8.src | 11 +++++++++++ 4 files changed, 30 insertions(+), 10 deletions(-) create mode 100644 src/go/types/testdata/go1_8.src diff --git a/src/go/types/decl.go b/src/go/types/decl.go index 571e172351..b861cde496 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -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()) diff --git a/src/go/types/errorcodes.go b/src/go/types/errorcodes.go index d27abdf4d4..ac28c3bd13 100644 --- a/src/go/types/errorcodes.go +++ b/src/go/types/errorcodes.go @@ -1366,4 +1366,7 @@ const ( // return i // } _InvalidGo + + // _BadDecl occurs when a declaration has invalid syntax. + _BadDecl ) diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go index 47e165db36..e4411592e8 100644 --- a/src/go/types/resolver.go +++ b/src/go/types/resolver.go @@ -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 index 0000000000..3ead1e981b --- /dev/null +++ b/src/go/types/testdata/go1_8.src @@ -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{} +