---
doc/go1.18.html | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/doc/go1.18.html b/doc/go1.18.html
index 8617dd8fe1..25d85dd92a 100644
--- a/doc/go1.18.html
+++ b/doc/go1.18.html
@@ -333,15 +333,6 @@ Do not send CLs removing the interior tags from such phrases.
third-party tools that need to collect package source code.)
-go build -asan
-
-
- The go build command and related commands
- now support an -asan flag that enables interoperation
- with C (or C++) code compiled with the address sanitizer (C compiler
- option -fsanitize=address).
-
-
go mod tidy
@@ -369,6 +360,15 @@ Do not send CLs removing the interior tags from such phrases.
documentation.
+go build -asan
+
+
+ The go build command and related commands
+ now support an -asan flag that enables interoperation
+ with C (or C++) code compiled with the address sanitizer (C compiler
+ option -fsanitize=address).
+
+
go test
From 35170365c83085024e4855c14032599f5513d563 Mon Sep 17 00:00:00 2001
From: Martin Sucha
Date: Tue, 22 Feb 2022 21:51:04 +0100
Subject: [PATCH 14/44] net: document methods of Buffers
There is code in the wild that copies the Buffers slice,
but not the contents.
Let's document explicitly that it is not safe to do so.
Updates #45163
Change-Id: Id45e27b93037d4e9f2bfde2558e7869983b60bcf
Reviewed-on: https://go-review.googlesource.com/c/go/+/387434
Reviewed-by: Ian Lance Taylor
Run-TryBot: Ian Lance Taylor
TryBot-Result: Gopher Robot
Reviewed-by: Damien Neil
---
src/net/net.go | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/src/net/net.go b/src/net/net.go
index 77e54a9125..d91e743a01 100644
--- a/src/net/net.go
+++ b/src/net/net.go
@@ -703,6 +703,12 @@ var (
_ io.Reader = (*Buffers)(nil)
)
+// WriteTo writes contents of the buffers to w.
+//
+// WriteTo implements io.WriterTo for Buffers.
+//
+// WriteTo modifies the slice v as well as v[i] for 0 <= i < len(v),
+// but does not modify v[i][j] for any i, j.
func (v *Buffers) WriteTo(w io.Writer) (n int64, err error) {
if wv, ok := w.(buffersWriter); ok {
return wv.writeBuffers(v)
@@ -719,6 +725,12 @@ func (v *Buffers) WriteTo(w io.Writer) (n int64, err error) {
return n, nil
}
+// Read from the buffers.
+//
+// Read implements io.Reader for Buffers.
+//
+// Read modifies the slice v as well as v[i] for 0 <= i < len(v),
+// but does not modify v[i][j] for any i, j.
func (v *Buffers) Read(p []byte) (n int, err error) {
for len(p) > 0 && len(*v) > 0 {
n0 := copy(p, (*v)[0])
From d0c3b0116217a898f2e5d2d00cc5f0356ea5ad1e Mon Sep 17 00:00:00 2001
From: Michael Pratt
Date: Wed, 23 Feb 2022 12:23:41 -0500
Subject: [PATCH 15/44] doc/go1.18: drop misplaced period
Change-Id: Id29f352c8d2e61672f55294120058b1f585f7aeb
Reviewed-on: https://go-review.googlesource.com/c/go/+/387655
Trust: Michael Pratt
Run-TryBot: Michael Pratt
Reviewed-by: Jeremy Faller
TryBot-Result: Gopher Robot
---
doc/go1.18.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/go1.18.html b/doc/go1.18.html
index 25d85dd92a..8c786b94fc 100644
--- a/doc/go1.18.html
+++ b/doc/go1.18.html
@@ -1210,7 +1210,7 @@ For more details, see go.dev/issue/44505
- SysProcAttr.Pdeathsig.
+ SysProcAttr.Pdeathsig
is now supported in FreeBSD.
From e534907f65f5a3eda47a069ea0aab33306c1d616 Mon Sep 17 00:00:00 2001
From: Robert Findley
Date: Fri, 18 Feb 2022 09:19:47 -0500
Subject: [PATCH 16/44] go/types: delete unnecessary slice construction
CL 374294 made our check for incorrect type parameters constraints
eager, but failed to remove the construction of the bounds slice, which
was no longer used.
Change-Id: Ib8778fba947ef8a8414803e95d72c49b8f75c204
Reviewed-on: https://go-review.googlesource.com/c/go/+/386717
Trust: Robert Findley
Run-TryBot: Robert Findley
TryBot-Result: Gopher Robot
Reviewed-by: Robert Griesemer
---
src/cmd/compile/internal/types2/decl.go | 2 --
src/go/types/decl.go | 2 --
2 files changed, 4 deletions(-)
diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go
index 0e8f5085ba..579fa55e59 100644
--- a/src/cmd/compile/internal/types2/decl.go
+++ b/src/cmd/compile/internal/types2/decl.go
@@ -569,7 +569,6 @@ func (check *Checker) collectTypeParams(dst **TypeParamList, list []*syntax.Fiel
// Keep track of bounds for later validation.
var bound Type
- var bounds []Type
for i, f := range list {
// Optimization: Re-use the previous type bound if it hasn't changed.
// This also preserves the grouped output of type parameter lists
@@ -584,7 +583,6 @@ func (check *Checker) collectTypeParams(dst **TypeParamList, list []*syntax.Fiel
check.error(f.Type, "cannot use a type parameter as constraint")
bound = Typ[Invalid]
}
- bounds = append(bounds, bound)
}
tparams[i].bound = bound
}
diff --git a/src/go/types/decl.go b/src/go/types/decl.go
index cd6f709a56..93a37d76ce 100644
--- a/src/go/types/decl.go
+++ b/src/go/types/decl.go
@@ -624,7 +624,6 @@ func (check *Checker) collectTypeParams(dst **TypeParamList, list *ast.FieldList
}()
index := 0
- var bounds []Type
for _, f := range list.List {
var bound Type
// NOTE: we may be able to assert that f.Type != nil here, but this is not
@@ -642,7 +641,6 @@ func (check *Checker) collectTypeParams(dst **TypeParamList, list *ast.FieldList
} else {
bound = Typ[Invalid]
}
- bounds = append(bounds, bound)
for i := range f.Names {
tparams[index+i].bound = bound
}
From 163da6feb525a98dab5c1f01d81b2c705ead51ea Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Sun, 20 Feb 2022 12:58:21 -0800
Subject: [PATCH 17/44] go/types, types2: add "dynamic" flag to comparable
predicate
A type implements a comparable interface only if the type
is statically known to be comparable. Specifically, a type
cannot contain (component) interfaces that are not statically
known to be comparable.
This CL adds a flag "dynamic" to the comparable predicate to
control whether interfaces are always (dynamically) comparable.
Set the flag to true when testing for (traditional) Go comparability;
set the flag to false when testing whether a type implements the
comparable interface.
Fixes #51257.
Change-Id: If22bc047ee59337deb2e7844b8f488d67e5c5530
Reviewed-on: https://go-review.googlesource.com/c/go/+/387055
Trust: Robert Griesemer
Run-TryBot: Robert Griesemer
TryBot-Result: Gopher Robot
Reviewed-by: Robert Findley
---
src/cmd/compile/internal/types2/expr.go | 2 +-
.../compile/internal/types2/instantiate.go | 2 +-
src/cmd/compile/internal/types2/predicates.go | 11 +++--
.../types2/testdata/fixedbugs/issue51257.go2 | 46 +++++++++++++++++++
src/cmd/compile/internal/types2/typeset.go | 2 +-
src/go/types/expr.go | 2 +-
src/go/types/instantiate.go | 2 +-
src/go/types/predicates.go | 11 +++--
.../types/testdata/fixedbugs/issue51257.go2 | 46 +++++++++++++++++++
src/go/types/typeset.go | 2 +-
10 files changed, 110 insertions(+), 16 deletions(-)
create mode 100644 src/cmd/compile/internal/types2/testdata/fixedbugs/issue51257.go2
create mode 100644 src/go/types/testdata/fixedbugs/issue51257.go2
diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go
index 02ece21e67..ac5630dbbb 100644
--- a/src/cmd/compile/internal/types2/expr.go
+++ b/src/cmd/compile/internal/types2/expr.go
@@ -899,7 +899,7 @@ func (check *Checker) incomparableCause(typ Type) string {
}
// see if we can extract a more specific error
var cause string
- comparable(typ, nil, func(format string, args ...interface{}) {
+ comparable(typ, true, nil, func(format string, args ...interface{}) {
cause = check.sprintf(format, args...)
})
return cause
diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go
index f54938b6e1..c2653a3834 100644
--- a/src/cmd/compile/internal/types2/instantiate.go
+++ b/src/cmd/compile/internal/types2/instantiate.go
@@ -204,7 +204,7 @@ func (check *Checker) implements(V, T Type) error {
// If T is comparable, V must be comparable.
// Remember as a pending error and report only if we don't have a more specific error.
var pending error
- if Ti.IsComparable() && ((Vi != nil && !Vi.IsComparable()) || (Vi == nil && !Comparable(V))) {
+ if Ti.IsComparable() && !comparable(V, false, nil, nil) {
pending = errorf("%s does not implement comparable", V)
}
diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go
index 0e46333af7..ba259341f6 100644
--- a/src/cmd/compile/internal/types2/predicates.go
+++ b/src/cmd/compile/internal/types2/predicates.go
@@ -102,11 +102,12 @@ func isGeneric(t Type) bool {
// Comparable reports whether values of type T are comparable.
func Comparable(T Type) bool {
- return comparable(T, nil, nil)
+ return comparable(T, true, nil, nil)
}
+// If dynamic is set, non-type parameter interfaces are always comparable.
// If reportf != nil, it may be used to report why T is not comparable.
-func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{})) bool {
+func comparable(T Type, dynamic bool, seen map[Type]bool, reportf func(string, ...interface{})) bool {
if seen[T] {
return true
}
@@ -124,7 +125,7 @@ func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{})
return true
case *Struct:
for _, f := range t.fields {
- if !comparable(f.typ, seen, nil) {
+ if !comparable(f.typ, dynamic, seen, nil) {
if reportf != nil {
reportf("struct containing %s cannot be compared", f.typ)
}
@@ -133,7 +134,7 @@ func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{})
}
return true
case *Array:
- if !comparable(t.elem, seen, nil) {
+ if !comparable(t.elem, dynamic, seen, nil) {
if reportf != nil {
reportf("%s cannot be compared", t)
}
@@ -141,7 +142,7 @@ func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{})
}
return true
case *Interface:
- return !isTypeParam(T) || t.typeSet().IsComparable(seen)
+ return dynamic && !isTypeParam(T) || t.typeSet().IsComparable(seen)
}
return false
}
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51257.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51257.go2
new file mode 100644
index 0000000000..bc4208e6ee
--- /dev/null
+++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51257.go2
@@ -0,0 +1,46 @@
+// Copyright 2022 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.
+
+package p
+
+func f[_ comparable]() {}
+
+type S1 struct{ x int }
+type S2 struct{ x any }
+type S3 struct{ x [10]interface{ m() } }
+
+func _[P1 comparable, P2 S2]() {
+ _ = f[S1]
+ _ = f[S2 /* ERROR S2 does not implement comparable */ ]
+ _ = f[S3 /* ERROR S3 does not implement comparable */ ]
+
+ type L1 struct { x P1 }
+ type L2 struct { x P2 }
+ _ = f[L1]
+ _ = f[L2 /* ERROR L2 does not implement comparable */ ]
+}
+
+
+// example from issue
+
+type Set[T comparable] map[T]struct{}
+
+func NewSetFromSlice[T comparable](items []T) *Set[T] {
+ s := Set[T]{}
+
+ for _, item := range items {
+ s[item] = struct{}{}
+ }
+
+ return &s
+}
+
+type T struct{ x any }
+
+func main() {
+ NewSetFromSlice( /* ERROR T does not implement comparable */ []T{
+ {"foo"},
+ {5},
+ })
+}
diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go
index fff348bcf4..2c3e826a3f 100644
--- a/src/cmd/compile/internal/types2/typeset.go
+++ b/src/cmd/compile/internal/types2/typeset.go
@@ -39,7 +39,7 @@ func (s *_TypeSet) IsComparable(seen map[Type]bool) bool {
return s.comparable
}
return s.is(func(t *term) bool {
- return t != nil && comparable(t.typ, seen, nil)
+ return t != nil && comparable(t.typ, false, seen, nil)
})
}
diff --git a/src/go/types/expr.go b/src/go/types/expr.go
index 8747838c4b..e8038dd178 100644
--- a/src/go/types/expr.go
+++ b/src/go/types/expr.go
@@ -859,7 +859,7 @@ func (check *Checker) incomparableCause(typ Type) string {
}
// see if we can extract a more specific error
var cause string
- comparable(typ, nil, func(format string, args ...interface{}) {
+ comparable(typ, true, nil, func(format string, args ...interface{}) {
cause = check.sprintf(format, args...)
})
return cause
diff --git a/src/go/types/instantiate.go b/src/go/types/instantiate.go
index 4aeaeb7f11..4b8e3d4661 100644
--- a/src/go/types/instantiate.go
+++ b/src/go/types/instantiate.go
@@ -204,7 +204,7 @@ func (check *Checker) implements(V, T Type) error {
// If T is comparable, V must be comparable.
// Remember as a pending error and report only if we don't have a more specific error.
var pending error
- if Ti.IsComparable() && ((Vi != nil && !Vi.IsComparable()) || (Vi == nil && !Comparable(V))) {
+ if Ti.IsComparable() && !comparable(V, false, nil, nil) {
pending = errorf("%s does not implement comparable", V)
}
diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go
index 14e99bf426..0360f27ee6 100644
--- a/src/go/types/predicates.go
+++ b/src/go/types/predicates.go
@@ -104,11 +104,12 @@ func isGeneric(t Type) bool {
// Comparable reports whether values of type T are comparable.
func Comparable(T Type) bool {
- return comparable(T, nil, nil)
+ return comparable(T, true, nil, nil)
}
+// If dynamic is set, non-type parameter interfaces are always comparable.
// If reportf != nil, it may be used to report why T is not comparable.
-func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{})) bool {
+func comparable(T Type, dynamic bool, seen map[Type]bool, reportf func(string, ...interface{})) bool {
if seen[T] {
return true
}
@@ -126,7 +127,7 @@ func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{})
return true
case *Struct:
for _, f := range t.fields {
- if !comparable(f.typ, seen, nil) {
+ if !comparable(f.typ, dynamic, seen, nil) {
if reportf != nil {
reportf("struct containing %s cannot be compared", f.typ)
}
@@ -135,7 +136,7 @@ func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{})
}
return true
case *Array:
- if !comparable(t.elem, seen, nil) {
+ if !comparable(t.elem, dynamic, seen, nil) {
if reportf != nil {
reportf("%s cannot be compared", t)
}
@@ -143,7 +144,7 @@ func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{})
}
return true
case *Interface:
- return !isTypeParam(T) || t.typeSet().IsComparable(seen)
+ return dynamic && !isTypeParam(T) || t.typeSet().IsComparable(seen)
}
return false
}
diff --git a/src/go/types/testdata/fixedbugs/issue51257.go2 b/src/go/types/testdata/fixedbugs/issue51257.go2
new file mode 100644
index 0000000000..8a3eb3278d
--- /dev/null
+++ b/src/go/types/testdata/fixedbugs/issue51257.go2
@@ -0,0 +1,46 @@
+// Copyright 2022 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.
+
+package p
+
+func f[_ comparable]() {}
+
+type S1 struct{ x int }
+type S2 struct{ x any }
+type S3 struct{ x [10]interface{ m() } }
+
+func _[P1 comparable, P2 S2]() {
+ _ = f[S1]
+ _ = f[S2 /* ERROR S2 does not implement comparable */ ]
+ _ = f[S3 /* ERROR S3 does not implement comparable */ ]
+
+ type L1 struct { x P1 }
+ type L2 struct { x P2 }
+ _ = f[L1]
+ _ = f[L2 /* ERROR L2 does not implement comparable */ ]
+}
+
+
+// example from issue
+
+type Set[T comparable] map[T]struct{}
+
+func NewSetFromSlice[T comparable](items []T) *Set[T] {
+ s := Set[T]{}
+
+ for _, item := range items {
+ s[item] = struct{}{}
+ }
+
+ return &s
+}
+
+type T struct{ x any }
+
+func main() {
+ NewSetFromSlice /* ERROR T does not implement comparable */ ([]T{
+ {"foo"},
+ {5},
+ })
+}
diff --git a/src/go/types/typeset.go b/src/go/types/typeset.go
index e1f73015b9..3bc9474660 100644
--- a/src/go/types/typeset.go
+++ b/src/go/types/typeset.go
@@ -37,7 +37,7 @@ func (s *_TypeSet) IsComparable(seen map[Type]bool) bool {
return s.comparable
}
return s.is(func(t *term) bool {
- return t != nil && comparable(t.typ, seen, nil)
+ return t != nil && comparable(t.typ, false, seen, nil)
})
}
From e94f7df957b6cfbdfbed7092fd05628452c5e018 Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Tue, 22 Feb 2022 13:06:52 -0800
Subject: [PATCH 18/44] go/types, types2: generalize cleanup phase after type
checking
Use a cleanup method and simple registration mechanism
for types that need some final processing before the end
of type checking.
Use cleanup mechanism instead of expandDefTypes mechanism
for *Named types. There is no change in functionality here.
Use cleanup mechanism also for TypeParam and Interface types
to ensure that their check fields are nilled out at the end.
Introduce a simple constructor method for Interface types
to ensure that the cleanup method is always registered.
In go/types, add tracing code to Checker.checkFiles to match
types2.
Minor comment adjustments.
Fixes #51316.
Fixes #51326.
Change-Id: I7b2bd79cc419717982f3c918645af623c0e80d5e
Reviewed-on: https://go-review.googlesource.com/c/go/+/387417
Trust: Robert Griesemer
Run-TryBot: Robert Griesemer
Reviewed-by: Robert Findley
TryBot-Result: Gopher Robot
---
src/cmd/compile/internal/types2/check.go | 45 +++++++--------
src/cmd/compile/internal/types2/interface.go | 28 ++++++----
src/cmd/compile/internal/types2/named.go | 32 +++++++++--
src/cmd/compile/internal/types2/subst.go | 5 +-
src/cmd/compile/internal/types2/typeparam.go | 12 ++--
src/cmd/compile/internal/types2/typexpr.go | 2 +-
src/go/types/check.go | 58 ++++++++++++--------
src/go/types/interface.go | 28 ++++++----
src/go/types/named.go | 32 +++++++++--
src/go/types/subst.go | 5 +-
src/go/types/typeparam.go | 12 ++--
src/go/types/typexpr.go | 2 +-
12 files changed, 168 insertions(+), 93 deletions(-)
diff --git a/src/cmd/compile/internal/types2/check.go b/src/cmd/compile/internal/types2/check.go
index 535de0256c..4ec6a7b4fd 100644
--- a/src/cmd/compile/internal/types2/check.go
+++ b/src/cmd/compile/internal/types2/check.go
@@ -126,7 +126,7 @@ type Checker struct {
untyped map[syntax.Expr]exprInfo // map of expressions without final type
delayed []action // stack of delayed action segments; segments are processed in FIFO order
objPath []Object // path of object dependencies during type inference (for cycle reporting)
- defTypes []*Named // defined types created during type checking, for final validation.
+ cleaners []cleaner // list of types that may need a final cleanup at the end of type-checking
// environment within which the current object is type-checked (valid only
// for the duration of type-checking a specific object)
@@ -205,6 +205,16 @@ func (check *Checker) pop() Object {
return obj
}
+type cleaner interface {
+ cleanup()
+}
+
+// needsCleanup records objects/types that implement the cleanup method
+// which will be called at the end of type-checking.
+func (check *Checker) needsCleanup(c cleaner) {
+ check.cleaners = append(check.cleaners, c)
+}
+
// NewChecker returns a new Checker instance for a given package.
// Package files may be added incrementally via checker.Files.
func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
@@ -247,6 +257,8 @@ func (check *Checker) initFiles(files []*syntax.File) {
check.methods = nil
check.untyped = nil
check.delayed = nil
+ check.objPath = nil
+ check.cleaners = nil
// determine package name and collect valid files
pkg := check.pkg
@@ -315,8 +327,8 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) {
print("== processDelayed ==")
check.processDelayed(0) // incl. all functions
- print("== expandDefTypes ==")
- check.expandDefTypes()
+ print("== cleanup ==")
+ check.cleanup()
print("== initOrder ==")
check.initOrder()
@@ -344,7 +356,6 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) {
check.recvTParamMap = nil
check.brokenAliases = nil
check.unionTypeSets = nil
- check.defTypes = nil
check.ctxt = nil
// TODO(gri) There's more memory we should release at this point.
@@ -372,27 +383,13 @@ func (check *Checker) processDelayed(top int) {
check.delayed = check.delayed[:top]
}
-func (check *Checker) expandDefTypes() {
- // Ensure that every defined type created in the course of type-checking has
- // either non-*Named underlying, or is unresolved.
- //
- // This guarantees that we don't leak any types whose underlying is *Named,
- // because any unresolved instances will lazily compute their underlying by
- // substituting in the underlying of their origin. The origin must have
- // either been imported or type-checked and expanded here, and in either case
- // its underlying will be fully expanded.
- for i := 0; i < len(check.defTypes); i++ {
- n := check.defTypes[i]
- switch n.underlying.(type) {
- case nil:
- if n.resolver == nil {
- panic("nil underlying")
- }
- case *Named:
- n.under() // n.under may add entries to check.defTypes
- }
- n.check = nil
+// cleanup runs cleanup for all collected cleaners.
+func (check *Checker) cleanup() {
+ // Don't use a range clause since Named.cleanup may add more cleaners.
+ for i := 0; i < len(check.cleaners); i++ {
+ check.cleaners[i].cleanup()
}
+ check.cleaners = nil
}
func (check *Checker) record(x *operand) {
diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go
index ca5140d092..75597abaf9 100644
--- a/src/cmd/compile/internal/types2/interface.go
+++ b/src/cmd/compile/internal/types2/interface.go
@@ -37,7 +37,7 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface {
}
// set method receivers if necessary
- typ := new(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)
@@ -54,6 +54,15 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface {
return typ
}
+// check may be nil
+func (check *Checker) newInterface() *Interface {
+ typ := &Interface{check: check}
+ if check != nil {
+ check.needsCleanup(typ)
+ }
+ return typ
+}
+
// MarkImplicit marks the interface t as implicit, meaning this interface
// corresponds to a constraint literal such as ~T or A|B without explicit
// interface embedding. MarkImplicit should be called before any concurrent use
@@ -100,6 +109,11 @@ func (t *Interface) String() string { return TypeString(t, nil) }
// ----------------------------------------------------------------------------
// Implementation
+func (t *Interface) cleanup() {
+ t.check = nil
+ t.embedPos = nil
+}
+
func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType, def *Named) {
addEmbedded := func(pos syntax.Pos, typ Type) {
ityp.embeddeds = append(ityp.embeddeds, typ)
@@ -162,16 +176,10 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType
// (don't sort embeddeds: they must correspond to *embedPos entries)
sortMethods(ityp.methods)
- // Compute type set with a non-nil *Checker as soon as possible
- // to report any errors. Subsequent uses of type sets will use
- // this computed type set and won't need to pass in a *Checker.
- //
- // Pin the checker to the interface type in the interim, in case the type set
- // must be used before delayed funcs are processed (see issue #48234).
- // TODO(rfindley): clean up use of *Checker with computeInterfaceTypeSet
- ityp.check = check
+ // Compute type set as soon as possible to report any errors.
+ // Subsequent uses of type sets will use this computed type
+ // set and won't need to pass in a *Checker.
check.later(func() {
computeInterfaceTypeSet(check, iface.Pos(), ityp)
- ityp.check = nil
}).describef(iface, "compute type set for %s", ityp)
}
diff --git a/src/cmd/compile/internal/types2/named.go b/src/cmd/compile/internal/types2/named.go
index bb522e8fe3..5c6a1cf5d8 100644
--- a/src/cmd/compile/internal/types2/named.go
+++ b/src/cmd/compile/internal/types2/named.go
@@ -72,11 +72,31 @@ func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tpar
}
// Ensure that typ is always expanded and sanity-checked.
if check != nil {
- check.defTypes = append(check.defTypes, typ)
+ check.needsCleanup(typ)
}
return typ
}
+func (t *Named) cleanup() {
+ // Ensure that every defined type created in the course of type-checking has
+ // either non-*Named underlying, or is unresolved.
+ //
+ // This guarantees that we don't leak any types whose underlying is *Named,
+ // because any unresolved instances will lazily compute their underlying by
+ // substituting in the underlying of their origin. The origin must have
+ // either been imported or type-checked and expanded here, and in either case
+ // its underlying will be fully expanded.
+ switch t.underlying.(type) {
+ case nil:
+ if t.resolver == nil {
+ panic("nil underlying")
+ }
+ case *Named:
+ t.under() // t.under may add entries to check.cleaners
+ }
+ t.check = nil
+}
+
// Obj returns the type name for the declaration defining the named type t. For
// instantiated types, this is the type name of the base type.
func (t *Named) Obj() *TypeName { return t.orig.obj } // for non-instances this is the same as t.obj
@@ -360,11 +380,11 @@ func expandNamed(ctxt *Context, n *Named, instPos syntax.Pos) (tparams *TypePara
// that it wasn't substituted. In this case we need to create a new
// *Interface before modifying receivers.
if iface == n.orig.underlying {
- iface = &Interface{
- embeddeds: iface.embeddeds,
- complete: iface.complete,
- implicit: iface.implicit, // should be false but be conservative
- }
+ old := iface
+ iface = check.newInterface()
+ iface.embeddeds = old.embeddeds
+ iface.complete = old.complete
+ iface.implicit = old.implicit // should be false but be conservative
underlying = iface
}
iface.methods = methods
diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go
index 44a59f55fd..037f04797b 100644
--- a/src/cmd/compile/internal/types2/subst.go
+++ b/src/cmd/compile/internal/types2/subst.go
@@ -160,7 +160,10 @@ func (subst *subster) typ(typ Type) Type {
methods, mcopied := subst.funcList(t.methods)
embeddeds, ecopied := subst.typeList(t.embeddeds)
if mcopied || ecopied {
- iface := &Interface{embeddeds: embeddeds, implicit: t.implicit, complete: t.complete}
+ iface := subst.check.newInterface()
+ iface.embeddeds = embeddeds
+ iface.implicit = t.implicit
+ iface.complete = t.complete
// If we've changed the interface type, we may need to replace its
// receiver if the receiver type is the original interface. Receivers of
// *Named type are replaced during named type expansion.
diff --git a/src/cmd/compile/internal/types2/typeparam.go b/src/cmd/compile/internal/types2/typeparam.go
index 971fdaec73..57613706f7 100644
--- a/src/cmd/compile/internal/types2/typeparam.go
+++ b/src/cmd/compile/internal/types2/typeparam.go
@@ -36,6 +36,7 @@ func NewTypeParam(obj *TypeName, constraint Type) *TypeParam {
return (*Checker)(nil).newTypeParam(obj, constraint)
}
+// check may be nil
func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam {
// Always increment lastID, even if it is not used.
id := nextID()
@@ -50,9 +51,7 @@ func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam {
// iface may mutate typ.bound, so we must ensure that iface() is called
// at least once before the resulting TypeParam escapes.
if check != nil {
- check.later(func() {
- typ.iface()
- })
+ check.needsCleanup(typ)
} else if constraint != nil {
typ.iface()
}
@@ -93,9 +92,12 @@ func (t *TypeParam) String() string { return TypeString(t, nil) }
// ----------------------------------------------------------------------------
// Implementation
+func (t *TypeParam) cleanup() {
+ t.iface()
+ t.check = nil
+}
+
// iface returns the constraint interface of t.
-// TODO(gri) If we make tparamIsIface the default, this should be renamed to under
-// (similar to Named.under).
func (t *TypeParam) iface() *Interface {
bound := t.bound
diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go
index 149bd5b0b3..2847aa76c0 100644
--- a/src/cmd/compile/internal/types2/typexpr.go
+++ b/src/cmd/compile/internal/types2/typexpr.go
@@ -342,7 +342,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) {
return typ
case *syntax.InterfaceType:
- typ := new(Interface)
+ typ := check.newInterface()
def.setUnderlying(typ)
if def != nil {
typ.obj = def.obj
diff --git a/src/go/types/check.go b/src/go/types/check.go
index 6e1da04b9f..23136377c8 100644
--- a/src/go/types/check.go
+++ b/src/go/types/check.go
@@ -133,7 +133,7 @@ type Checker struct {
untyped map[ast.Expr]exprInfo // map of expressions without final type
delayed []action // stack of delayed action segments; segments are processed in FIFO order
objPath []Object // path of object dependencies during type inference (for cycle reporting)
- defTypes []*Named // defined types created during type checking, for final validation.
+ cleaners []cleaner // list of types that may need a final cleanup at the end of type-checking
// environment within which the current object is type-checked (valid only
// for the duration of type-checking a specific object)
@@ -212,6 +212,16 @@ func (check *Checker) pop() Object {
return obj
}
+type cleaner interface {
+ cleanup()
+}
+
+// needsCleanup records objects/types that implement the cleanup method
+// which will be called at the end of type-checking.
+func (check *Checker) needsCleanup(c cleaner) {
+ check.cleaners = append(check.cleaners, c)
+}
+
// NewChecker returns a new Checker instance for a given package.
// Package files may be added incrementally via checker.Files.
func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Checker {
@@ -255,6 +265,8 @@ func (check *Checker) initFiles(files []*ast.File) {
check.methods = nil
check.untyped = nil
check.delayed = nil
+ check.objPath = nil
+ check.cleaners = nil
// determine package name and collect valid files
pkg := check.pkg
@@ -304,22 +316,37 @@ func (check *Checker) checkFiles(files []*ast.File) (err error) {
defer check.handleBailout(&err)
+ print := func(msg string) {
+ if trace {
+ fmt.Println()
+ fmt.Println(msg)
+ }
+ }
+
+ print("== initFiles ==")
check.initFiles(files)
+ print("== collectObjects ==")
check.collectObjects()
+ print("== packageObjects ==")
check.packageObjects()
+ print("== processDelayed ==")
check.processDelayed(0) // incl. all functions
- check.expandDefTypes()
+ print("== cleanup ==")
+ check.cleanup()
+ print("== initOrder ==")
check.initOrder()
if !check.conf.DisableUnusedImportCheck {
+ print("== unusedImports ==")
check.unusedImports()
}
+ print("== recordUntyped ==")
check.recordUntyped()
if check.firstErr == nil {
@@ -337,7 +364,6 @@ func (check *Checker) checkFiles(files []*ast.File) (err error) {
check.recvTParamMap = nil
check.brokenAliases = nil
check.unionTypeSets = nil
- check.defTypes = nil
check.ctxt = nil
// TODO(rFindley) There's more memory we should release at this point.
@@ -365,27 +391,13 @@ func (check *Checker) processDelayed(top int) {
check.delayed = check.delayed[:top]
}
-func (check *Checker) expandDefTypes() {
- // Ensure that every defined type created in the course of type-checking has
- // either non-*Named underlying, or is unresolved.
- //
- // This guarantees that we don't leak any types whose underlying is *Named,
- // because any unresolved instances will lazily compute their underlying by
- // substituting in the underlying of their origin. The origin must have
- // either been imported or type-checked and expanded here, and in either case
- // its underlying will be fully expanded.
- for i := 0; i < len(check.defTypes); i++ {
- n := check.defTypes[i]
- switch n.underlying.(type) {
- case nil:
- if n.resolver == nil {
- panic("nil underlying")
- }
- case *Named:
- n.under() // n.under may add entries to check.defTypes
- }
- n.check = nil
+// cleanup runs cleanup for all collected cleaners.
+func (check *Checker) cleanup() {
+ // Don't use a range clause since Named.cleanup may add more cleaners.
+ for i := 0; i < len(check.cleaners); i++ {
+ check.cleaners[i].cleanup()
}
+ check.cleaners = nil
}
func (check *Checker) record(x *operand) {
diff --git a/src/go/types/interface.go b/src/go/types/interface.go
index b9d4660eb4..3db3580a91 100644
--- a/src/go/types/interface.go
+++ b/src/go/types/interface.go
@@ -56,7 +56,7 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface {
}
// set method receivers if necessary
- typ := new(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)
@@ -73,6 +73,15 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface {
return typ
}
+// check may be nil
+func (check *Checker) newInterface() *Interface {
+ typ := &Interface{check: check}
+ if check != nil {
+ check.needsCleanup(typ)
+ }
+ return typ
+}
+
// MarkImplicit marks the interface t as implicit, meaning this interface
// corresponds to a constraint literal such as ~T or A|B without explicit
// interface embedding. MarkImplicit should be called before any concurrent use
@@ -141,6 +150,11 @@ func (t *Interface) String() string { return TypeString(t, nil) }
// ----------------------------------------------------------------------------
// Implementation
+func (t *Interface) cleanup() {
+ t.check = nil
+ t.embedPos = nil
+}
+
func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, def *Named) {
addEmbedded := func(pos token.Pos, typ Type) {
ityp.embeddeds = append(ityp.embeddeds, typ)
@@ -210,16 +224,10 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
sortMethods(ityp.methods)
// (don't sort embeddeds: they must correspond to *embedPos entries)
- // Compute type set with a non-nil *Checker as soon as possible
- // to report any errors. Subsequent uses of type sets will use
- // this computed type set and won't need to pass in a *Checker.
- //
- // Pin the checker to the interface type in the interim, in case the type set
- // must be used before delayed funcs are processed (see issue #48234).
- // TODO(rfindley): clean up use of *Checker with computeInterfaceTypeSet
- ityp.check = check
+ // Compute type set as soon as possible to report any errors.
+ // Subsequent uses of type sets will use this computed type
+ // set and won't need to pass in a *Checker.
check.later(func() {
computeInterfaceTypeSet(check, iface.Pos(), ityp)
- ityp.check = nil
}).describef(iface, "compute type set for %s", ityp)
}
diff --git a/src/go/types/named.go b/src/go/types/named.go
index 5e84c39776..5b84e0653b 100644
--- a/src/go/types/named.go
+++ b/src/go/types/named.go
@@ -72,11 +72,31 @@ func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tpar
}
// Ensure that typ is always expanded and sanity-checked.
if check != nil {
- check.defTypes = append(check.defTypes, typ)
+ check.needsCleanup(typ)
}
return typ
}
+func (t *Named) cleanup() {
+ // Ensure that every defined type created in the course of type-checking has
+ // either non-*Named underlying, or is unresolved.
+ //
+ // This guarantees that we don't leak any types whose underlying is *Named,
+ // because any unresolved instances will lazily compute their underlying by
+ // substituting in the underlying of their origin. The origin must have
+ // either been imported or type-checked and expanded here, and in either case
+ // its underlying will be fully expanded.
+ switch t.underlying.(type) {
+ case nil:
+ if t.resolver == nil {
+ panic("nil underlying")
+ }
+ case *Named:
+ t.under() // t.under may add entries to check.cleaners
+ }
+ t.check = nil
+}
+
// Obj returns the type name for the declaration defining the named type t. For
// instantiated types, this is the type name of the base type.
func (t *Named) Obj() *TypeName {
@@ -362,11 +382,11 @@ func expandNamed(ctxt *Context, n *Named, instPos token.Pos) (tparams *TypeParam
// that it wasn't substituted. In this case we need to create a new
// *Interface before modifying receivers.
if iface == n.orig.underlying {
- iface = &Interface{
- embeddeds: iface.embeddeds,
- complete: iface.complete,
- implicit: iface.implicit, // should be false but be conservative
- }
+ old := iface
+ iface = check.newInterface()
+ iface.embeddeds = old.embeddeds
+ iface.complete = old.complete
+ iface.implicit = old.implicit // should be false but be conservative
underlying = iface
}
iface.methods = methods
diff --git a/src/go/types/subst.go b/src/go/types/subst.go
index 53247a3585..4b4a0f4ad6 100644
--- a/src/go/types/subst.go
+++ b/src/go/types/subst.go
@@ -160,7 +160,10 @@ func (subst *subster) typ(typ Type) Type {
methods, mcopied := subst.funcList(t.methods)
embeddeds, ecopied := subst.typeList(t.embeddeds)
if mcopied || ecopied {
- iface := &Interface{embeddeds: embeddeds, implicit: t.implicit, complete: t.complete}
+ iface := subst.check.newInterface()
+ iface.embeddeds = embeddeds
+ iface.implicit = t.implicit
+ iface.complete = t.complete
// If we've changed the interface type, we may need to replace its
// receiver if the receiver type is the original interface. Receivers of
// *Named type are replaced during named type expansion.
diff --git a/src/go/types/typeparam.go b/src/go/types/typeparam.go
index 71e6861b87..5505372cff 100644
--- a/src/go/types/typeparam.go
+++ b/src/go/types/typeparam.go
@@ -35,6 +35,7 @@ func NewTypeParam(obj *TypeName, constraint Type) *TypeParam {
return (*Checker)(nil).newTypeParam(obj, constraint)
}
+// check may be nil
func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam {
// Always increment lastID, even if it is not used.
id := nextID()
@@ -49,9 +50,7 @@ func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam {
// iface may mutate typ.bound, so we must ensure that iface() is called
// at least once before the resulting TypeParam escapes.
if check != nil {
- check.later(func() {
- typ.iface()
- })
+ check.needsCleanup(typ)
} else if constraint != nil {
typ.iface()
}
@@ -95,9 +94,12 @@ func (t *TypeParam) String() string { return TypeString(t, nil) }
// ----------------------------------------------------------------------------
// Implementation
+func (t *TypeParam) cleanup() {
+ t.iface()
+ t.check = nil
+}
+
// iface returns the constraint interface of t.
-// TODO(gri) If we make tparamIsIface the default, this should be renamed to under
-// (similar to Named.under).
func (t *TypeParam) iface() *Interface {
bound := t.bound
diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go
index db6a904aaa..724c40963f 100644
--- a/src/go/types/typexpr.go
+++ b/src/go/types/typexpr.go
@@ -323,7 +323,7 @@ func (check *Checker) typInternal(e0 ast.Expr, def *Named) (T Type) {
return typ
case *ast.InterfaceType:
- typ := new(Interface)
+ typ := check.newInterface()
def.setUnderlying(typ)
if def != nil {
typ.obj = def.obj
From 78e99761fc4bf1f5370f912b8a4594789c2f09f8 Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Wed, 23 Feb 2022 14:26:07 -0800
Subject: [PATCH 19/44] go/types, types2: don't crash if comp. literal element
type has no core type
Instead, report a suitable error.
Fixes #51335.
Change-Id: Ifce90cb7487b1e99c6b4221c0d43bacc0c39dca8
Reviewed-on: https://go-review.googlesource.com/c/go/+/387676
Trust: Robert Griesemer
Run-TryBot: Robert Griesemer
TryBot-Result: Gopher Robot
Reviewed-by: Robert Findley
---
src/cmd/compile/internal/types2/expr.go | 4 ++++
.../types2/testdata/fixedbugs/issue51335.go2 | 16 ++++++++++++++++
src/go/types/expr.go | 4 ++++
src/go/types/testdata/fixedbugs/issue51335.go2 | 16 ++++++++++++++++
4 files changed, 40 insertions(+)
create mode 100644 src/cmd/compile/internal/types2/testdata/fixedbugs/issue51335.go2
create mode 100644 src/go/types/testdata/fixedbugs/issue51335.go2
diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go
index ac5630dbbb..c587c40f80 100644
--- a/src/cmd/compile/internal/types2/expr.go
+++ b/src/cmd/compile/internal/types2/expr.go
@@ -1360,6 +1360,10 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
// no composite literal type present - use hint (element type of enclosing type)
typ = hint
base, _ = deref(coreType(typ)) // *T implies &T{}
+ if base == nil {
+ check.errorf(e, "invalid composite literal element type %s: no core type", typ)
+ goto Error
+ }
default:
// TODO(gri) provide better error messages depending on context
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51335.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51335.go2
new file mode 100644
index 0000000000..0b5a1af082
--- /dev/null
+++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51335.go2
@@ -0,0 +1,16 @@
+// Copyright 2022 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.
+
+package p
+
+type S1 struct{}
+type S2 struct{}
+
+func _[P *S1|*S2]() {
+ _= []P{{ /* ERROR invalid composite literal element type P: no core type */ }}
+}
+
+func _[P *S1|S1]() {
+ _= []P{{ /* ERROR invalid composite literal element type P: no core type */ }}
+}
diff --git a/src/go/types/expr.go b/src/go/types/expr.go
index e8038dd178..9241c243f2 100644
--- a/src/go/types/expr.go
+++ b/src/go/types/expr.go
@@ -1339,6 +1339,10 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
// no composite literal type present - use hint (element type of enclosing type)
typ = hint
base, _ = deref(coreType(typ)) // *T implies &T{}
+ if base == nil {
+ check.errorf(e, _InvalidLit, "invalid composite literal element type %s: no core type", typ)
+ goto Error
+ }
default:
// TODO(gri) provide better error messages depending on context
diff --git a/src/go/types/testdata/fixedbugs/issue51335.go2 b/src/go/types/testdata/fixedbugs/issue51335.go2
new file mode 100644
index 0000000000..0b5a1af082
--- /dev/null
+++ b/src/go/types/testdata/fixedbugs/issue51335.go2
@@ -0,0 +1,16 @@
+// Copyright 2022 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.
+
+package p
+
+type S1 struct{}
+type S2 struct{}
+
+func _[P *S1|*S2]() {
+ _= []P{{ /* ERROR invalid composite literal element type P: no core type */ }}
+}
+
+func _[P *S1|S1]() {
+ _= []P{{ /* ERROR invalid composite literal element type P: no core type */ }}
+}
From b2dfec100afa7739dc1845f1009dad2d7163116c Mon Sep 17 00:00:00 2001
From: Tobias Klauser
Date: Thu, 24 Feb 2022 10:02:52 +0100
Subject: [PATCH 20/44] doc/go1.18: fix typo in AMD64 port section
Change-Id: I234ae7988fd3c7a41c08e72664f8db811eb23bb1
Reviewed-on: https://go-review.googlesource.com/c/go/+/387854
Trust: Tobias Klauser
Reviewed-by: Matt Layher
Reviewed-by: Keith Randall
---
doc/go1.18.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/go1.18.html b/doc/go1.18.html
index 8c786b94fc..2af5e04f98 100644
--- a/doc/go1.18.html
+++ b/doc/go1.18.html
@@ -182,7 +182,7 @@ Do not send CLs removing the interior tags from such phrases.
Go 1.18 introduces the new GOAMD64 environment variable, which selects at compile time
- a mininum target version of the AMD64 architecture. Allowed values are v1,
+ a minimum target version of the AMD64 architecture. Allowed values are v1,
v2, v3, or v4. Each higher level requires,
and takes advantage of, additional processor features. A detailed
description can be found
From 8c5904f149a4863183925c71ce4118413e7e0167 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?=
Date: Wed, 23 Feb 2022 10:55:18 +0100
Subject: [PATCH 21/44] doc/go1.18: mention runtime/pprof improvements
For #47694.
Change-Id: Ib49145a58b8388d35267cf4b0caa730d7e436d06
Reviewed-on: https://go-review.googlesource.com/c/go/+/387574
Reviewed-by: Michael Pratt
Trust: Michael Pratt
Run-TryBot: Michael Pratt
TryBot-Result: Gopher Robot
Reviewed-by: Rhys Hiltner
Reviewed-by: Bryan Mills
Trust: Bryan Mills
---
doc/go1.18.html | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/doc/go1.18.html b/doc/go1.18.html
index 2af5e04f98..bc29ed4afe 100644
--- a/doc/go1.18.html
+++ b/doc/go1.18.html
@@ -1141,6 +1141,16 @@ For more details, see go.dev/issue/44505
+- runtime/pprof
+ -
+
+ The CPU profiler now uses per-thread timers on Linux. This increases the
+ maximum CPU usage that a profile can observe, and reduces some forms of
+ bias.
+
+
+
+
- strconv
-
From 4edefe95689c31846a73e36b3e0723c924def45d Mon Sep 17 00:00:00 2001
From: Dan Scales
Date: Sun, 31 Oct 2021 19:45:21 -0700
Subject: [PATCH 22/44] cmd/compile: delay all call transforms if in a generic
function
We changed to delaying all transforms of generic functions, since there
are so many complicated situations where type params can be used. We
missed changing so that all Call expressions(not just some) are delayed
if in a generic function. This changes to delaying all transforms on
calls in generic functions. Had to convert Call() to g.callExpr() (so we
can access g.delayTransform()). By always delaying transforms on calls
in generic functions, we actually simplify the code a bit both in
g.CallExpr() and stencil.go.
Fixes #51236
Change-Id: I0342c7995254082c4baf709b0b92a06ec14425e9
Reviewed-on: https://go-review.googlesource.com/c/go/+/386220
Reviewed-by: Keith Randall
Trust: Dan Scales
Run-TryBot: Dan Scales
TryBot-Result: Gopher Robot
---
src/cmd/compile/internal/noder/expr.go | 49 ++++++++++++-
src/cmd/compile/internal/noder/helpers.go | 89 -----------------------
src/cmd/compile/internal/noder/stencil.go | 11 +--
test/typeparam/issue51236.go | 22 ++++++
4 files changed, 71 insertions(+), 100 deletions(-)
create mode 100644 test/typeparam/issue51236.go
diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go
index a4e144554c..4b5ae706c1 100644
--- a/src/cmd/compile/internal/noder/expr.go
+++ b/src/cmd/compile/internal/noder/expr.go
@@ -114,7 +114,7 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node {
case *syntax.CallExpr:
fun := g.expr(expr.Fun)
- return Call(pos, g.typ(typ), fun, g.exprs(expr.ArgList), expr.HasDots)
+ return g.callExpr(pos, g.typ(typ), fun, g.exprs(expr.ArgList), expr.HasDots)
case *syntax.IndexExpr:
args := unpackListExpr(expr.Index)
@@ -206,6 +206,53 @@ func (g *irgen) substType(typ *types.Type, tparams *types.Type, targs []ir.Node)
return newt
}
+// callExpr creates a call expression (which might be a type conversion, built-in
+// call, or a regular call) and does standard transforms, unless we are in a generic
+// function.
+func (g *irgen) callExpr(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool) ir.Node {
+ n := ir.NewCallExpr(pos, ir.OCALL, fun, args)
+ n.IsDDD = dots
+ typed(typ, n)
+
+ if fun.Op() == ir.OTYPE {
+ // Actually a type conversion, not a function call.
+ if !g.delayTransform() {
+ return transformConvCall(n)
+ }
+ return n
+ }
+
+ if fun, ok := fun.(*ir.Name); ok && fun.BuiltinOp != 0 {
+ if !g.delayTransform() {
+ return transformBuiltin(n)
+ }
+ return n
+ }
+
+ // Add information, now that we know that fun is actually being called.
+ switch fun := fun.(type) {
+ case *ir.SelectorExpr:
+ if fun.Op() == ir.OMETHVALUE {
+ op := ir.ODOTMETH
+ if fun.X.Type().IsInterface() {
+ op = ir.ODOTINTER
+ }
+ fun.SetOp(op)
+ // Set the type to include the receiver, since that's what
+ // later parts of the compiler expect
+ fun.SetType(fun.Selection.Type)
+ }
+ }
+
+ // A function instantiation (even if fully concrete) shouldn't be
+ // transformed yet, because we need to add the dictionary during the
+ // transformation.
+ if fun.Op() != ir.OFUNCINST && !g.delayTransform() {
+ transformCall(n)
+ }
+ return n
+}
+
// selectorExpr resolves the choice of ODOT, ODOTPTR, OMETHVALUE (eventually
// ODOTMETH & ODOTINTER), and OMETHEXPR and deals with embedded fields here rather
// than in typecheck.go.
diff --git a/src/cmd/compile/internal/noder/helpers.go b/src/cmd/compile/internal/noder/helpers.go
index 5524673e66..33acd6051a 100644
--- a/src/cmd/compile/internal/noder/helpers.go
+++ b/src/cmd/compile/internal/noder/helpers.go
@@ -98,95 +98,6 @@ func Binary(pos src.XPos, op ir.Op, typ *types.Type, x, y ir.Node) *ir.BinaryExp
}
}
-func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool) ir.Node {
- n := ir.NewCallExpr(pos, ir.OCALL, fun, args)
- n.IsDDD = dots
-
- if fun.Op() == ir.OTYPE {
- // Actually a type conversion, not a function call.
- if !fun.Type().IsInterface() &&
- (fun.Type().HasTParam() || args[0].Type().HasTParam()) {
- // For type params, we can transform if fun.Type() is known
- // to be an interface (in which case a CONVIFACE node will be
- // inserted). Otherwise, don't typecheck until we actually
- // know the type.
- return typed(typ, n)
- }
- typed(typ, n)
- return transformConvCall(n)
- }
-
- if fun, ok := fun.(*ir.Name); ok && fun.BuiltinOp != 0 {
- // For most Builtin ops, we delay doing transformBuiltin if any of the
- // args have type params, for a variety of reasons:
- //
- // OMAKE: transformMake can't choose specific ops OMAKESLICE, etc.
- // until arg type is known
- // OREAL/OIMAG: transformRealImag can't determine type float32/float64
- // until arg type known
- // OAPPEND: transformAppend requires that the arg is a slice
- // ODELETE: transformDelete requires that the arg is a map
- // OALIGNOF, OSIZEOF: can be eval'ed to a constant until types known.
- switch fun.BuiltinOp {
- case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.ODELETE, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
- hasTParam := false
- for _, arg := range args {
- if fun.BuiltinOp == ir.OOFFSETOF {
- // It's the type of left operand of the
- // selection that matters, not the type of
- // the field itself (which is irrelevant for
- // offsetof).
- arg = arg.(*ir.SelectorExpr).X
- }
- if arg.Type().HasTParam() {
- hasTParam = true
- break
- }
- }
- if hasTParam {
- return typed(typ, n)
- }
- }
-
- typed(typ, n)
- return transformBuiltin(n)
- }
-
- // Add information, now that we know that fun is actually being called.
- switch fun := fun.(type) {
- case *ir.SelectorExpr:
- if fun.Op() == ir.OMETHVALUE {
- op := ir.ODOTMETH
- if fun.X.Type().IsInterface() {
- op = ir.ODOTINTER
- }
- fun.SetOp(op)
- // Set the type to include the receiver, since that's what
- // later parts of the compiler expect
- fun.SetType(fun.Selection.Type)
- }
- }
-
- if fun.Type().HasTParam() || fun.Op() == ir.OXDOT || fun.Op() == ir.OFUNCINST {
- // If the fun arg is or has a type param, we can't do all the
- // transformations, since we may not have needed properties yet
- // (e.g. number of return values, etc). The same applies if a fun
- // which is an XDOT could not be transformed yet because of a generic
- // type in the X of the selector expression.
- //
- // A function instantiation (even if fully concrete) shouldn't be
- // transformed yet, because we need to add the dictionary during the
- // transformation.
- return typed(typ, n)
- }
-
- // If no type params, do the normal call transformations. This
- // will convert OCALL to OCALLFUNC.
- typed(typ, n)
- transformCall(n)
- return n
-}
-
func Compare(pos src.XPos, typ *types.Type, op ir.Op, x, y ir.Node) *ir.BinaryExpr {
n := ir.NewBinaryExpr(pos, op, x, y)
typed(typ, n)
diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go
index 50b6c0efcd..03937094e1 100644
--- a/src/cmd/compile/internal/noder/stencil.go
+++ b/src/cmd/compile/internal/noder/stencil.go
@@ -1055,8 +1055,6 @@ func (subst *subster) node(n ir.Node) ir.Node {
// Transform the conversion, now that we know the
// type argument.
m = transformConvCall(call)
- // CONVIFACE transformation was already done in noder2
- assert(m.Op() != ir.OCONVIFACE)
case ir.OMETHVALUE, ir.OMETHEXPR:
// Redo the transformation of OXDOT, now that we
@@ -1076,14 +1074,7 @@ func (subst *subster) node(n ir.Node) ir.Node {
case ir.ONAME:
name := call.X.Name()
if name.BuiltinOp != ir.OXXX {
- switch name.BuiltinOp {
- case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.ODELETE, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
- // Transform these builtins now that we
- // know the type of the args.
- m = transformBuiltin(call)
- default:
- base.FatalfAt(call.Pos(), "Unexpected builtin op")
- }
+ m = transformBuiltin(call)
} else {
// This is the case of a function value that was a
// type parameter (implied to be a function via a
diff --git a/test/typeparam/issue51236.go b/test/typeparam/issue51236.go
new file mode 100644
index 0000000000..779c74ee6c
--- /dev/null
+++ b/test/typeparam/issue51236.go
@@ -0,0 +1,22 @@
+// run -gcflags=-G=3
+
+// Copyright 2022 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.
+
+package main
+
+type I interface {
+ []byte
+}
+
+func F[T I]() {
+ var t T
+ explodes(t)
+}
+
+func explodes(b []byte) {}
+
+func main() {
+
+}
From 5a9fc946b42cc987db41eabcfcbaffd2fb310d94 Mon Sep 17 00:00:00 2001
From: "Bryan C. Mills"
Date: Wed, 23 Feb 2022 11:55:08 -0500
Subject: [PATCH 23/44] cmd/go: avoid +incompatible major versions if a go.mod
file exists in a subdirectory for that version
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Previous versions of the 'go' command would reject a pseudo-version
passed to 'go get' if that pseudo-version had a mismatched major
version and lacked a "+incompatible" suffix. However, they would
erroneously accept a version *with* a "+incompatible" suffix even if
the repo contained a vN/go.mod file for the same major version, and
would generate a "+incompatible" pseudo-version or version if the user
requested a tag, branch, or commit hash.
This change uniformly rejects "vN.…" without "+incompatible", and also
avoids resolving to "vN.…+incompatible", when vN/go.mod exists.
To maintain compatibility with existing go.mod files, it still accepts
"vN.…+incompatible" if the version is requested explicitly as such
and the repo root lacks a go.mod file.
Fixes #51324
Updates #36438
Change-Id: I2b16150c73fc2abe4d0a1cd34cb1600635db7139
Reviewed-on: https://go-review.googlesource.com/c/go/+/387675
Trust: Bryan Mills
Reviewed-by: Michael Matloob
---
src/cmd/go/internal/modfetch/coderepo.go | 53 ++++++++++++++-----
src/cmd/go/internal/modfetch/coderepo_test.go | 48 +++++++++++++++++
2 files changed, 89 insertions(+), 12 deletions(-)
diff --git a/src/cmd/go/internal/modfetch/coderepo.go b/src/cmd/go/internal/modfetch/coderepo.go
index 2206c7c840..dfaf16def6 100644
--- a/src/cmd/go/internal/modfetch/coderepo.go
+++ b/src/cmd/go/internal/modfetch/coderepo.go
@@ -305,17 +305,46 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
//
// (If the version is +incompatible, then the go.mod file must not exist:
// +incompatible is not an ongoing opt-out from semantic import versioning.)
- var canUseIncompatible func() bool
- canUseIncompatible = func() bool {
- var ok bool
- if r.codeDir == "" && r.pathMajor == "" {
+ incompatibleOk := map[string]bool{}
+ canUseIncompatible := func(v string) bool {
+ if r.codeDir != "" || r.pathMajor != "" {
+ // A non-empty codeDir indicates a module within a subdirectory,
+ // which necessarily has a go.mod file indicating the module boundary.
+ // A non-empty pathMajor indicates a module path with a major-version
+ // suffix, which must match.
+ return false
+ }
+
+ ok, seen := incompatibleOk[""]
+ if !seen {
_, errGoMod := r.code.ReadFile(info.Name, "go.mod", codehost.MaxGoMod)
- if errGoMod != nil {
- ok = true
+ ok = (errGoMod != nil)
+ incompatibleOk[""] = ok
+ }
+ if !ok {
+ // A go.mod file exists at the repo root.
+ return false
+ }
+
+ // Per https://go.dev/issue/51324, previous versions of the 'go' command
+ // didn't always check for go.mod files in subdirectories, so if the user
+ // requests a +incompatible version explicitly, we should continue to allow
+ // it. Otherwise, if vN/go.mod exists, expect that release tags for that
+ // major version are intended for the vN module.
+ if v != "" && !strings.HasSuffix(statVers, "+incompatible") {
+ major := semver.Major(v)
+ ok, seen = incompatibleOk[major]
+ if !seen {
+ _, errGoModSub := r.code.ReadFile(info.Name, path.Join(major, "go.mod"), codehost.MaxGoMod)
+ ok = (errGoModSub != nil)
+ incompatibleOk[major] = ok
+ }
+ if !ok {
+ return false
}
}
- canUseIncompatible = func() bool { return ok }
- return ok
+
+ return true
}
// checkCanonical verifies that the canonical version v is compatible with the
@@ -367,7 +396,7 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
base := strings.TrimSuffix(v, "+incompatible")
var errIncompatible error
if !module.MatchPathMajor(base, r.pathMajor) {
- if canUseIncompatible() {
+ if canUseIncompatible(base) {
v = base + "+incompatible"
} else {
if r.pathMajor != "" {
@@ -495,7 +524,7 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
// Save the highest non-retracted canonical tag for the revision.
// If we don't find a better match, we'll use it as the canonical version.
if tagIsCanonical && semver.Compare(highestCanonical, v) < 0 && !isRetracted(v) {
- if module.MatchPathMajor(v, r.pathMajor) || canUseIncompatible() {
+ if module.MatchPathMajor(v, r.pathMajor) || canUseIncompatible(v) {
highestCanonical = v
}
}
@@ -513,12 +542,12 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
// retracted versions.
allowedMajor := func(major string) func(v string) bool {
return func(v string) bool {
- return (major == "" || semver.Major(v) == major) && !isRetracted(v)
+ return ((major == "" && canUseIncompatible(v)) || semver.Major(v) == major) && !isRetracted(v)
}
}
if pseudoBase == "" {
var tag string
- if r.pseudoMajor != "" || canUseIncompatible() {
+ if r.pseudoMajor != "" || canUseIncompatible("") {
tag, _ = r.code.RecentTag(info.Name, tagPrefix, allowedMajor(r.pseudoMajor))
} else {
// Allow either v1 or v0, but not incompatible higher versions.
diff --git a/src/cmd/go/internal/modfetch/coderepo_test.go b/src/cmd/go/internal/modfetch/coderepo_test.go
index d98ea87da2..bb9268adb8 100644
--- a/src/cmd/go/internal/modfetch/coderepo_test.go
+++ b/src/cmd/go/internal/modfetch/coderepo_test.go
@@ -458,6 +458,54 @@ var codeRepoTests = []codeRepoTest{
rev: "v3.0.0-devel",
err: `resolves to version v0.1.1-0.20220203155313-d59622f6e4d7 (v3.0.0-devel is not a tag)`,
},
+
+ // If v2/go.mod exists, then we should prefer to match the "v2"
+ // pseudo-versions to the nested module, and resolve the module in the parent
+ // directory to only compatible versions.
+ //
+ // However (https://go.dev/issue/51324), previous versions of the 'go' command
+ // didn't always do so, so if the user explicitly requests a +incompatible
+ // version (as would be present in an existing go.mod file), we should
+ // continue to allow it.
+ {
+ vcs: "git",
+ path: "vcs-test.golang.org/git/v2sub.git",
+ rev: "80beb17a1603",
+ version: "v0.0.0-20220222205507-80beb17a1603",
+ name: "80beb17a16036f17a5aedd1bb5bd6d407b3c6dc5",
+ short: "80beb17a1603",
+ time: time.Date(2022, 2, 22, 20, 55, 7, 0, time.UTC),
+ },
+ {
+ vcs: "git",
+ path: "vcs-test.golang.org/git/v2sub.git",
+ rev: "v2.0.0",
+ err: `module contains a go.mod file, so module path must match major version ("vcs-test.golang.org/git/v2sub.git/v2")`,
+ },
+ {
+ vcs: "git",
+ path: "vcs-test.golang.org/git/v2sub.git",
+ rev: "v2.0.1-0.20220222205507-80beb17a1603",
+ err: `module contains a go.mod file, so module path must match major version ("vcs-test.golang.org/git/v2sub.git/v2")`,
+ },
+ {
+ vcs: "git",
+ path: "vcs-test.golang.org/git/v2sub.git",
+ rev: "v2.0.0+incompatible",
+ version: "v2.0.0+incompatible",
+ name: "5fcd3eaeeb391d399f562fd45a50dac9fc34ae8b",
+ short: "5fcd3eaeeb39",
+ time: time.Date(2022, 2, 22, 20, 53, 33, 0, time.UTC),
+ },
+ {
+ vcs: "git",
+ path: "vcs-test.golang.org/git/v2sub.git",
+ rev: "v2.0.1-0.20220222205507-80beb17a1603+incompatible",
+ version: "v2.0.1-0.20220222205507-80beb17a1603+incompatible",
+ name: "80beb17a16036f17a5aedd1bb5bd6d407b3c6dc5",
+ short: "80beb17a1603",
+ time: time.Date(2022, 2, 22, 20, 55, 7, 0, time.UTC),
+ },
}
func TestCodeRepo(t *testing.T) {
From c15527f0b05fe893e2630420747b128fe17566a6 Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Tue, 22 Feb 2022 16:53:17 -0800
Subject: [PATCH 24/44] go/types, types2: implement adjCoreType using
TypeParam.is
TypeParam.is also provides ~ (tilde) information which is needed
to fix #51229. Delete all code related to singleType as it's not
used anymore.
Also, remove TypeParam.hasTerms as it was not used.
For #51229.
Change-Id: Ie49b19d157230beecb17a444d1f17cf24aa4f6ba
Reviewed-on: https://go-review.googlesource.com/c/go/+/387774
Trust: Robert Griesemer
Reviewed-by: Robert Findley
---
src/cmd/compile/internal/types2/infer.go | 23 ++++++++++-----
src/cmd/compile/internal/types2/termlist.go | 9 ------
.../compile/internal/types2/termlist_test.go | 29 -------------------
src/cmd/compile/internal/types2/typeparam.go | 10 -------
src/cmd/compile/internal/types2/typeset.go | 3 --
src/go/types/infer.go | 23 ++++++++++-----
src/go/types/termlist.go | 9 ------
src/go/types/termlist_test.go | 29 -------------------
src/go/types/typeparam.go | 10 -------
src/go/types/typeset.go | 3 --
10 files changed, 32 insertions(+), 116 deletions(-)
diff --git a/src/cmd/compile/internal/types2/infer.go b/src/cmd/compile/internal/types2/infer.go
index 2d6f26c0c9..617f3edad7 100644
--- a/src/cmd/compile/internal/types2/infer.go
+++ b/src/cmd/compile/internal/types2/infer.go
@@ -591,15 +591,24 @@ func (check *Checker) inferB(pos syntax.Pos, tparams []*TypeParam, targs []Type)
return
}
+// adjCoreType returns the core type of tpar unless the
+// type parameter embeds a single, possibly named type,
+// in which case it returns that single type instead.
+// (The core type is always the underlying type of that
+// single type.)
func adjCoreType(tpar *TypeParam) Type {
- // If the type parameter embeds a single, possibly named
- // type, use that one instead of the core type (which is
- // always the underlying type of that single type).
- if single := tpar.singleType(); single != nil {
- if debug {
- assert(under(single) == coreType(tpar))
+ var single *term
+ if tpar.is(func(t *term) bool {
+ if single == nil && t != nil {
+ single = t
+ return true
}
- return single
+ return false // zero or more than one terms
+ }) {
+ if debug {
+ assert(under(single.typ) == coreType(tpar))
+ }
+ return single.typ
}
return coreType(tpar)
}
diff --git a/src/cmd/compile/internal/types2/termlist.go b/src/cmd/compile/internal/types2/termlist.go
index 844e39e3bf..a0108c4638 100644
--- a/src/cmd/compile/internal/types2/termlist.go
+++ b/src/cmd/compile/internal/types2/termlist.go
@@ -92,15 +92,6 @@ func (xl termlist) norm() termlist {
return rl
}
-// If the type set represented by xl is specified by a single (non-𝓤) term,
-// singleType returns that type. Otherwise it returns nil.
-func (xl termlist) singleType() Type {
- if nl := xl.norm(); len(nl) == 1 {
- return nl[0].typ // if nl.isAll() then typ is nil, which is ok
- }
- return nil
-}
-
// union returns the union xl ∪ yl.
func (xl termlist) union(yl termlist) termlist {
return append(xl, yl...).norm()
diff --git a/src/cmd/compile/internal/types2/termlist_test.go b/src/cmd/compile/internal/types2/termlist_test.go
index 1bdf9e1386..d1e3bdf88e 100644
--- a/src/cmd/compile/internal/types2/termlist_test.go
+++ b/src/cmd/compile/internal/types2/termlist_test.go
@@ -106,35 +106,6 @@ func TestTermlistNorm(t *testing.T) {
}
}
-func TestTermlistSingleType(t *testing.T) {
- // helper to deal with nil types
- tstring := func(typ Type) string {
- if typ == nil {
- return "nil"
- }
- return typ.String()
- }
-
- for test, want := range map[string]string{
- "∅": "nil",
- "𝓤": "nil",
- "int": "int",
- "myInt": "myInt",
- "~int": "int",
- "~int ∪ string": "nil",
- "~int ∪ myInt": "int",
- "∅ ∪ int": "int",
- "∅ ∪ ~int": "int",
- "∅ ∪ ~int ∪ string": "nil",
- } {
- xl := maketl(test)
- got := tstring(xl.singleType())
- if got != want {
- t.Errorf("(%v).singleType() == %v; want %v", test, got, want)
- }
- }
-}
-
func TestTermlistUnion(t *testing.T) {
for _, test := range []struct {
xl, yl, want string
diff --git a/src/cmd/compile/internal/types2/typeparam.go b/src/cmd/compile/internal/types2/typeparam.go
index 57613706f7..9ed3369ff4 100644
--- a/src/cmd/compile/internal/types2/typeparam.go
+++ b/src/cmd/compile/internal/types2/typeparam.go
@@ -138,16 +138,6 @@ func (t *TypeParam) iface() *Interface {
return ityp
}
-// singleType returns the single type of the type parameter constraint; or nil.
-func (t *TypeParam) singleType() Type {
- return t.iface().typeSet().singleType()
-}
-
-// hasTerms reports whether the type parameter constraint has specific type terms.
-func (t *TypeParam) hasTerms() bool {
- return t.iface().typeSet().hasTerms()
-}
-
// is calls f with the specific type terms of t's constraint and reports whether
// all calls to f returned true. If there are no specific terms, is
// returns the result of f(nil).
diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go
index 2c3e826a3f..65ae04819e 100644
--- a/src/cmd/compile/internal/types2/typeset.go
+++ b/src/cmd/compile/internal/types2/typeset.go
@@ -103,9 +103,6 @@ func (s *_TypeSet) String() string {
// hasTerms reports whether the type set has specific type terms.
func (s *_TypeSet) hasTerms() bool { return !s.terms.isEmpty() && !s.terms.isAll() }
-// singleType returns the single type in s if there is exactly one; otherwise the result is nil.
-func (s *_TypeSet) singleType() Type { return s.terms.singleType() }
-
// subsetOf reports whether s1 ⊆ s2.
func (s1 *_TypeSet) subsetOf(s2 *_TypeSet) bool { return s1.terms.subsetOf(s2.terms) }
diff --git a/src/go/types/infer.go b/src/go/types/infer.go
index 8f22144c83..d481aaa877 100644
--- a/src/go/types/infer.go
+++ b/src/go/types/infer.go
@@ -590,15 +590,24 @@ func (check *Checker) inferB(posn positioner, tparams []*TypeParam, targs []Type
return
}
+// adjCoreType returns the core type of tpar unless the
+// type parameter embeds a single, possibly named type,
+// in which case it returns that single type instead.
+// (The core type is always the underlying type of that
+// single type.)
func adjCoreType(tpar *TypeParam) Type {
- // If the type parameter embeds a single, possibly named
- // type, use that one instead of the core type (which is
- // always the underlying type of that single type).
- if single := tpar.singleType(); single != nil {
- if debug {
- assert(under(single) == coreType(tpar))
+ var single *term
+ if tpar.is(func(t *term) bool {
+ if single == nil && t != nil {
+ single = t
+ return true
}
- return single
+ return false // zero or more than one terms
+ }) {
+ if debug {
+ assert(under(single.typ) == coreType(tpar))
+ }
+ return single.typ
}
return coreType(tpar)
}
diff --git a/src/go/types/termlist.go b/src/go/types/termlist.go
index c4ab0e037e..94e49caee0 100644
--- a/src/go/types/termlist.go
+++ b/src/go/types/termlist.go
@@ -92,15 +92,6 @@ func (xl termlist) norm() termlist {
return rl
}
-// If the type set represented by xl is specified by a single (non-𝓤) term,
-// singleType returns that type. Otherwise it returns nil.
-func (xl termlist) singleType() Type {
- if nl := xl.norm(); len(nl) == 1 {
- return nl[0].typ // if nl.isAll() then typ is nil, which is ok
- }
- return nil
-}
-
// union returns the union xl ∪ yl.
func (xl termlist) union(yl termlist) termlist {
return append(xl, yl...).norm()
diff --git a/src/go/types/termlist_test.go b/src/go/types/termlist_test.go
index dddca7a682..f0d58ac1bc 100644
--- a/src/go/types/termlist_test.go
+++ b/src/go/types/termlist_test.go
@@ -106,35 +106,6 @@ func TestTermlistNorm(t *testing.T) {
}
}
-func TestTermlistSingleType(t *testing.T) {
- // helper to deal with nil types
- tstring := func(typ Type) string {
- if typ == nil {
- return "nil"
- }
- return typ.String()
- }
-
- for test, want := range map[string]string{
- "∅": "nil",
- "𝓤": "nil",
- "int": "int",
- "myInt": "myInt",
- "~int": "int",
- "~int ∪ string": "nil",
- "~int ∪ myInt": "int",
- "∅ ∪ int": "int",
- "∅ ∪ ~int": "int",
- "∅ ∪ ~int ∪ string": "nil",
- } {
- xl := maketl(test)
- got := tstring(xl.singleType())
- if got != want {
- t.Errorf("(%v).singleType() == %v; want %v", test, got, want)
- }
- }
-}
-
func TestTermlistUnion(t *testing.T) {
for _, test := range []struct {
xl, yl, want string
diff --git a/src/go/types/typeparam.go b/src/go/types/typeparam.go
index 5505372cff..778c687d43 100644
--- a/src/go/types/typeparam.go
+++ b/src/go/types/typeparam.go
@@ -140,16 +140,6 @@ func (t *TypeParam) iface() *Interface {
return ityp
}
-// singleType returns the single type of the type parameter constraint; or nil.
-func (t *TypeParam) singleType() Type {
- return t.iface().typeSet().singleType()
-}
-
-// hasTerms reports whether the type parameter constraint has specific type terms.
-func (t *TypeParam) hasTerms() bool {
- return t.iface().typeSet().hasTerms()
-}
-
// is calls f with the specific type terms of t's constraint and reports whether
// all calls to f returned true. If there are no specific terms, is
// returns the result of f(nil).
diff --git a/src/go/types/typeset.go b/src/go/types/typeset.go
index 3bc9474660..4c3f018cfe 100644
--- a/src/go/types/typeset.go
+++ b/src/go/types/typeset.go
@@ -101,9 +101,6 @@ func (s *_TypeSet) String() string {
// hasTerms reports whether the type set has specific type terms.
func (s *_TypeSet) hasTerms() bool { return !s.terms.isEmpty() && !s.terms.isAll() }
-// singleType returns the single type in s if there is exactly one; otherwise the result is nil.
-func (s *_TypeSet) singleType() Type { return s.terms.singleType() }
-
// subsetOf reports whether s1 ⊆ s2.
func (s1 *_TypeSet) subsetOf(s2 *_TypeSet) bool { return s1.terms.subsetOf(s2.terms) }
From c0840a7c720061f1293063bad5d5648267a02ba8 Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Wed, 23 Feb 2022 21:43:06 -0800
Subject: [PATCH 25/44] go/types, types2: method recv type parameter count must
match base type parameter count
Check receiver type parameter count when type checking the method
signature and report a suitable error (don't rely on delayed
instantiation and possibly constraint type inference).
While at it, simplify blank name recoding and type bound rewriting.
Stop-gap measure to avoid crashes in the compiler.
Fixes #51339.
For #51343.
Change-Id: Idbe2d32d69b66573ca973339f8924b349d2bc9cc
Reviewed-on: https://go-review.googlesource.com/c/go/+/387836
Trust: Robert Griesemer
Reviewed-by: David Chase
Reviewed-by: Robert Findley
---
.../compile/internal/types2/assignments.go | 13 +++----
src/cmd/compile/internal/types2/signature.go | 34 ++++++++---------
.../types2/testdata/fixedbugs/issue51339.go2 | 16 ++++++++
src/go/types/assignments.go | 13 +++----
src/go/types/signature.go | 37 ++++++++++---------
.../types/testdata/fixedbugs/issue51339.go2 | 16 ++++++++
6 files changed, 80 insertions(+), 49 deletions(-)
create mode 100644 src/cmd/compile/internal/types2/testdata/fixedbugs/issue51339.go2
create mode 100644 src/go/types/testdata/fixedbugs/issue51339.go2
diff --git a/src/cmd/compile/internal/types2/assignments.go b/src/cmd/compile/internal/types2/assignments.go
index 936930f0b1..d88b03748f 100644
--- a/src/cmd/compile/internal/types2/assignments.go
+++ b/src/cmd/compile/internal/types2/assignments.go
@@ -294,15 +294,14 @@ func (check *Checker) typesSummary(list []Type, variadic bool) string {
return "(" + strings.Join(res, ", ") + ")"
}
-func (check *Checker) assignError(rhs []syntax.Expr, nvars, nvals int) {
- measure := func(x int, unit string) string {
- s := fmt.Sprintf("%d %s", x, unit)
- if x != 1 {
- s += "s"
- }
- return s
+func measure(x int, unit string) string {
+ if x != 1 {
+ unit += "s"
}
+ return fmt.Sprintf("%d %s", x, unit)
+}
+func (check *Checker) assignError(rhs []syntax.Expr, nvars, nvals int) {
vars := measure(nvars, "variable")
vals := measure(nvals, "value")
rhs0 := rhs[0]
diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go
index c87fab749c..76e588254d 100644
--- a/src/cmd/compile/internal/types2/signature.go
+++ b/src/cmd/compile/internal/types2/signature.go
@@ -116,11 +116,10 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
// lookup in the scope.
for i, p := range rparams {
if p.Value == "_" {
- tpar := sig.rparams.At(i)
if check.recvTParamMap == nil {
check.recvTParamMap = make(map[*syntax.Name]*TypeParam)
}
- check.recvTParamMap[p] = tpar
+ check.recvTParamMap[p] = tparams[i]
}
}
// determine receiver type to get its type parameters
@@ -136,22 +135,23 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
}
}
// provide type parameter bounds
- // - only do this if we have the right number (otherwise an error is reported elsewhere)
- if sig.RecvTypeParams().Len() == len(recvTParams) {
- // We have a list of *TypeNames but we need a list of Types.
- list := make([]Type, sig.RecvTypeParams().Len())
- for i, t := range sig.RecvTypeParams().list() {
- list[i] = t
- check.mono.recordCanon(t, recvTParams[i])
- }
- smap := makeSubstMap(recvTParams, list)
- for i, tpar := range sig.RecvTypeParams().list() {
- bound := recvTParams[i].bound
- // bound is (possibly) parameterized in the context of the
- // receiver type declaration. Substitute parameters for the
- // current context.
- tpar.bound = check.subst(tpar.obj.pos, bound, smap, nil)
+ if len(tparams) == len(recvTParams) {
+ smap := makeRenameMap(recvTParams, tparams)
+ for i, tpar := range tparams {
+ recvTPar := recvTParams[i]
+ check.mono.recordCanon(tpar, recvTPar)
+ // recvTPar.bound is (possibly) parameterized in the context of the
+ // receiver type declaration. Substitute parameters for the current
+ // context.
+ tpar.bound = check.subst(tpar.obj.pos, recvTPar.bound, smap, nil)
}
+ } else if len(tparams) < len(recvTParams) {
+ // Reporting an error here is a stop-gap measure to avoid crashes in the
+ // compiler when a type parameter/argument cannot be inferred later. It
+ // may lead to follow-on errors (see issues #51339, #51343).
+ // TODO(gri) find a better solution
+ got := measure(len(tparams), "type parameter")
+ check.errorf(recvPar, "got %s, but receiver base type declares %d", got, len(recvTParams))
}
}
}
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51339.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51339.go2
new file mode 100644
index 0000000000..40706ec493
--- /dev/null
+++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51339.go2
@@ -0,0 +1,16 @@
+// Copyright 2022 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 is tested when running "go test -run Manual"
+// without source arguments. Use for one-off debugging.
+
+package p
+
+type T[P any, B *P] struct{}
+
+func (T /* ERROR cannot use generic type */ ) m0() {}
+func (T /* ERROR got 1 type parameter, but receiver base type declares 2 */ [_]) m1() {}
+func (T[_, _]) m2() {}
+// TODO(gri) this error is unfortunate (issue #51343)
+func (T /* ERROR got 3 arguments but 2 type parameters */ [_, _, _]) m3() {}
diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go
index f75b8b6f6b..f5e22c2f67 100644
--- a/src/go/types/assignments.go
+++ b/src/go/types/assignments.go
@@ -290,15 +290,14 @@ func (check *Checker) typesSummary(list []Type, variadic bool) string {
return "(" + strings.Join(res, ", ") + ")"
}
-func (check *Checker) assignError(rhs []ast.Expr, nvars, nvals int) {
- measure := func(x int, unit string) string {
- s := fmt.Sprintf("%d %s", x, unit)
- if x != 1 {
- s += "s"
- }
- return s
+func measure(x int, unit string) string {
+ if x != 1 {
+ unit += "s"
}
+ return fmt.Sprintf("%d %s", x, unit)
+}
+func (check *Checker) assignError(rhs []ast.Expr, nvars, nvals int) {
vars := measure(nvars, "variable")
vals := measure(nvals, "value")
rhs0 := rhs[0]
diff --git a/src/go/types/signature.go b/src/go/types/signature.go
index 8f89e931fb..f174516268 100644
--- a/src/go/types/signature.go
+++ b/src/go/types/signature.go
@@ -112,7 +112,8 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
// - the receiver specification acts as local declaration for its type parameters, which may be blank
_, rname, rparams := check.unpackRecv(recvPar.List[0].Type, true)
if len(rparams) > 0 {
- sig.rparams = bindTParams(check.declareTypeParams(nil, rparams))
+ tparams := check.declareTypeParams(nil, rparams)
+ sig.rparams = bindTParams(tparams)
// Blank identifiers don't get declared, so naive type-checking of the
// receiver type expression would fail in Checker.collectParams below,
// when Checker.ident cannot resolve the _ to a type.
@@ -122,11 +123,10 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
// lookup in the scope.
for i, p := range rparams {
if p.Name == "_" {
- tpar := sig.rparams.At(i)
if check.recvTParamMap == nil {
check.recvTParamMap = make(map[*ast.Ident]*TypeParam)
}
- check.recvTParamMap[p] = tpar
+ check.recvTParamMap[p] = tparams[i]
}
}
// determine receiver type to get its type parameters
@@ -142,22 +142,23 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
}
}
// provide type parameter bounds
- // - only do this if we have the right number (otherwise an error is reported elsewhere)
- if sig.RecvTypeParams().Len() == len(recvTParams) {
- // We have a list of *TypeNames but we need a list of Types.
- list := make([]Type, sig.RecvTypeParams().Len())
- for i, t := range sig.RecvTypeParams().list() {
- list[i] = t
- check.mono.recordCanon(t, recvTParams[i])
- }
- smap := makeSubstMap(recvTParams, list)
- for i, tpar := range sig.RecvTypeParams().list() {
- bound := recvTParams[i].bound
- // bound is (possibly) parameterized in the context of the
- // receiver type declaration. Substitute parameters for the
- // current context.
- tpar.bound = check.subst(tpar.obj.pos, bound, smap, nil)
+ if len(tparams) == len(recvTParams) {
+ smap := makeRenameMap(recvTParams, tparams)
+ for i, tpar := range tparams {
+ recvTPar := recvTParams[i]
+ check.mono.recordCanon(tpar, recvTPar)
+ // recvTPar.bound is (possibly) parameterized in the context of the
+ // receiver type declaration. Substitute parameters for the current
+ // context.
+ tpar.bound = check.subst(tpar.obj.pos, recvTPar.bound, smap, nil)
}
+ } else if len(tparams) < len(recvTParams) {
+ // Reporting an error here is a stop-gap measure to avoid crashes in the
+ // compiler when a type parameter/argument cannot be inferred later. It
+ // may lead to follow-on errors (see issues #51339, #51343).
+ // TODO(gri) find a better solution
+ got := measure(len(tparams), "type parameter")
+ check.errorf(recvPar, _BadRecv, "got %s, but receiver base type declares %d", got, len(recvTParams))
}
}
}
diff --git a/src/go/types/testdata/fixedbugs/issue51339.go2 b/src/go/types/testdata/fixedbugs/issue51339.go2
new file mode 100644
index 0000000000..6803c44d76
--- /dev/null
+++ b/src/go/types/testdata/fixedbugs/issue51339.go2
@@ -0,0 +1,16 @@
+// Copyright 2022 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 is tested when running "go test -run Manual"
+// without source arguments. Use for one-off debugging.
+
+package p
+
+type T[P any, B *P] struct{}
+
+func (T /* ERROR cannot use generic type */ ) m0() {}
+func (/* ERROR got 1 type parameter, but receiver base type declares 2 */ T[_]) m1() {}
+func (T[_, _]) m2() {}
+// TODO(gri) this error is unfortunate (issue #51343)
+func (T /* ERROR got 3 arguments but 2 type parameters */ [_, _, _]) m3() {}
From b8b3196375e6b5275ae05eba8ca04662f10ab047 Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Thu, 24 Feb 2022 15:45:11 -0800
Subject: [PATCH 26/44] doc/go1.18: document method set limitation for method
selectors
For #51183.
For #47694.
Change-Id: If47ae074c3cd9f73b2e7f6408749d9a7d56bd8d2
Reviewed-on: https://go-review.googlesource.com/c/go/+/387924
Trust: Robert Griesemer
Reviewed-by: Ian Lance Taylor
---
doc/go1.18.html | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/doc/go1.18.html b/doc/go1.18.html
index bc29ed4afe..53e9d9b258 100644
--- a/doc/go1.18.html
+++ b/doc/go1.18.html
@@ -135,6 +135,16 @@ Do not send CLs removing the interior tags from such phrases.
the predeclared functions real, imag, and complex.
We hope to remove this restriction in Go 1.19.
+ -
+ The Go compiler currently only supports calling a method
m on a value
+ x of type parameter type P if m is explictly
+ declared by P's constraint interface.
+ Similarly, method values x.m and method expressions
+ P.m also are only supported if m is explicitly
+ declared by P, even though m might be in the method set
+ of P by virtue of the fact that all types in P implement
+ m. We hope to remove this restriction in Go 1.19.
+
-
Embedding a type parameter, or a pointer to a type parameter, as
an unnamed field in a struct type is not permitted. Similarly,
From 6d810241ebd2a02bc63b7706ad68ae8d0edbfd8e Mon Sep 17 00:00:00 2001
From: Tobias Klauser
Date: Thu, 24 Feb 2022 10:19:54 +0100
Subject: [PATCH 27/44] doc/go1.18: document minimum Linux kernel version
For #45964
Change-Id: Ic66502c50ca328e944c91e710dca6c8dbc168e4f
Reviewed-on: https://go-review.googlesource.com/c/go/+/387855
Trust: Tobias Klauser
Reviewed-by: Matt Layher
Reviewed-by: Ian Lance Taylor
---
doc/go1.18.html | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/doc/go1.18.html b/doc/go1.18.html
index 53e9d9b258..5289f82665 100644
--- a/doc/go1.18.html
+++ b/doc/go1.18.html
@@ -209,6 +209,12 @@ Do not send CLs removing the interior tags from such phrases.
now supports the
c-archive and c-shared build modes.
+Linux
+
+
+ Go 1.18 requires Linux kernel version 2.6.32 or later.
+
+
Windows
From 55e5b03cb359c591a2ca6ad8b6e9274d094b1632 Mon Sep 17 00:00:00 2001
From: "Bryan C. Mills"
Date: Thu, 24 Feb 2022 17:01:14 -0500
Subject: [PATCH 28/44] doc/go1.18: note changes to automatic go.mod and go.sum
updates
Fixes #51242
Updates #45551
Change-Id: Iba6e6acd9a94d24e26fcdd125f1022430723ada7
Reviewed-on: https://go-review.googlesource.com/c/go/+/387920
Trust: Dmitri Shuralyov
Reviewed-by: Ian Lance Taylor
Trust: Bryan Mills
---
doc/go1.18.html | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/doc/go1.18.html b/doc/go1.18.html
index 5289f82665..21089ef4b3 100644
--- a/doc/go1.18.html
+++ b/doc/go1.18.html
@@ -287,6 +287,20 @@ Do not send CLs removing the interior tags from such phrases.
and installs packages, as before.
+Automatic go.mod and go.sum updates
+
+
+ The go mod graph,
+ go mod vendor,
+ go mod verify, and
+ go mod why subcommands
+ no longer automatically update the go.mod and
+ go.sum files.
+ (Those files can be updated explicitly using go get,
+ go mod tidy, or
+ go mod download.)
+
+
go version
From 7c694fbad1ed6f2f825fd09cf7a86da3be549cea Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Thu, 24 Feb 2022 13:35:16 -0800
Subject: [PATCH 29/44] go/types, types2: delay receiver type validation
Delay validation of receiver type as it may cause premature expansion
of types the receiver type is dependent on. This was actually a TODO.
While the diff looks large-ish, the actual change is small: all the
receiver validation code has been moved inside the delayed function
body, and a couple of comments have been adjusted.
Fixes #51232.
Fixes #51233.
Change-Id: I44edf0ba615996266791724b832d81b9ccb8b435
Reviewed-on: https://go-review.googlesource.com/c/go/+/387918
Trust: Robert Griesemer
Run-TryBot: Robert Griesemer
TryBot-Result: Gopher Robot
Reviewed-by: Robert Findley
---
src/cmd/compile/internal/types2/signature.go | 105 ++++++++---------
.../types2/testdata/fixedbugs/issue51232.go2 | 29 +++++
.../types2/testdata/fixedbugs/issue51233.go2 | 25 ++++
src/go/types/signature.go | 107 ++++++++++--------
.../types/testdata/fixedbugs/issue51232.go2 | 29 +++++
.../types/testdata/fixedbugs/issue51233.go2 | 25 ++++
test/typeparam/issue51232.go | 31 +++++
test/typeparam/issue51233.go | 22 ++++
8 files changed, 274 insertions(+), 99 deletions(-)
create mode 100644 src/cmd/compile/internal/types2/testdata/fixedbugs/issue51232.go2
create mode 100644 src/cmd/compile/internal/types2/testdata/fixedbugs/issue51233.go2
create mode 100644 src/go/types/testdata/fixedbugs/issue51232.go2
create mode 100644 src/go/types/testdata/fixedbugs/issue51233.go2
create mode 100644 test/typeparam/issue51232.go
create mode 100644 test/typeparam/issue51233.go
diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go
index 76e588254d..c98024f924 100644
--- a/src/cmd/compile/internal/types2/signature.go
+++ b/src/cmd/compile/internal/types2/signature.go
@@ -194,66 +194,69 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
case 1:
recv = recvList[0]
}
+ sig.recv = recv
- // TODO(gri) We should delay rtyp expansion to when we actually need the
- // receiver; thus all checks here should be delayed to later.
- rtyp, _ := deref(recv.typ)
+ // Delay validation of receiver type as it may cause premature expansion
+ // of types the receiver type is dependent on (see issues #51232, #51233).
+ check.later(func() {
+ rtyp, _ := deref(recv.typ)
- // spec: "The receiver type must be of the form T or *T where T is a type name."
- // (ignore invalid types - error was reported before)
- if rtyp != Typ[Invalid] {
- var err string
- switch T := rtyp.(type) {
- case *Named:
- T.resolve(check.bestContext(nil))
- // The receiver type may be an instantiated type referred to
- // by an alias (which cannot have receiver parameters for now).
- if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
- check.errorf(recv.pos, "cannot define methods on instantiated type %s", recv.typ)
- break
- }
- // spec: "The type denoted by T is called the receiver base type; it must not
- // be a pointer or interface type and it must be declared in the same package
- // as the method."
- if T.obj.pkg != check.pkg {
- err = "type not defined in this package"
+ // spec: "The receiver type must be of the form T or *T where T is a type name."
+ // (ignore invalid types - error was reported before)
+ if rtyp != Typ[Invalid] {
+ var err string
+ switch T := rtyp.(type) {
+ case *Named:
+ T.resolve(check.bestContext(nil))
+ // The receiver type may be an instantiated type referred to
+ // by an alias (which cannot have receiver parameters for now).
+ if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
+ check.errorf(recv.pos, "cannot define methods on instantiated type %s", recv.typ)
+ break
+ }
+ // spec: "The type denoted by T is called the receiver base type; it must not
+ // be a pointer or interface type and it must be declared in the same package
+ // as the method."
+ if T.obj.pkg != check.pkg {
+ err = "type not defined in this package"
+ if check.conf.CompilerErrorMessages {
+ check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
+ err = ""
+ }
+ } else {
+ // The underlying type of a receiver base type can be a type parameter;
+ // e.g. for methods with a generic receiver T[P] with type T[P any] P.
+ // TODO(gri) Such declarations are currently disallowed.
+ // Revisit the need for underIs.
+ underIs(T, func(u Type) bool {
+ switch u := u.(type) {
+ case *Basic:
+ // unsafe.Pointer is treated like a regular pointer
+ if u.kind == UnsafePointer {
+ err = "unsafe.Pointer"
+ return false
+ }
+ case *Pointer, *Interface:
+ err = "pointer or interface type"
+ return false
+ }
+ return true
+ })
+ }
+ case *Basic:
+ err = "basic or unnamed type"
if check.conf.CompilerErrorMessages {
check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
err = ""
}
- } else {
- // The underlying type of a receiver base type can be a type parameter;
- // e.g. for methods with a generic receiver T[P] with type T[P any] P.
- underIs(T, func(u Type) bool {
- switch u := u.(type) {
- case *Basic:
- // unsafe.Pointer is treated like a regular pointer
- if u.kind == UnsafePointer {
- err = "unsafe.Pointer"
- return false
- }
- case *Pointer, *Interface:
- err = "pointer or interface type"
- return false
- }
- return true
- })
+ default:
+ check.errorf(recv.pos, "invalid receiver type %s", recv.typ)
}
- case *Basic:
- err = "basic or unnamed type"
- if check.conf.CompilerErrorMessages {
- check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
- err = ""
+ if err != "" {
+ check.errorf(recv.pos, "invalid receiver type %s (%s)", recv.typ, err)
}
- default:
- check.errorf(recv.pos, "invalid receiver type %s", recv.typ)
}
- if err != "" {
- check.errorf(recv.pos, "invalid receiver type %s (%s)", recv.typ, err)
- // ok to continue
- }
- }
- sig.recv = recv
+ }).describef(recv, "validate receiver %s", recv)
}
sig.params = NewTuple(params...)
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51232.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51232.go2
new file mode 100644
index 0000000000..6e575a376d
--- /dev/null
+++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51232.go2
@@ -0,0 +1,29 @@
+// Copyright 2022 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.
+
+package p
+
+type RC[RG any] interface {
+ ~[]RG
+}
+
+type Fn[RCT RC[RG], RG any] func(RCT)
+
+type F[RCT RC[RG], RG any] interface {
+ Fn() Fn[RCT]
+}
+
+type concreteF[RCT RC[RG], RG any] struct {
+ makeFn func() Fn[RCT]
+}
+
+func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
+ return c.makeFn()
+}
+
+func NewConcrete[RCT RC[RG], RG any](Rc RCT) F[RCT] {
+ return &concreteF[RCT]{
+ makeFn: nil,
+ }
+}
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51233.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51233.go2
new file mode 100644
index 0000000000..5c8393d039
--- /dev/null
+++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51233.go2
@@ -0,0 +1,25 @@
+// Copyright 2022 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.
+
+package p
+
+type RC[RG any] interface {
+ ~[]RG
+}
+
+type Fn[RCT RC[RG], RG any] func(RCT)
+
+type FFn[RCT RC[RG], RG any] func() Fn[RCT]
+
+type F[RCT RC[RG], RG any] interface {
+ Fn() Fn[RCT]
+}
+
+type concreteF[RCT RC[RG], RG any] struct {
+ makeFn FFn[RCT]
+}
+
+func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
+ return c.makeFn()
+}
diff --git a/src/go/types/signature.go b/src/go/types/signature.go
index f174516268..a340ac701e 100644
--- a/src/go/types/signature.go
+++ b/src/go/types/signature.go
@@ -193,66 +193,77 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
switch len(recvList) {
case 0:
// error reported by resolver
- recv = NewParam(0, nil, "", Typ[Invalid]) // ignore recv below
+ recv = NewParam(token.NoPos, nil, "", Typ[Invalid]) // ignore recv below
default:
// more than one receiver
- check.error(recvList[len(recvList)-1], _BadRecv, "method must have exactly one receiver")
+ check.error(recvList[len(recvList)-1], _InvalidRecv, "method must have exactly one receiver")
fallthrough // continue with first receiver
case 1:
recv = recvList[0]
}
+ sig.recv = recv
- // TODO(gri) We should delay rtyp expansion to when we actually need the
- // receiver; thus all checks here should be delayed to later.
- rtyp, _ := deref(recv.typ)
+ // Delay validation of receiver type as it may cause premature expansion
+ // of types the receiver type is dependent on (see issues #51232, #51233).
+ check.later(func() {
+ rtyp, _ := deref(recv.typ)
- // spec: "The receiver type must be of the form T or *T where T is a type name."
- // (ignore invalid types - error was reported before)
- if rtyp != Typ[Invalid] {
- var err string
- switch T := rtyp.(type) {
- case *Named:
- T.resolve(check.bestContext(nil))
- // The receiver type may be an instantiated type referred to
- // by an alias (which cannot have receiver parameters for now).
- if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
- check.errorf(atPos(recv.pos), _InvalidRecv, "cannot define methods on instantiated type %s", recv.typ)
- break
- }
- // spec: "The type denoted by T is called the receiver base type; it must not
- // be a pointer or interface type and it must be declared in the same package
- // as the method."
- if T.obj.pkg != check.pkg {
- err = "type not defined in this package"
- } else {
- // The underlying type of a receiver base type can be a type parameter;
- // e.g. for methods with a generic receiver T[P] with type T[P any] P.
- underIs(T, func(u Type) bool {
- switch u := u.(type) {
- case *Basic:
- // unsafe.Pointer is treated like a regular pointer
- if u.kind == UnsafePointer {
- err = "unsafe.Pointer"
+ // spec: "The receiver type must be of the form T or *T where T is a type name."
+ // (ignore invalid types - error was reported before)
+ if rtyp != Typ[Invalid] {
+ var err string
+ switch T := rtyp.(type) {
+ case *Named:
+ T.resolve(check.bestContext(nil))
+ // The receiver type may be an instantiated type referred to
+ // by an alias (which cannot have receiver parameters for now).
+ if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
+ check.errorf(recv, _InvalidRecv, "cannot define methods on instantiated type %s", recv.typ)
+ break
+ }
+ // spec: "The type denoted by T is called the receiver base type; it must not
+ // be a pointer or interface type and it must be declared in the same package
+ // as the method."
+ if T.obj.pkg != check.pkg {
+ err = "type not defined in this package"
+ if compilerErrorMessages {
+ check.errorf(recv, _InvalidRecv, "cannot define new methods on non-local type %s", recv.typ)
+ err = ""
+ }
+ } else {
+ // The underlying type of a receiver base type can be a type parameter;
+ // e.g. for methods with a generic receiver T[P] with type T[P any] P.
+ // TODO(gri) Such declarations are currently disallowed.
+ // Revisit the need for underIs.
+ underIs(T, func(u Type) bool {
+ switch u := u.(type) {
+ case *Basic:
+ // unsafe.Pointer is treated like a regular pointer
+ if u.kind == UnsafePointer {
+ err = "unsafe.Pointer"
+ return false
+ }
+ case *Pointer, *Interface:
+ err = "pointer or interface type"
return false
}
- case *Pointer, *Interface:
- err = "pointer or interface type"
- return false
- }
- return true
- })
+ return true
+ })
+ }
+ case *Basic:
+ err = "basic or unnamed type"
+ if compilerErrorMessages {
+ check.errorf(recv, _InvalidRecv, "cannot define new methods on non-local type %s", recv.typ)
+ err = ""
+ }
+ default:
+ check.errorf(recv, _InvalidRecv, "invalid receiver type %s", recv.typ)
+ }
+ if err != "" {
+ check.errorf(recv, _InvalidRecv, "invalid receiver type %s (%s)", recv.typ, err)
}
- case *Basic:
- err = "basic or unnamed type"
- default:
- check.errorf(recv, _InvalidRecv, "invalid receiver type %s", recv.typ)
}
- if err != "" {
- check.errorf(recv, _InvalidRecv, "invalid receiver type %s (%s)", recv.typ, err)
- // ok to continue
- }
- }
- sig.recv = recv
+ }).describef(recv, "validate receiver %s", recv)
}
sig.params = NewTuple(params...)
diff --git a/src/go/types/testdata/fixedbugs/issue51232.go2 b/src/go/types/testdata/fixedbugs/issue51232.go2
new file mode 100644
index 0000000000..6e575a376d
--- /dev/null
+++ b/src/go/types/testdata/fixedbugs/issue51232.go2
@@ -0,0 +1,29 @@
+// Copyright 2022 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.
+
+package p
+
+type RC[RG any] interface {
+ ~[]RG
+}
+
+type Fn[RCT RC[RG], RG any] func(RCT)
+
+type F[RCT RC[RG], RG any] interface {
+ Fn() Fn[RCT]
+}
+
+type concreteF[RCT RC[RG], RG any] struct {
+ makeFn func() Fn[RCT]
+}
+
+func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
+ return c.makeFn()
+}
+
+func NewConcrete[RCT RC[RG], RG any](Rc RCT) F[RCT] {
+ return &concreteF[RCT]{
+ makeFn: nil,
+ }
+}
diff --git a/src/go/types/testdata/fixedbugs/issue51233.go2 b/src/go/types/testdata/fixedbugs/issue51233.go2
new file mode 100644
index 0000000000..5c8393d039
--- /dev/null
+++ b/src/go/types/testdata/fixedbugs/issue51233.go2
@@ -0,0 +1,25 @@
+// Copyright 2022 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.
+
+package p
+
+type RC[RG any] interface {
+ ~[]RG
+}
+
+type Fn[RCT RC[RG], RG any] func(RCT)
+
+type FFn[RCT RC[RG], RG any] func() Fn[RCT]
+
+type F[RCT RC[RG], RG any] interface {
+ Fn() Fn[RCT]
+}
+
+type concreteF[RCT RC[RG], RG any] struct {
+ makeFn FFn[RCT]
+}
+
+func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
+ return c.makeFn()
+}
diff --git a/test/typeparam/issue51232.go b/test/typeparam/issue51232.go
new file mode 100644
index 0000000000..2272dcdfcd
--- /dev/null
+++ b/test/typeparam/issue51232.go
@@ -0,0 +1,31 @@
+// compile -G=3
+
+// Copyright 2022 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.
+
+package p
+
+type RC[RG any] interface {
+ ~[]RG
+}
+
+type Fn[RCT RC[RG], RG any] func(RCT)
+
+type F[RCT RC[RG], RG any] interface {
+ Fn() Fn[RCT]
+}
+
+type concreteF[RCT RC[RG], RG any] struct {
+ makeFn func() Fn[RCT]
+}
+
+func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
+ return c.makeFn()
+}
+
+func NewConcrete[RCT RC[RG], RG any](Rc RCT) F[RCT] {
+ return &concreteF[RCT]{
+ makeFn: nil,
+ }
+}
diff --git a/test/typeparam/issue51233.go b/test/typeparam/issue51233.go
new file mode 100644
index 0000000000..523f0b34d6
--- /dev/null
+++ b/test/typeparam/issue51233.go
@@ -0,0 +1,22 @@
+// compile -G=3
+
+// Copyright 2022 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.
+package p
+
+type RC[RG any] interface {
+ ~[]RG
+}
+type Fn[RCT RC[RG], RG any] func(RCT)
+type FFn[RCT RC[RG], RG any] func() Fn[RCT]
+type F[RCT RC[RG], RG any] interface {
+ Fn() Fn[RCT]
+}
+type concreteF[RCT RC[RG], RG any] struct {
+ makeFn FFn[RCT]
+}
+
+func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
+ return c.makeFn()
+}
From 26999cfd84dfa11f8e87153dc91a9f67070f6916 Mon Sep 17 00:00:00 2001
From: Cherry Mui
Date: Thu, 24 Feb 2022 23:31:53 -0500
Subject: [PATCH 30/44] runtime/internal/atomic: set SP delta correctly for
64-bit atomic functions on ARM
64-bit atomic functions on ARM have the following structure:
- check if the address is 64-bit aligned, if not, prepare a frame
and call panicUnaligned
- tail call armXXX or goXXX depending on GOARM
The alignment check calls panicUnaligned after preparing a frame,
so the stack can be unwound. The call never returns, so the SP is
not set back. However, the assembler assigns SP delta following
the instruction stream order, not the control flow. So it leaves
a nonzero SP delta after the check, to the tail call instructions,
which is wrong because when they are executed the SP is not
decremented. This CL fixes this by adding the SP back (the
instruction never executes, just tells the assembler to set the
SP delta back).
Should fix #51353.
Change-Id: I976cb1cfb0e9008b13538765cbc7eea0c19c7130
Reviewed-on: https://go-review.googlesource.com/c/go/+/388014
Trust: Cherry Mui
Run-TryBot: Cherry Mui
TryBot-Result: Gopher Robot
Reviewed-by: Michael Pratt
---
src/runtime/internal/atomic/atomic_arm.s | 42 +++++++++---------------
1 file changed, 16 insertions(+), 26 deletions(-)
diff --git a/src/runtime/internal/atomic/atomic_arm.s b/src/runtime/internal/atomic/atomic_arm.s
index be3fd3a395..92cbe8a34f 100644
--- a/src/runtime/internal/atomic/atomic_arm.s
+++ b/src/runtime/internal/atomic/atomic_arm.s
@@ -229,16 +229,22 @@ store64loop:
// functions tail-call into the appropriate implementation, which
// means they must not open a frame. Hence, when they go down the
// panic path, at that point they push the LR to create a real frame
-// (they don't need to pop it because panic won't return).
+// (they don't need to pop it because panic won't return; however, we
+// do need to set the SP delta back).
+
+// Check if R1 is 8-byte aligned, panic if not.
+// Clobbers R2.
+#define CHECK_ALIGN \
+ AND.S $7, R1, R2 \
+ BEQ 4(PC) \
+ MOVW.W R14, -4(R13) /* prepare a real frame */ \
+ BL ·panicUnaligned(SB) \
+ ADD $4, R13 /* compensate SP delta */
TEXT ·Cas64(SB),NOSPLIT,$-4-21
NO_LOCAL_POINTERS
MOVW addr+0(FP), R1
- // make unaligned atomic access panic
- AND.S $7, R1, R2
- BEQ 3(PC)
- MOVW.W R14, -4(R13) // prepare a real frame
- BL ·panicUnaligned(SB)
+ CHECK_ALIGN
MOVB runtime·goarm(SB), R11
CMP $7, R11
@@ -249,11 +255,7 @@ TEXT ·Cas64(SB),NOSPLIT,$-4-21
TEXT ·Xadd64(SB),NOSPLIT,$-4-20
NO_LOCAL_POINTERS
MOVW addr+0(FP), R1
- // make unaligned atomic access panic
- AND.S $7, R1, R2
- BEQ 3(PC)
- MOVW.W R14, -4(R13) // prepare a real frame
- BL ·panicUnaligned(SB)
+ CHECK_ALIGN
MOVB runtime·goarm(SB), R11
CMP $7, R11
@@ -264,11 +266,7 @@ TEXT ·Xadd64(SB),NOSPLIT,$-4-20
TEXT ·Xchg64(SB),NOSPLIT,$-4-20
NO_LOCAL_POINTERS
MOVW addr+0(FP), R1
- // make unaligned atomic access panic
- AND.S $7, R1, R2
- BEQ 3(PC)
- MOVW.W R14, -4(R13) // prepare a real frame
- BL ·panicUnaligned(SB)
+ CHECK_ALIGN
MOVB runtime·goarm(SB), R11
CMP $7, R11
@@ -279,11 +277,7 @@ TEXT ·Xchg64(SB),NOSPLIT,$-4-20
TEXT ·Load64(SB),NOSPLIT,$-4-12
NO_LOCAL_POINTERS
MOVW addr+0(FP), R1
- // make unaligned atomic access panic
- AND.S $7, R1, R2
- BEQ 3(PC)
- MOVW.W R14, -4(R13) // prepare a real frame
- BL ·panicUnaligned(SB)
+ CHECK_ALIGN
MOVB runtime·goarm(SB), R11
CMP $7, R11
@@ -294,11 +288,7 @@ TEXT ·Load64(SB),NOSPLIT,$-4-12
TEXT ·Store64(SB),NOSPLIT,$-4-12
NO_LOCAL_POINTERS
MOVW addr+0(FP), R1
- // make unaligned atomic access panic
- AND.S $7, R1, R2
- BEQ 3(PC)
- MOVW.W R14, -4(R13) // prepare a real frame
- BL ·panicUnaligned(SB)
+ CHECK_ALIGN
MOVB runtime·goarm(SB), R11
CMP $7, R11
From 01e522a97384d2c81c90490654c2749bfe05045e Mon Sep 17 00:00:00 2001
From: Robert Findley
Date: Fri, 25 Feb 2022 18:20:12 -0500
Subject: [PATCH 31/44] go/types,types2: revert documentation for
Type.Underlying
In the dev.typeparams branch, the documentation for Type.Underlying was
updated with commentary about forwarding chains. This aspect of
Underlying should not be exposed to the user. Revert to the
documentation of Go 1.16.
Fixes #51036
Change-Id: I4b73d3908a88606314aab56540cca91c014dc426
Reviewed-on: https://go-review.googlesource.com/c/go/+/388036
Trust: Robert Findley
Run-TryBot: Robert Findley
TryBot-Result: Gopher Robot
Reviewed-by: Robert Griesemer
---
src/cmd/compile/internal/types2/type.go | 4 +---
src/go/types/type.go | 4 +---
2 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go
index ca8f155791..0fe39dbca4 100644
--- a/src/cmd/compile/internal/types2/type.go
+++ b/src/cmd/compile/internal/types2/type.go
@@ -7,9 +7,7 @@ package types2
// A Type represents a type of Go.
// All types implement the Type interface.
type Type interface {
- // Underlying returns the underlying type of a type
- // w/o following forwarding chains. Only used by
- // client packages.
+ // Underlying returns the underlying type of a type.
Underlying() Type
// String returns a string representation of a type.
diff --git a/src/go/types/type.go b/src/go/types/type.go
index 323365aefe..130637530b 100644
--- a/src/go/types/type.go
+++ b/src/go/types/type.go
@@ -7,9 +7,7 @@ package types
// A Type represents a type of Go.
// All types implement the Type interface.
type Type interface {
- // Underlying returns the underlying type of a type
- // w/o following forwarding chains. Only used by
- // client packages.
+ // Underlying returns the underlying type of a type.
Underlying() Type
// String returns a string representation of a type.
From 286e3e61aa9310bb8fd333adac6d06cfb2fcc95b Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Fri, 25 Feb 2022 11:10:44 -0800
Subject: [PATCH 32/44] go/types, types2: report an error for x.sel where x is
a built-in
In case of a selector expression x.sel where x is a built-in
we didn't report an error because the type of built-ins is
invalid and we surpress errors on operands of invalid types,
assuming that an error has been reported before.
Add a corresponding check for this case.
Review all places where we call Checker.exprOrType to ensure
(invalid) built-ins are reported.
Adjusted position for index error in types2.
Fixes #51360.
Change-Id: I24693819c729994ab79d31de8fa7bd370b3e8469
Reviewed-on: https://go-review.googlesource.com/c/go/+/388054
Trust: Robert Griesemer
Reviewed-by: Robert Findley
---
src/cmd/compile/internal/types2/call.go | 6 +++++-
src/cmd/compile/internal/types2/index.go | 2 +-
.../types2/testdata/fixedbugs/issue51360.go | 13 +++++++++++++
src/go/types/call.go | 7 ++++++-
src/go/types/index.go | 1 +
src/go/types/testdata/fixedbugs/issue51360.go | 13 +++++++++++++
6 files changed, 39 insertions(+), 3 deletions(-)
create mode 100644 src/cmd/compile/internal/types2/testdata/fixedbugs/issue51360.go
create mode 100644 src/go/types/testdata/fixedbugs/issue51360.go
diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go
index 22f65ed626..d12ee49adb 100644
--- a/src/cmd/compile/internal/types2/call.go
+++ b/src/cmd/compile/internal/types2/call.go
@@ -525,7 +525,11 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) {
}
check.exprOrType(x, e.X, false)
- if x.mode == invalid {
+ switch x.mode {
+ case builtin:
+ check.errorf(e.Pos(), "cannot select on %s", x)
+ goto Error
+ case invalid:
goto Error
}
diff --git a/src/cmd/compile/internal/types2/index.go b/src/cmd/compile/internal/types2/index.go
index 1eaddded9a..61009c121e 100644
--- a/src/cmd/compile/internal/types2/index.go
+++ b/src/cmd/compile/internal/types2/index.go
@@ -182,7 +182,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo
}
if !valid {
- check.errorf(x, invalidOp+"cannot index %s", x)
+ check.errorf(e.Pos(), invalidOp+"cannot index %s", x)
x.mode = invalid
return false
}
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51360.go b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51360.go
new file mode 100644
index 0000000000..447ce036ae
--- /dev/null
+++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51360.go
@@ -0,0 +1,13 @@
+// Copyright 2022 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.
+
+package p
+
+func _() {
+ len. /* ERROR cannot select on len */ Println
+ len. /* ERROR cannot select on len */ Println()
+ _ = len. /* ERROR cannot select on len */ Println
+ _ = len[ /* ERROR cannot index len */ 0]
+ _ = *len /* ERROR cannot indirect len */
+}
diff --git a/src/go/types/call.go b/src/go/types/call.go
index 3dab284459..854528ddfa 100644
--- a/src/go/types/call.go
+++ b/src/go/types/call.go
@@ -527,7 +527,12 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
}
check.exprOrType(x, e.X, false)
- if x.mode == invalid {
+ switch x.mode {
+ case builtin:
+ // types2 uses the position of '.' for the error
+ check.errorf(e.Sel, _UncalledBuiltin, "cannot select on %s", x)
+ goto Error
+ case invalid:
goto Error
}
diff --git a/src/go/types/index.go b/src/go/types/index.go
index eac6017ba2..33075edaf1 100644
--- a/src/go/types/index.go
+++ b/src/go/types/index.go
@@ -183,6 +183,7 @@ func (check *Checker) indexExpr(x *operand, e *typeparams.IndexExpr) (isFuncInst
}
if !valid {
+ // types2 uses the position of '[' for the error
check.invalidOp(x, _NonIndexableOperand, "cannot index %s", x)
x.mode = invalid
return false
diff --git a/src/go/types/testdata/fixedbugs/issue51360.go b/src/go/types/testdata/fixedbugs/issue51360.go
new file mode 100644
index 0000000000..fe3de04dbf
--- /dev/null
+++ b/src/go/types/testdata/fixedbugs/issue51360.go
@@ -0,0 +1,13 @@
+// Copyright 2022 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.
+
+package p
+
+func _() {
+ len.Println /* ERROR cannot select on len */
+ len.Println /* ERROR cannot select on len */ ()
+ _ = len.Println /* ERROR cannot select on len */
+ _ = len /* ERROR cannot index len */ [0]
+ _ = *len /* ERROR cannot indirect len */
+}
From a064a4f29a97a4fc7398d1ac9d7c53c5ba0bc646 Mon Sep 17 00:00:00 2001
From: Keith Randall
Date: Fri, 25 Feb 2022 15:10:24 -0800
Subject: [PATCH 33/44] cmd/compile: ensure dictionary assignment statements
are defining statements
The problem in 51355 is that escape analysis decided that the
dictionary variable was captured by reference instead of by value. We
want dictionaries to always be captured by value.
Escape analysis was confused because it saw what it thought was a
reassignment of the dictionary variable. In fact, it was the only
assignment, it just wasn't marked as the defining assignment. Fix
that.
Add an assert to make sure this stays true.
Fixes #51355
Change-Id: Ifd9342455fa107b113f5ff521a94cdbf1b8a7733
Reviewed-on: https://go-review.googlesource.com/c/go/+/388115
Trust: Keith Randall
Run-TryBot: Keith Randall
Trust: Cuong Manh Le
Trust: Dan Scales
Reviewed-by: Cuong Manh Le
Reviewed-by: Dan Scales
TryBot-Result: Gopher Robot
---
src/cmd/compile/internal/escape/escape.go | 4 +++
src/cmd/compile/internal/noder/stencil.go | 4 ++-
test/typeparam/issue51355.go | 31 +++++++++++++++++++++++
3 files changed, 38 insertions(+), 1 deletion(-)
create mode 100644 test/typeparam/issue51355.go
diff --git a/src/cmd/compile/internal/escape/escape.go b/src/cmd/compile/internal/escape/escape.go
index c2145bdf91..bc6f7c93bb 100644
--- a/src/cmd/compile/internal/escape/escape.go
+++ b/src/cmd/compile/internal/escape/escape.go
@@ -10,6 +10,7 @@ import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/logopt"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
)
@@ -243,6 +244,9 @@ func (b *batch) flowClosure(k hole, clo *ir.ClosureExpr) {
n.SetByval(!loc.addrtaken && !loc.reassigned && n.Type().Size() <= 128)
if !n.Byval() {
n.SetAddrtaken(true)
+ if n.Sym().Name == typecheck.LocalDictName {
+ base.FatalfAt(n.Pos(), "dictionary variable not captured by value")
+ }
}
if base.Flag.LowerM > 1 {
diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go
index 03937094e1..807794dc30 100644
--- a/src/cmd/compile/internal/noder/stencil.go
+++ b/src/cmd/compile/internal/noder/stencil.go
@@ -410,7 +410,8 @@ func (g *genInst) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
fn, formalParams, formalResults := startClosure(pos, outer, typ)
// This is the dictionary we want to use.
- // It may be a constant, or it may be a dictionary acquired from the outer function's dictionary.
+ // It may be a constant, it may be the outer functions's dictionary, or it may be
+ // a subdictionary acquired from the outer function's dictionary.
// For the latter, dictVar is a variable in the outer function's scope, set to the subdictionary
// read from the outer function's dictionary.
var dictVar *ir.Name
@@ -1145,6 +1146,7 @@ func (subst *subster) node(n ir.Node) ir.Node {
newfn.Dcl = append(newfn.Dcl, ldict)
as := ir.NewAssignStmt(x.Pos(), ldict, cdict)
as.SetTypecheck(1)
+ ldict.Defn = as
newfn.Body.Append(as)
// Create inst info for the instantiated closure. The dict
diff --git a/test/typeparam/issue51355.go b/test/typeparam/issue51355.go
new file mode 100644
index 0000000000..15ffa4ba21
--- /dev/null
+++ b/test/typeparam/issue51355.go
@@ -0,0 +1,31 @@
+// compile -G=3
+
+// Copyright 2022 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.
+
+package main
+
+type Cache[E comparable] struct {
+ adder func(...E)
+}
+
+func New[E comparable]() *Cache[E] {
+ c := &Cache[E]{}
+
+ c.adder = func(elements ...E) {
+ for _, value := range elements {
+ value := value
+ go func() {
+ println(value)
+ }()
+ }
+ }
+
+ return c
+}
+
+func main() {
+ c := New[string]()
+ c.adder("test")
+}
From 57dda9795da20fc12c7cfb03438959302200dbc7 Mon Sep 17 00:00:00 2001
From: Dan Scales
Date: Wed, 23 Feb 2022 17:57:09 -0800
Subject: [PATCH 34/44] test: add new test case for 51219 that triggers the
types2 issue
The existing test for 51219 didn't actually trigger the types2 issue - I
hadn't been able to minimize the test case yet properly. This new test
case issue51219b.go now does trigger the types2 issue (it's only
slightly different).
Updates #51219
Change-Id: Iaba8144b4702ff4fefec86c899b8acef127b10dc
Reviewed-on: https://go-review.googlesource.com/c/go/+/387814
Trust: Dan Scales
Reviewed-by: Robert Findley
---
test/typeparam/issue51219.dir/a.go | 39 -------------------
test/typeparam/issue51219.dir/main.go | 4 +-
test/typeparam/issue51219.out | 2 +-
test/typeparam/issue51219b.dir/a.go | 37 ++++++++++++++++++
.../{issue51219.dir => issue51219b.dir}/b.go | 5 ++-
test/typeparam/issue51219b.dir/p.go | 14 +++++++
test/typeparam/issue51219b.go | 7 ++++
7 files changed, 64 insertions(+), 44 deletions(-)
create mode 100644 test/typeparam/issue51219b.dir/a.go
rename test/typeparam/{issue51219.dir => issue51219b.dir}/b.go (77%)
create mode 100644 test/typeparam/issue51219b.dir/p.go
create mode 100644 test/typeparam/issue51219b.go
diff --git a/test/typeparam/issue51219.dir/a.go b/test/typeparam/issue51219.dir/a.go
index 3ed4322dbf..29670df0d3 100644
--- a/test/typeparam/issue51219.dir/a.go
+++ b/test/typeparam/issue51219.dir/a.go
@@ -18,42 +18,3 @@ type IConstraint interface {
type I[T IConstraint] struct {
}
-
-// The following types form an even more complex recursion (through two type
-// constraints), and model the actual types in the issue (#51219) more closely.
-// However, they don't reveal any new issue. But it seems useful to leave this
-// complex set of types in a test in case it might be broken by future changes.
-
-type Message struct {
- Interaction *Interaction[JsonRaw] `json:"interaction,omitempty"`
-}
-
-type ResolvedDataConstraint interface {
- User | Message
-}
-
-type Snowflake uint64
-
-type ResolvedData[T ResolvedDataConstraint] map[Snowflake]T
-
-type User struct {
-}
-
-type Resolved struct {
- Users ResolvedData[User] `json:"users,omitempty"`
-}
-
-type resolvedInteractionWithOptions struct {
- Resolved Resolved `json:"resolved,omitempty"`
-}
-
-type UserCommandInteractionData struct {
- resolvedInteractionWithOptions
-}
-
-type InteractionDataConstraint interface {
- JsonRaw | UserCommandInteractionData
-}
-
-type Interaction[DataT InteractionDataConstraint] struct {
-}
diff --git a/test/typeparam/issue51219.dir/main.go b/test/typeparam/issue51219.dir/main.go
index c5cffd111c..999b4a96a1 100644
--- a/test/typeparam/issue51219.dir/main.go
+++ b/test/typeparam/issue51219.dir/main.go
@@ -6,13 +6,11 @@ package main
import (
"a"
- "b"
"fmt"
)
func main() {
var x a.I[a.JsonRaw]
- var y b.InteractionRequest[a.JsonRaw]
- fmt.Printf("%v %v\n", x, y)
+ fmt.Printf("%v\n", x)
}
diff --git a/test/typeparam/issue51219.out b/test/typeparam/issue51219.out
index 99c5b9aa9b..0967ef424b 100644
--- a/test/typeparam/issue51219.out
+++ b/test/typeparam/issue51219.out
@@ -1 +1 @@
-{} {{}}
+{}
diff --git a/test/typeparam/issue51219b.dir/a.go b/test/typeparam/issue51219b.dir/a.go
new file mode 100644
index 0000000000..19049406a6
--- /dev/null
+++ b/test/typeparam/issue51219b.dir/a.go
@@ -0,0 +1,37 @@
+// Copyright 2022 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.
+
+package a
+
+type Interaction[DataT InteractionDataConstraint] struct {
+}
+
+type InteractionDataConstraint interface {
+ []byte |
+ UserCommandInteractionData
+}
+
+type UserCommandInteractionData struct {
+ resolvedInteractionWithOptions
+}
+
+type resolvedInteractionWithOptions struct {
+ Resolved Resolved `json:"resolved,omitempty"`
+}
+
+type Resolved struct {
+ Users ResolvedData[User] `json:"users,omitempty"`
+}
+
+type ResolvedData[T ResolvedDataConstraint] map[uint64]T
+
+type ResolvedDataConstraint interface {
+ User | Message
+}
+
+type User struct{}
+
+type Message struct {
+ Interaction *Interaction[[]byte] `json:"interaction,omitempty"`
+}
diff --git a/test/typeparam/issue51219.dir/b.go b/test/typeparam/issue51219b.dir/b.go
similarity index 77%
rename from test/typeparam/issue51219.dir/b.go
rename to test/typeparam/issue51219b.dir/b.go
index c1590725b0..8413d666b7 100644
--- a/test/typeparam/issue51219.dir/b.go
+++ b/test/typeparam/issue51219b.dir/b.go
@@ -4,8 +4,11 @@
package b
-import "a"
+import (
+ "./a"
+)
+// InteractionRequest is an incoming request Interaction
type InteractionRequest[T a.InteractionDataConstraint] struct {
a.Interaction[T]
}
diff --git a/test/typeparam/issue51219b.dir/p.go b/test/typeparam/issue51219b.dir/p.go
new file mode 100644
index 0000000000..9f8b840d48
--- /dev/null
+++ b/test/typeparam/issue51219b.dir/p.go
@@ -0,0 +1,14 @@
+// Copyright 2022 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.
+
+package p
+
+import (
+ "./b"
+)
+
+// ResponseWriterMock mocks corde's ResponseWriter interface
+type ResponseWriterMock struct {
+ x b.InteractionRequest[[]byte]
+}
diff --git a/test/typeparam/issue51219b.go b/test/typeparam/issue51219b.go
new file mode 100644
index 0000000000..060a1214cc
--- /dev/null
+++ b/test/typeparam/issue51219b.go
@@ -0,0 +1,7 @@
+// compiledir -G=3
+
+// Copyright 2022 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.
+
+package ignored
From 9c4a8620c802fbb03545e401c41f11d622b84b42 Mon Sep 17 00:00:00 2001
From: Dmitri Shuralyov
Date: Mon, 28 Feb 2022 09:28:47 -0500
Subject: [PATCH 35/44] CONTRIBUTORS: update for the Go 1.18 release
This update was created using the updatecontrib command:
go install golang.org/x/build/cmd/updatecontrib@latest
cd gotip
updatecontrib
With manual changes based on publicly available information
to canonicalize letter case and formatting for a few names.
For #12042.
Change-Id: If08b7e798cff6ec4248011bdadcc524b510aaff7
Reviewed-on: https://go-review.googlesource.com/c/go/+/388394
Trust: Dmitri Shuralyov
Run-TryBot: Dmitri Shuralyov
Auto-Submit: Dmitri Shuralyov
TryBot-Result: Gopher Robot
Reviewed-by: Carlos Amedee
Trust: Carlos Amedee
---
CONTRIBUTORS | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 96 insertions(+), 1 deletion(-)
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index e2e102f610..48567eed15 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -120,6 +120,7 @@ Alex Kohler
Alex Myasoedov
Alex Opie
Alex Plugaru
+Alex Schade <39062967+aschade92@users.noreply.github.com>
Alex Schroeder
Alex Sergeyev
Alex Tokarev
@@ -135,6 +136,7 @@ Alexander Klauer
Alexander Kucherenko
Alexander Larsson
Alexander Lourier
+Alexander Melentyev
Alexander Menzhinsky
Alexander Morozov
Alexander Neumann
@@ -145,6 +147,7 @@ Alexander Polcyn
Alexander Rakoczy
Alexander Reece
Alexander Surma
+Alexander Yastrebov
Alexander Zhavnerchik
Alexander Zillion
Alexander Zolotov
@@ -179,6 +182,7 @@ Alok Menghrajani
Alwin Doss
Aman Gupta
Amarjeet Anand
+Amelia Downs
Amir Mohammad Saied
Amit Kumar
Amr Mohammed
@@ -191,6 +195,7 @@ Anatol Pomozov
Anders Pearson
Anderson Queiroz
André Carvalho
+Andre Marianiello
André Martins
Andre Nathan
Andrea Nodari
@@ -221,6 +226,7 @@ Andrew Gerrand
Andrew Harding
Andrew Jackura
Andrew Kemm
+Andrew LeFevre
Andrew Louis
Andrew Lutomirski
Andrew Medvedev
@@ -234,6 +240,7 @@ Andrew Stormont
Andrew Stribblehill
Andrew Szeto
Andrew Todd
+Andrew Wansink
Andrew Werner
Andrew Wilkins
Andrew Williams
@@ -283,6 +290,7 @@ Antonio Bibiano
Antonio Garcia
Antonio Huete Jimenez
Antonio Murdaca
+Antonio Ojea
Antonio Troina
Anze Kolar
Aofei Sheng
@@ -290,6 +298,7 @@ Apisak Darakananda
Aram Hăvărneanu
Araragi Hokuto
Arash Bina
+Archana Ravindar
Arda Güçlü
Areski Belaid
Ariel Mashraki
@@ -299,6 +308,7 @@ Arnaud Ysmal
Arne Hormann
Arnout Engelen
Aron Nopanen
+Arran Walker
Artem Alekseev
Artem Khvastunov
Artem Kolin
@@ -337,6 +347,7 @@ Balaram Makam
Balazs Lecz
Baokun Lee
Barnaby Keene
+Bartłomiej Klimczak
Bartosz Grzybowski
Bartosz Oler
Bassam Ojeil
@@ -368,6 +379,7 @@ Benny Siegert
Benoit Sigoure
Berengar Lehr
Berkant Ipek <41230766+0xbkt@users.noreply.github.com>
+Beth Brown
Bharath Kumar Uppala
Bharath Thiruveedula
Bhavin Gandhi
@@ -430,6 +442,7 @@ Brian Ketelsen
Brian Slesinsky
Brian Smith
Brian Starke
+Bruce Huang
Bryan Alexander
Bryan Boreham
Bryan C. Mills
@@ -482,17 +495,21 @@ Charles Kenney
Charles L. Dorian
Charles Lee
Charles Weill
+Charlie Getzen
Charlie Moog
Charlotte Brandhorst-Satzkorn
Chauncy Cullitan
Chen Zhidong
Chen Zhihan
+Cheng Wang
Cherry Mui
Chew Choon Keat
+Chia-Chi Hsu
Chiawen Chen
Chirag Sukhala
Cholerae Hu
Chotepud Teo
+Chressie Himpel
Chris Ball
Chris Biscardi
Chris Broadfoot
@@ -570,6 +587,7 @@ Cuong Manh Le
Curtis La Graff
Cyrill Schumacher
Dai Jie
+Dai Wentao
Daisuke Fujita
Daisuke Suzuki
Daker Fernandes Pinheiro
@@ -603,6 +621,7 @@ Daniel Langner
Daniel Lidén
Daniel Lublin
Daniel Mangum
+Daniel Marshall
Daniel Martí
Daniel McCarney
Daniel Morsing