Skip to content

Commit e39ab9b

Browse files
committed
cmd/compile: pop instantiations of local types when leaving scope
Since we use existing instantiations from the symbol table when possible (to make sure each instantiation is unique), we need to pop instantiations of local types when leaving the containing scope. g.stmts() now pushes and pops scope, and we do a Pushdcl() in g.typ0() when creating an instantiation of a local type. Non-instantiated local types (generic or not) are translated directly from types2, so they don't need to be pushed/popped. We don't export function bodies with local types, so there is no issue during import. We still don't support local types in generic functions/methods. Fixes #50177 Change-Id: If2d2fe71aec003d13f0338565c7a0da2c9580a14 Reviewed-on: https://go-review.googlesource.com/c/go/+/372654 Reviewed-by: Keith Randall <[email protected]> Trust: Dan Scales <[email protected]> Run-TryBot: Dan Scales <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent 1c8f9d2 commit e39ab9b

File tree

3 files changed

+112
-1
lines changed

3 files changed

+112
-1
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ import (
1313
"cmd/internal/src"
1414
)
1515

16+
// stmts creates nodes for a slice of statements that form a scope.
1617
func (g *irgen) stmts(stmts []syntax.Stmt) []ir.Node {
1718
var nodes []ir.Node
19+
types.Markdcl()
1820
for _, stmt := range stmts {
1921
switch s := g.stmt(stmt).(type) {
2022
case nil: // EmptyStmt
@@ -24,6 +26,7 @@ func (g *irgen) stmts(stmts []syntax.Stmt) []ir.Node {
2426
nodes = append(nodes, s)
2527
}
2628
}
29+
types.Popdcl()
2730
return nodes
2831
}
2932

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,14 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
123123
// Make sure the base generic type exists in type1 (it may
124124
// not yet if we are referecing an imported generic type, as
125125
// opposed to a generic type declared in this package).
126-
_ = g.obj(typ.Origin().Obj())
126+
base := g.obj(typ.Origin().Obj())
127+
if base.Class == ir.PAUTO {
128+
// If the base type is a local type, we want to pop
129+
// this instantiated type symbol/definition when we
130+
// leave the containing block, so we don't use it
131+
// incorrectly later.
132+
types.Pushdcl(s)
133+
}
127134

128135
// Create a forwarding type first and put it in the g.typs
129136
// map, in order to deal with recursive generic types

test/typeparam/issue50177.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// compile -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 main
8+
9+
import "fmt"
10+
11+
type Fn[T any] func(T)
12+
type FnErr[T any] func(T) error
13+
14+
// Test that local generic types across functions don't conflict, and they also don't
15+
// conflict with local non-generic types and local variables.
16+
func caller0() {
17+
type X[T any] struct {
18+
fn Fn[int]
19+
}
20+
21+
x := X[int]{func(v int) { fmt.Println(v) }}
22+
x.fn(0)
23+
}
24+
25+
func caller1(val int) {
26+
type X[T any] struct {
27+
fn FnErr[int]
28+
}
29+
30+
x := X[int]{func(v int) error { fmt.Println(v); return nil }}
31+
x.fn(0)
32+
}
33+
34+
func caller1a(val int) {
35+
type X struct {
36+
fn func(float64) error
37+
}
38+
39+
x := X{func(v float64) error { fmt.Println(v); return nil }}
40+
x.fn(float64(3.2))
41+
}
42+
43+
func caller1b(val int) {
44+
type Y struct {
45+
fn func(float64) error
46+
}
47+
48+
X := Y{func(v float64) error { fmt.Println(v); return nil }}
49+
X.fn(float64(3.2))
50+
}
51+
52+
// Test that local generic types within different if clauses don't conflict.
53+
func caller2(val int) {
54+
if val > 2 {
55+
type X[T any] struct {
56+
fn func(v int) float64
57+
}
58+
59+
x := X[int]{func(v int) float64 { fmt.Println(v); return 1.5 }}
60+
x.fn(0)
61+
} else {
62+
type X[T any] struct {
63+
fn func(v int) int
64+
}
65+
x := X[int]{func(v int) int { fmt.Println(v); return 5 }}
66+
x.fn(0)
67+
}
68+
}
69+
70+
// Test that local generic types within different cases don't conflict with each
71+
// other or with local non-generic types or local variables.
72+
func caller3(val int) {
73+
switch val {
74+
case 0:
75+
type X[T any] struct {
76+
fn func(v int) float64
77+
}
78+
79+
x := X[int]{func(v int) float64 { fmt.Println(v); return 1.5 }}
80+
x.fn(0)
81+
case 1:
82+
type X[T any] struct {
83+
fn func(v int) int
84+
}
85+
x := X[int]{func(v int) int { fmt.Println(v); return 5 }}
86+
x.fn(0)
87+
case 2:
88+
type X struct {
89+
fn func(v int) bool
90+
}
91+
x := X{func(v int) bool { fmt.Println(v); return false }}
92+
x.fn(0)
93+
case 3:
94+
type Y struct {
95+
fn func(v int) bool
96+
}
97+
X := Y{func(v int) bool { fmt.Println(v); return false }}
98+
X.fn(0)
99+
100+
}
101+
}

0 commit comments

Comments
 (0)