Skip to content

Commit 16d6a52

Browse files
committed
cmd/compile: new absdiff.go test, fix problem with g.curDecl
Added a new absdiff2.go test case, which works fully without using a typeparam on the right-hand-side of a type declaration (which is disallowed). Fixed an issue that the test revealed, which is that we need to set g.curDecl properly for the "later" functions which are deferred until after all declarations are initially processed. Also, g.curDecl may be non-nil in typeDecl for local type declaration. So, we adjust the associate assertion, and save/restore g.curDecl appropriately. Fixes #50790 Change-Id: Ieed76a7ad0a83bccb99cbad4bf98a7bfafbcbbd3 Reviewed-on: https://go-review.googlesource.com/c/go/+/380594 Reviewed-by: Keith Randall <khr@golang.org> Trust: Dan Scales <danscales@google.com>
1 parent 84eefdc commit 16d6a52

File tree

6 files changed

+235
-6
lines changed

6 files changed

+235
-6
lines changed

src/cmd/compile/internal/noder/decl.go

+15-6
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,20 @@ func (g *irgen) funcDecl(out *ir.Nodes, decl *syntax.FuncDecl) {
133133
g.target.Inits = append(g.target.Inits, fn)
134134
}
135135

136-
haveEmbed := g.haveEmbed
136+
saveHaveEmbed := g.haveEmbed
137+
saveCurDecl := g.curDecl
137138
g.curDecl = ""
138139
g.later(func() {
139-
defer func(b bool) { g.haveEmbed = b }(g.haveEmbed)
140-
141-
g.haveEmbed = haveEmbed
140+
defer func(b bool, s string) {
141+
// Revert haveEmbed and curDecl back to what they were before
142+
// the "later" function.
143+
g.haveEmbed = b
144+
g.curDecl = s
145+
}(g.haveEmbed, g.curDecl)
146+
147+
// Set haveEmbed and curDecl to what they were for this funcDecl.
148+
g.haveEmbed = saveHaveEmbed
149+
g.curDecl = saveCurDecl
142150
if fn.Type().HasTParam() {
143151
g.topFuncIsGeneric = true
144152
}
@@ -162,9 +170,10 @@ func (g *irgen) funcDecl(out *ir.Nodes, decl *syntax.FuncDecl) {
162170
func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) {
163171
// Set the position for any error messages we might print (e.g. too large types).
164172
base.Pos = g.pos(decl)
165-
assert(g.curDecl == "")
173+
assert(ir.CurFunc != nil || g.curDecl == "")
166174
// Set g.curDecl to the type name, as context for the type params declared
167175
// during types2-to-types1 translation if this is a generic type.
176+
saveCurDecl := g.curDecl
168177
g.curDecl = decl.Name.Value
169178
if decl.Alias {
170179
name, _ := g.def(decl.Name)
@@ -225,7 +234,7 @@ func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) {
225234
}
226235
types.ResumeCheckSize()
227236

228-
g.curDecl = ""
237+
g.curDecl = saveCurDecl
229238
if otyp, ok := otyp.(*types2.Named); ok && otyp.NumMethods() != 0 {
230239
methods := make([]*types.Field, otyp.NumMethods())
231240
for i := range methods {

test/run.go

+2
Original file line numberDiff line numberDiff line change
@@ -2180,6 +2180,8 @@ var unifiedFailures = setOf(
21802180
"typeparam/typeswitch4.go", // duplicate case failure due to stenciling
21812181
"typeparam/issue50417b.go", // Need to handle field access on a type param
21822182
"typeparam/issue50552.go", // gives missing method for instantiated type
2183+
"typeparam/absdiff2.go", // wrong assertion about closure variables
2184+
"typeparam/absdiffimp2.go", // wrong assertion about closure variables
21832185
)
21842186

21852187
func setOf(keys ...string) map[string]bool {

test/typeparam/absdiff2.go

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// run -gcflags=-G=3
2+
3+
// Copyright 2022 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package main
8+
9+
import (
10+
"fmt"
11+
"math"
12+
)
13+
14+
type Numeric interface {
15+
~int | ~int8 | ~int16 | ~int32 | ~int64 |
16+
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
17+
~float32 | ~float64 |
18+
~complex64 | ~complex128
19+
}
20+
21+
// numericAbs matches a struct containing a numeric type that has an Abs method.
22+
type numericAbs[T Numeric] interface {
23+
~struct{ Value T }
24+
Abs() T
25+
}
26+
27+
// AbsDifference computes the absolute value of the difference of
28+
// a and b, where the absolute value is determined by the Abs method.
29+
func absDifference[T Numeric, U numericAbs[T]](a, b U) T {
30+
d := a.Value - b.Value
31+
dt := U{Value: d}
32+
return dt.Abs()
33+
}
34+
35+
// orderedNumeric matches numeric types that support the < operator.
36+
type orderedNumeric interface {
37+
~int | ~int8 | ~int16 | ~int32 | ~int64 |
38+
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
39+
~float32 | ~float64
40+
}
41+
42+
// Complex matches the two complex types, which do not have a < operator.
43+
type Complex interface {
44+
~complex64 | ~complex128
45+
}
46+
47+
// orderedAbs is a helper type that defines an Abs method for
48+
// a struct containing an ordered numeric type.
49+
type orderedAbs[T orderedNumeric] struct {
50+
Value T
51+
}
52+
53+
func (a orderedAbs[T]) Abs() T {
54+
if a.Value < 0 {
55+
return -a.Value
56+
}
57+
return a.Value
58+
}
59+
60+
// complexAbs is a helper type that defines an Abs method for
61+
// a struct containing a complex type.
62+
type complexAbs[T Complex] struct {
63+
Value T
64+
}
65+
66+
func (a complexAbs[T]) Abs() T {
67+
r := float64(real(a.Value))
68+
i := float64(imag(a.Value))
69+
d := math.Sqrt(r*r + i*i)
70+
return T(complex(d, 0))
71+
}
72+
73+
// OrderedAbsDifference returns the absolute value of the difference
74+
// between a and b, where a and b are of an ordered type.
75+
func OrderedAbsDifference[T orderedNumeric](a, b T) T {
76+
return absDifference(orderedAbs[T]{a}, orderedAbs[T]{b})
77+
}
78+
79+
// ComplexAbsDifference returns the absolute value of the difference
80+
// between a and b, where a and b are of a complex type.
81+
func ComplexAbsDifference[T Complex](a, b T) T {
82+
return absDifference(complexAbs[T]{a}, complexAbs[T]{b})
83+
}
84+
85+
func main() {
86+
if got, want := OrderedAbsDifference(1.0, -2.0), 3.0; got != want {
87+
panic(fmt.Sprintf("got = %v, want = %v", got, want))
88+
}
89+
if got, want := OrderedAbsDifference(-1.0, 2.0), 3.0; got != want {
90+
panic(fmt.Sprintf("got = %v, want = %v", got, want))
91+
}
92+
if got, want := OrderedAbsDifference(-20, 15), 35; got != want {
93+
panic(fmt.Sprintf("got = %v, want = %v", got, want))
94+
}
95+
96+
if got, want := ComplexAbsDifference(5.0+2.0i, 2.0-2.0i), 5+0i; got != want {
97+
panic(fmt.Sprintf("got = %v, want = %v", got, want))
98+
}
99+
if got, want := ComplexAbsDifference(2.0-2.0i, 5.0+2.0i), 5+0i; got != want {
100+
panic(fmt.Sprintf("got = %v, want = %v", got, want))
101+
}
102+
}

test/typeparam/absdiffimp2.dir/a.go

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright 2022 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package a
6+
7+
import (
8+
"math"
9+
)
10+
11+
type Numeric interface {
12+
~int | ~int8 | ~int16 | ~int32 | ~int64 |
13+
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
14+
~float32 | ~float64 |
15+
~complex64 | ~complex128
16+
}
17+
18+
// numericAbs matches a struct containing a numeric type that has an Abs method.
19+
type numericAbs[T Numeric] interface {
20+
~struct{ Value T }
21+
Abs() T
22+
}
23+
24+
// AbsDifference computes the absolute value of the difference of
25+
// a and b, where the absolute value is determined by the Abs method.
26+
func absDifference[T Numeric, U numericAbs[T]](a, b U) T {
27+
d := a.Value - b.Value
28+
dt := U{Value: d}
29+
return dt.Abs()
30+
}
31+
32+
// orderedNumeric matches numeric types that support the < operator.
33+
type orderedNumeric interface {
34+
~int | ~int8 | ~int16 | ~int32 | ~int64 |
35+
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
36+
~float32 | ~float64
37+
}
38+
39+
// Complex matches the two complex types, which do not have a < operator.
40+
type Complex interface {
41+
~complex64 | ~complex128
42+
}
43+
44+
// orderedAbs is a helper type that defines an Abs method for
45+
// a struct containing an ordered numeric type.
46+
type orderedAbs[T orderedNumeric] struct {
47+
Value T
48+
}
49+
50+
func (a orderedAbs[T]) Abs() T {
51+
if a.Value < 0 {
52+
return -a.Value
53+
}
54+
return a.Value
55+
}
56+
57+
// complexAbs is a helper type that defines an Abs method for
58+
// a struct containing a complex type.
59+
type complexAbs[T Complex] struct {
60+
Value T
61+
}
62+
63+
func (a complexAbs[T]) Abs() T {
64+
r := float64(real(a.Value))
65+
i := float64(imag(a.Value))
66+
d := math.Sqrt(r*r + i*i)
67+
return T(complex(d, 0))
68+
}
69+
70+
// OrderedAbsDifference returns the absolute value of the difference
71+
// between a and b, where a and b are of an ordered type.
72+
func OrderedAbsDifference[T orderedNumeric](a, b T) T {
73+
return absDifference(orderedAbs[T]{a}, orderedAbs[T]{b})
74+
}
75+
76+
// ComplexAbsDifference returns the absolute value of the difference
77+
// between a and b, where a and b are of a complex type.
78+
func ComplexAbsDifference[T Complex](a, b T) T {
79+
return absDifference(complexAbs[T]{a}, complexAbs[T]{b})
80+
}
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2021 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import (
8+
"a"
9+
"fmt"
10+
)
11+
12+
func main() {
13+
if got, want := a.OrderedAbsDifference(1.0, -2.0), 3.0; got != want {
14+
panic(fmt.Sprintf("got = %v, want = %v", got, want))
15+
}
16+
if got, want := a.OrderedAbsDifference(-1.0, 2.0), 3.0; got != want {
17+
panic(fmt.Sprintf("got = %v, want = %v", got, want))
18+
}
19+
if got, want := a.OrderedAbsDifference(-20, 15), 35; got != want {
20+
panic(fmt.Sprintf("got = %v, want = %v", got, want))
21+
}
22+
23+
if got, want := a.ComplexAbsDifference(5.0+2.0i, 2.0-2.0i), 5+0i; got != want {
24+
panic(fmt.Sprintf("got = %v, want = %v", got, want))
25+
}
26+
if got, want := a.ComplexAbsDifference(2.0-2.0i, 5.0+2.0i), 5+0i; got != want {
27+
panic(fmt.Sprintf("got = %v, want = %v", got, want))
28+
}
29+
}

test/typeparam/absdiffimp2.go

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// rundir -G=3
2+
3+
// Copyright 2021 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package ignored

0 commit comments

Comments
 (0)