Skip to content

Commit ffff021

Browse files
authored
Merge pull request #1237 from nevkontakte/generics10a
Fix minified variable name collision in a type generic factory function.
2 parents 985f89f + a135401 commit ffff021

File tree

2 files changed

+57
-1
lines changed

2 files changed

+57
-1
lines changed

compiler/utils.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,14 @@ func (fc *funcContext) typeName(ty types.Type) string {
572572
}
573573
return fmt.Sprintf("(%s(%s))", fc.objectName(t.Obj()), strings.Join(args, ","))
574574
case *types.TypeParam:
575-
return fc.objectName(fc.pkgCtx.canonicalTypeParams.Lookup(t).Obj())
575+
o := t.Obj()
576+
if fc.funcObject == nil {
577+
// If the current context is not associated with a function or method,
578+
// we processing type declaration, so we canonicalize method's type
579+
// parameter names to their receiver counterparts.
580+
o = fc.pkgCtx.canonicalTypeParams.Lookup(t).Obj()
581+
}
582+
return fc.objectName(o)
576583
case *types.Interface:
577584
if t.Empty() {
578585
return "$emptyInterface"

tests/typeparams/low_level_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package typeparams
2+
3+
import "testing"
4+
5+
// This file contains test cases for low-level details of typeparam
6+
// implementation like variable name assignment.
7+
8+
type TypeParamNameMismatch[T any] struct{}
9+
10+
func (TypeParamNameMismatch[T1]) M(_ T1) {}
11+
12+
func TestTypeParamNameMismatch(t *testing.T) {
13+
// This test case exercises the case when the same typeparam is named
14+
// differently between the struct definition and one of its methods. GopherJS
15+
// must allocate the same JS variable name to both instances of the type param
16+
// in order to make it possible for the reflection method data to be evaluated
17+
// within the type's generic factory function.
18+
19+
a := TypeParamNameMismatch[int]{}
20+
a.M(0) // Make sure the method is not eliminated as dead code.
21+
}
22+
23+
type (
24+
TypeParamVariableCollision1[T any] struct{}
25+
TypeParamVariableCollision2[T any] struct{}
26+
TypeParamVariableCollision3[T any] struct{}
27+
)
28+
29+
func (TypeParamVariableCollision1[T]) M() {}
30+
func (TypeParamVariableCollision2[T]) M() {}
31+
func (TypeParamVariableCollision3[T]) M() {}
32+
33+
func TestTypeParamVariableCollision(t *testing.T) {
34+
// This test case exercises a situation when in minified mode the variable
35+
// name that gets assigned to the type parameter in the method's generic
36+
// factory function collides with a different variable in the type's generic
37+
// factory function. The bug occurred because the JS variable name allocated
38+
// to the *types.TypeName object behind a type param within the method's
39+
// factory function was not marked as used within type's factory function.
40+
41+
// Note: to trigger the bug, a package should contain multiple generic types,
42+
// so that sequentially allocated minified variable names get far enough to
43+
// cause the collision.
44+
45+
// Make sure types and methods are not eliminated as dead code.
46+
TypeParamVariableCollision1[int]{}.M()
47+
TypeParamVariableCollision2[int]{}.M()
48+
TypeParamVariableCollision3[int]{}.M()
49+
}

0 commit comments

Comments
 (0)