aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cmd/compile/internal/noder/noder.go2
-rw-r--r--src/cmd/compile/internal/types2/call.go11
-rw-r--r--src/cmd/compile/internal/types2/decl.go23
-rw-r--r--src/cmd/compile/internal/types2/resolver.go40
-rw-r--r--src/cmd/compile/internal/types2/subst.go2
-rw-r--r--src/cmd/compile/internal/types2/testdata/check/decls0.src2
-rw-r--r--src/cmd/compile/internal/types2/testdata/check/issues.src6
-rw-r--r--src/cmd/compile/internal/types2/testdata/check/main.go22
-rw-r--r--src/cmd/compile/internal/types2/testdata/check/typeparams.go24
-rw-r--r--src/cmd/compile/internal/types2/testdata/fixedbugs/issue47818.go259
-rw-r--r--src/cmd/compile/internal/types2/typeset.go11
-rw-r--r--src/cmd/compile/internal/types2/typexpr.go15
-rw-r--r--test/fixedbugs/issue10975.go2
13 files changed, 142 insertions, 37 deletions
diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go
index 2b67a91b3f..e1b485b2b3 100644
--- a/src/cmd/compile/internal/noder/noder.go
+++ b/src/cmd/compile/internal/noder/noder.go
@@ -35,7 +35,7 @@ func LoadPackage(filenames []string) {
supportsGenerics := base.Flag.G != 0 || buildcfg.Experiment.Unified
mode := syntax.CheckBranches
- if supportsGenerics && types.AllowsGoVersion(types.LocalPkg, 1, 18) {
+ if supportsGenerics {
mode |= syntax.AllowGenerics
}
diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go
index 4bbc524856..0b062b4c94 100644
--- a/src/cmd/compile/internal/types2/call.go
+++ b/src/cmd/compile/internal/types2/call.go
@@ -15,6 +15,10 @@ import (
// funcInst type-checks a function instantiation inst and returns the result in x.
// The operand x must be the evaluation of inst.X and its type must be a signature.
func (check *Checker) funcInst(x *operand, inst *syntax.IndexExpr) {
+ if !check.allowVersion(check.pkg, 1, 18) {
+ check.softErrorf(inst.Pos(), "function instantiation requires go1.18 or later")
+ }
+
xlist := unpackExpr(inst.Index)
targs := check.typeList(xlist)
if targs == nil {
@@ -318,6 +322,13 @@ func (check *Checker) arguments(call *syntax.CallExpr, sig *Signature, targs []T
// infer type arguments and instantiate signature if necessary
if sig.TParams().Len() > 0 {
+ if !check.allowVersion(check.pkg, 1, 18) {
+ if iexpr, _ := call.Fun.(*syntax.IndexExpr); iexpr != nil {
+ check.softErrorf(iexpr.Pos(), "function instantiation requires go1.18 or later")
+ } else {
+ check.softErrorf(call.Pos(), "implicit function instantiation requires go1.18 or later")
+ }
+ }
// TODO(gri) provide position information for targs so we can feed
// it to the instantiate call for better error reporting
targs := check.infer(call.Pos(), sig.TParams().list(), targs, sigParams, args, true)
diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go
index 342e1090de..d7a33546aa 100644
--- a/src/cmd/compile/internal/types2/decl.go
+++ b/src/cmd/compile/internal/types2/decl.go
@@ -514,11 +514,26 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init syntax.Expr) {
check.initVars(lhs, []syntax.Expr{init}, nopos)
}
+// isImportedConstraint reports whether typ is an imported type constraint.
+func (check *Checker) isImportedConstraint(typ Type) bool {
+ named, _ := typ.(*Named)
+ if named == nil || named.obj.pkg == check.pkg || named.obj.pkg == nil {
+ return false
+ }
+ u, _ := named.under().(*Interface)
+ return u != nil && u.IsConstraint()
+}
+
func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named) {
assert(obj.typ == nil)
+ var rhs Type
check.later(func() {
check.validType(obj.typ, nil)
+ // If typ is local, an error was already reported where typ is specified/defined.
+ if check.isImportedConstraint(rhs) && !check.allowVersion(check.pkg, 1, 18) {
+ check.errorf(tdecl.Type.Pos(), "using type constraint %s requires go1.18 or later", rhs)
+ }
})
alias := tdecl.Alias
@@ -540,7 +555,8 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named
}
obj.typ = Typ[Invalid]
- obj.typ = check.anyType(tdecl.Type)
+ rhs = check.anyType(tdecl.Type)
+ obj.typ = rhs
return
}
@@ -555,8 +571,9 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named
}
// determine underlying type of named
- named.fromRHS = check.definedType(tdecl.Type, named)
- assert(named.fromRHS != nil)
+ rhs = check.definedType(tdecl.Type, named)
+ assert(rhs != nil)
+ named.fromRHS = rhs
// The underlying type of named may be itself a named type that is
// incomplete:
//
diff --git a/src/cmd/compile/internal/types2/resolver.go b/src/cmd/compile/internal/types2/resolver.go
index 018a20cfb2..34fbc3d41b 100644
--- a/src/cmd/compile/internal/types2/resolver.go
+++ b/src/cmd/compile/internal/types2/resolver.go
@@ -412,52 +412,60 @@ func (check *Checker) collectObjects() {
}
case *syntax.TypeDecl:
+ if len(s.TParamList) != 0 && !check.allowVersion(pkg, 1, 18) {
+ check.softErrorf(s.TParamList[0], "type parameters require go1.18 or later")
+ }
obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Value, nil)
check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, tdecl: s})
case *syntax.FuncDecl:
- d := s // TODO(gri) get rid of this
- name := d.Name.Value
- obj := NewFunc(d.Name.Pos(), pkg, name, nil)
- if d.Recv == nil {
+ name := s.Name.Value
+ obj := NewFunc(s.Name.Pos(), pkg, name, nil)
+ hasTParamError := false // avoid duplicate type parameter errors
+ if s.Recv == nil {
// regular function
if name == "init" || name == "main" && pkg.name == "main" {
- if d.TParamList != nil {
- check.softErrorf(d, "func %s must have no type parameters", name)
+ if len(s.TParamList) != 0 {
+ check.softErrorf(s.TParamList[0], "func %s must have no type parameters", name)
+ hasTParamError = true
}
- if t := d.Type; len(t.ParamList) != 0 || len(t.ResultList) != 0 {
- check.softErrorf(d, "func %s must have no arguments and no return values", name)
+ if t := s.Type; len(t.ParamList) != 0 || len(t.ResultList) != 0 {
+ check.softErrorf(s, "func %s must have no arguments and no return values", name)
}
}
// don't declare init functions in the package scope - they are invisible
if name == "init" {
obj.parent = pkg.scope
- check.recordDef(d.Name, obj)
+ check.recordDef(s.Name, obj)
// init functions must have a body
- if d.Body == nil {
+ if s.Body == nil {
// TODO(gri) make this error message consistent with the others above
check.softErrorf(obj.pos, "missing function body")
}
} else {
- check.declare(pkg.scope, d.Name, obj, nopos)
+ check.declare(pkg.scope, s.Name, obj, nopos)
}
} else {
// method
// d.Recv != nil
- if !acceptMethodTypeParams && len(d.TParamList) != 0 {
+ if !acceptMethodTypeParams && len(s.TParamList) != 0 {
//check.error(d.TParamList.Pos(), invalidAST + "method must have no type parameters")
- check.error(d, invalidAST+"method must have no type parameters")
+ check.error(s.TParamList[0], invalidAST+"method must have no type parameters")
+ hasTParamError = true
}
- ptr, recv, _ := check.unpackRecv(d.Recv.Type, false)
+ ptr, recv, _ := check.unpackRecv(s.Recv.Type, false)
// (Methods with invalid receiver cannot be associated to a type, and
// methods with blank _ names are never found; no need to collect any
// of them. They will still be type-checked with all the other functions.)
if recv != nil && name != "_" {
methods = append(methods, methodInfo{obj, ptr, recv})
}
- check.recordDef(d.Name, obj)
+ check.recordDef(s.Name, obj)
+ }
+ if len(s.TParamList) != 0 && !check.allowVersion(pkg, 1, 18) && !hasTParamError {
+ check.softErrorf(s.TParamList[0], "type parameters require go1.18 or later")
}
- info := &declInfo{file: fileScope, fdecl: d}
+ info := &declInfo{file: fileScope, fdecl: s}
// Methods are not package-level objects but we still track them in the
// object map so that we can handle them like regular functions (if the
// receiver is invalid); also we need their fdecl info when associating
diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go
index 918e5f3043..ff8dd13b6d 100644
--- a/src/cmd/compile/internal/types2/subst.go
+++ b/src/cmd/compile/internal/types2/subst.go
@@ -38,7 +38,7 @@ func (m substMap) lookup(tpar *TypeParam) Type {
// subst returns the type typ with its type parameters tpars replaced by the
// corresponding type arguments targs, recursively. subst doesn't modify the
// incoming type. If a substitution took place, the result type is different
-// from from the incoming type.
+// from the incoming type.
//
// If the given typMap is non-nil, it is used in lieu of check.typMap.
func (check *Checker) subst(pos syntax.Pos, typ Type, smap substMap, typMap map[string]*Named) Type {
diff --git a/src/cmd/compile/internal/types2/testdata/check/decls0.src b/src/cmd/compile/internal/types2/testdata/check/decls0.src
index f051a4f2ac..09e5d5c5ad 100644
--- a/src/cmd/compile/internal/types2/testdata/check/decls0.src
+++ b/src/cmd/compile/internal/types2/testdata/check/decls0.src
@@ -146,7 +146,7 @@ type (
m1(I5)
}
I6 interface {
- S0 /* ERROR "not an interface" */
+ S0 /* ERROR "non-interface type S0" */
}
I7 interface {
I1
diff --git a/src/cmd/compile/internal/types2/testdata/check/issues.src b/src/cmd/compile/internal/types2/testdata/check/issues.src
index 692ed37ef4..d83a95af0e 100644
--- a/src/cmd/compile/internal/types2/testdata/check/issues.src
+++ b/src/cmd/compile/internal/types2/testdata/check/issues.src
@@ -79,11 +79,11 @@ func issue9473(a []int, b ...int) {
// Check that embedding a non-interface type in an interface results in a good error message.
func issue10979() {
type _ interface {
- int /* ERROR int is not an interface */
+ int /* ERROR non-interface type int */
}
type T struct{}
type _ interface {
- T /* ERROR T is not an interface */
+ T /* ERROR non-interface type T */
}
type _ interface {
nosuchtype /* ERROR undeclared name: nosuchtype */
@@ -280,7 +280,7 @@ type issue25301b /* ERROR cycle */ = interface {
}
type issue25301c interface {
- notE // ERROR struct\{\} is not an interface
+ notE // ERROR non-interface type struct\{\}
}
type notE = struct{}
diff --git a/src/cmd/compile/internal/types2/testdata/check/main.go2 b/src/cmd/compile/internal/types2/testdata/check/main.go2
index b7ddeaa1a8..395e3bfec8 100644
--- a/src/cmd/compile/internal/types2/testdata/check/main.go2
+++ b/src/cmd/compile/internal/types2/testdata/check/main.go2
@@ -4,4 +4,4 @@
package main
-func /* ERROR "func main must have no type parameters" */ main[T any]() {}
+func main [T /* ERROR "func main must have no type parameters" */ any]() {}
diff --git a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 b/src/cmd/compile/internal/types2/testdata/check/typeparams.go2
index 1ad80b1e1b..765d561f3b 100644
--- a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2
+++ b/src/cmd/compile/internal/types2/testdata/check/typeparams.go2
@@ -304,8 +304,8 @@ var _ = f8[int, float64](0, 0, nil...) // test case for #18268
// init functions cannot have type parameters
func init() {}
-func init[/* ERROR func init must have no type parameters */ _ any]() {}
-func init[/* ERROR func init must have no type parameters */ P any]() {}
+func init[_ /* ERROR func init must have no type parameters */ any]() {}
+func init[P /* ERROR func init must have no type parameters */ any]() {}
type T struct {}
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47818.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47818.go2
new file mode 100644
index 0000000000..5334695b5e
--- /dev/null
+++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47818.go2
@@ -0,0 +1,59 @@
+// 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.
+
+// Parser accepts type parameters but the type checker
+// needs to report any operations that are not permitted
+// before Go 1.18.
+
+package go1_17
+
+type T[P /* ERROR type parameters require go1\.18 or later */ any] struct{}
+
+// for init (and main, but we're not in package main) we should only get one error
+func init[P /* ERROR func init must have no type parameters */ any]() {}
+func main[P /* ERROR type parameters require go1\.18 or later */ any]() {}
+
+func f[P /* ERROR type parameters require go1\.18 or later */ any](x P) {
+ var _ T[ /* ERROR type instantiation requires go1\.18 or later */ int]
+ var _ (T[ /* ERROR type instantiation requires go1\.18 or later */ int])
+ _ = T[ /* ERROR type instantiation requires go1\.18 or later */ int]{}
+ _ = T[ /* ERROR type instantiation requires go1\.18 or later */ int](struct{}{})
+}
+
+func (T[ /* ERROR type instantiation requires go1\.18 or later */ P]) g(x int) {
+ f[ /* ERROR function instantiation requires go1\.18 or later */ int](0) // explicit instantiation
+ (f[ /* ERROR function instantiation requires go1\.18 or later */ int])(0) // parentheses (different code path)
+ f( /* ERROR implicit function instantiation requires go1\.18 or later */ x) // implicit instantiation
+}
+
+type C1 interface {
+ comparable // ERROR undeclared name: comparable \(requires version go1\.18 or later\)
+}
+
+type C2 interface {
+ comparable // ERROR undeclared name: comparable \(requires version go1\.18 or later\)
+ int // ERROR embedding non-interface type int requires go1\.18 or later
+ ~ /* ERROR embedding interface element ~int requires go1\.18 or later */ int
+ int /* ERROR embedding interface element int\|~string requires go1\.18 or later */ | ~string
+}
+
+type _ interface {
+ // errors for these were reported with their declaration
+ C1
+ C2
+}
+
+type (
+ _ comparable // ERROR undeclared name: comparable \(requires version go1\.18 or later\)
+ // errors for these were reported with their declaration
+ _ C1
+ _ C2
+
+ _ = comparable // ERROR undeclared name: comparable \(requires version go1\.18 or later\)
+ // errors for these were reported with their declaration
+ _ = C1
+ _ = C2
+)
+
+// TODO(gri) need test cases for imported constraint types (see also issue #47967) \ No newline at end of file
diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go
index 14596b68a3..56f64ab405 100644
--- a/src/cmd/compile/internal/types2/typeset.go
+++ b/src/cmd/compile/internal/types2/typeset.go
@@ -271,6 +271,11 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
switch u := under(typ).(type) {
case *Interface:
tset := computeInterfaceTypeSet(check, pos, u)
+ // If typ is local, an error was already reported where typ is specified/defined.
+ if check != nil && check.isImportedConstraint(typ) && !check.allowVersion(check.pkg, 1, 18) {
+ check.errorf(pos, "embedding constraint interface %s requires go1.18 or later", typ)
+ continue
+ }
if tset.comparable {
ityp.tset.comparable = true
}
@@ -279,6 +284,10 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
}
terms = tset.terms
case *Union:
+ if check != nil && !check.allowVersion(check.pkg, 1, 18) {
+ check.errorf(pos, "embedding interface element %s requires go1.18 or later", u)
+ continue
+ }
tset := computeUnionTypeSet(check, pos, u)
if tset == &invalidTypeSet {
continue // ignore invalid unions
@@ -293,7 +302,7 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
continue
}
if check != nil && !check.allowVersion(check.pkg, 1, 18) {
- check.errorf(pos, "%s is not an interface", typ)
+ check.errorf(pos, "embedding non-interface type %s requires go1.18 or later", typ)
continue
}
terms = termlist{{false, typ}}
diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go
index 241c6d35fe..f3e415e4c7 100644
--- a/src/cmd/compile/internal/types2/typexpr.go
+++ b/src/cmd/compile/internal/types2/typexpr.go
@@ -38,14 +38,12 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *Named, wantType boo
}
return
case universeAny, universeComparable:
+ // complain if necessary but keep going
if !check.allowVersion(check.pkg, 1, 18) {
- check.errorf(e, "undeclared name: %s (requires version go1.18 or later)", e.Value)
- return
- }
- // If we allow "any" for general use, this if-statement can be removed (issue #33232).
- if obj == universeAny {
- check.error(e, "cannot use any outside constraint position")
- return
+ check.softErrorf(e, "undeclared name: %s (requires version go1.18 or later)", e.Value)
+ } else if obj == universeAny {
+ // If we allow "any" for general use, this if-statement can be removed (issue #33232).
+ check.softErrorf(e, "cannot use any outside constraint position")
}
}
check.recordUse(e, obj)
@@ -274,6 +272,9 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) {
}
case *syntax.IndexExpr:
+ if !check.allowVersion(check.pkg, 1, 18) {
+ check.softErrorf(e.Pos(), "type instantiation requires go1.18 or later")
+ }
return check.instantiatedType(e.X, unpackExpr(e.Index), def)
case *syntax.ParenExpr:
diff --git a/test/fixedbugs/issue10975.go b/test/fixedbugs/issue10975.go
index 876ea58ef9..a58ccce2db 100644
--- a/test/fixedbugs/issue10975.go
+++ b/test/fixedbugs/issue10975.go
@@ -10,7 +10,7 @@
package main
type I interface {
- int // ERROR "interface contains embedded non-interface|not an interface"
+ int // ERROR "interface contains embedded non-interface|embedding non-interface type"
}
func New() I {