Skip to content

Commit 3b25dbd

Browse files
committed
go/ssa: use core types for array length
Updates len, cap and range built-ins to use the array length based on the core types of the array or pointer to array. These are not constant in the language but can be treated as constants during translation. Change-Id: Iec9ca61edfd51a503a4fe99e57562bff1eb56309 Reviewed-on: https://go-review.googlesource.com/c/tools/+/494977 Reviewed-by: Alan Donovan <[email protected]> TryBot-Result: Gopher Robot <[email protected]> gopls-CI: kokoro <[email protected]> Run-TryBot: Tim King <[email protected]>
1 parent e7048d5 commit 3b25dbd

File tree

2 files changed

+66
-11
lines changed

2 files changed

+66
-11
lines changed

go/ssa/builder.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -373,10 +373,8 @@ func (b *builder) builtin(fn *Function, obj *types.Builtin, args []ast.Expr, typ
373373
// We must still evaluate the value, though. (If it
374374
// was side-effect free, the whole call would have
375375
// been constant-folded.)
376-
//
377-
// Type parameters are always non-constant so use Underlying.
378-
t, _ := deptr(fn.typeOf(args[0]))
379-
if at, ok := t.Underlying().(*types.Array); ok {
376+
t, _ := deref(fn.typeOf(args[0]))
377+
if at, ok := typeparams.CoreType(t).(*types.Array); ok {
380378
b.expr(fn, args[0]) // for effects only
381379
return intConst(at.Len())
382380
}
@@ -1884,17 +1882,14 @@ func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type, pos token.P
18841882

18851883
// Determine number of iterations.
18861884
var length Value
1887-
dt, _ := deptr(x.Type())
1888-
if arr, ok := dt.Underlying().(*types.Array); ok {
1885+
dt, _ := deref(x.Type())
1886+
if arr, ok := typeparams.CoreType(dt).(*types.Array); ok {
18891887
// For array or *array, the number of iterations is
18901888
// known statically thanks to the type. We avoid a
18911889
// data dependence upon x, permitting later dead-code
18921890
// elimination if x is pure, static unrolling, etc.
18931891
// Ranging over a nil *array may have >0 iterations.
18941892
// We still generate code for x, in case it has effects.
1895-
//
1896-
// TypeParams do not have constant length. Use underlying instead of core type.
1897-
// TODO: check if needed.
18981893
length = intConst(arr.Len())
18991894
} else {
19001895
// length = len(x).

go/ssa/builder_generic_test.go

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,57 @@ func TestGenericBodies(t *testing.T) {
436436
c := *(any(v).(*C)); print(c) /*@ types("p23.C")*/
437437
}
438438
`,
439+
`
440+
package p24
441+
442+
func a[T any](f func() [4]T) {
443+
x := len(f())
444+
print(x) /*@ types("int")*/
445+
}
446+
447+
func b[T [4]any](f func() T) {
448+
x := len(f())
449+
print(x) /*@ types("int")*/
450+
}
451+
452+
func c[T any](f func() *[4]T) {
453+
x := len(f())
454+
print(x) /*@ types("int")*/
455+
}
456+
457+
func d[T *[4]any](f func() T) {
458+
x := len(f())
459+
print(x) /*@ types("int")*/
460+
}
461+
`,
462+
`
463+
package p25
464+
465+
func a[T any]() {
466+
var f func() [4]T
467+
for i, v := range f() {
468+
print(i, v) /*@ types("int", "T")*/
469+
}
470+
}
471+
472+
func b[T [4]any](f func() T) {
473+
for i, v := range f() {
474+
print(i, v) /*@ types("int", "any")*/
475+
}
476+
}
477+
478+
func c[T any](f func() *[4]T) {
479+
for i, v := range f() {
480+
print(i, v) /*@ types("int", "T")*/
481+
}
482+
}
483+
484+
func d[T *[4]any](f func() T) {
485+
for i, v := range f() {
486+
print(i, v) /*@ types("int", "any")*/
487+
}
488+
}
489+
`,
439490
} {
440491
contents := contents
441492
pkgname := packageName(t, contents)
@@ -465,15 +516,15 @@ func TestGenericBodies(t *testing.T) {
465516
p.Build()
466517

467518
// Collect calls to the builtin print function.
468-
probes := make(map[*ssa.CallCommon]bool)
519+
probes := make(map[*ssa.CallCommon]*ssa.Function)
469520
for _, mem := range p.Members {
470521
if fn, ok := mem.(*ssa.Function); ok {
471522
for _, bb := range fn.Blocks {
472523
for _, i := range bb.Instrs {
473524
if i, ok := i.(ssa.CallInstruction); ok {
474525
call := i.Common()
475526
if b, ok := call.Value.(*ssa.Builtin); ok && b.Name() == "print" {
476-
probes[i.Common()] = true
527+
probes[i.Common()] = fn
477528
}
478529
}
479530
}
@@ -517,6 +568,7 @@ func TestGenericBodies(t *testing.T) {
517568
}
518569
if got, want := fmt.Sprint(args), fmt.Sprint(note.Args); got != want {
519570
t.Errorf("Arguments to print() were expected to be %q. got %q", want, got)
571+
logFunction(t, probes[call])
520572
}
521573
}
522574
})
@@ -568,6 +620,14 @@ func TestInstructionString(t *testing.T) {
568620
_ = x.foo
569621
_ = x.foo()
570622
}
623+
624+
//@ instrs("f4", "*ssa.BinOp", "t1 + 1:int", "t2 < 4:int")
625+
//@ instrs("f4", "*ssa.Call", "f()", "print(t2, t4)")
626+
func f4[T [4]string](f func() T) {
627+
for i, v := range f() {
628+
print(i, v)
629+
}
630+
}
571631
`
572632

573633
// Parse

0 commit comments

Comments
 (0)