Skip to content

Commit 3a364dc

Browse files
Fixed issue in len with string concatenation in argument
1 parent 8a27348 commit 3a364dc

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

compiler/compiler_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,51 @@ func TestDeclSelection_RemoveUnusedTypeConstraint(t *testing.T) {
360360
sel.InitCode.IsDead(`ghost = new Bar\[\d+ /\* int \*/\]\.ptr\(7\)`)
361361
}
362362

363+
func TestLengthParenthesizingIssue841(t *testing.T) {
364+
// See issue https://github.com/gopherjs/gopherjs/issues/841
365+
//
366+
// Summary: Given `len(a+b)` where a and b are strings being concatenated
367+
// together, the result was `a + b.length` instead of `(a+b).length`.
368+
//
369+
// The fix was to check if the expression in `len` is a binary
370+
// expression or not. If it is, then the expression is parenthesized.
371+
// This will work for concatenations any combination of variables and
372+
// literals but won't pick up `len(Foo(a+b))` or `len(a[0:i+3])`.
373+
374+
src := `
375+
package main
376+
377+
func main() {
378+
a := "a"
379+
b := "b"
380+
ab := a + b
381+
if len(a+b) != len(ab) {
382+
panic("unreachable")
383+
}
384+
}`
385+
386+
srcFiles := []srctesting.Source{{Name: `main.go`, Contents: []byte(src)}}
387+
root := srctesting.ParseSources(t, srcFiles, nil)
388+
archives := compileProject(t, root, false)
389+
mainPkg := archives[root.PkgPath]
390+
391+
badRegex := regexp.MustCompile(`a\s*\+\s*b\.length`)
392+
goodRegex := regexp.MustCompile(`\(a\s*\+\s*b\)\.length`)
393+
goodFound := false
394+
for i, decl := range mainPkg.Declarations {
395+
if badRegex.Match(decl.DeclCode) {
396+
t.Errorf("found length issue in decl #%d: %s", i, decl.FullName)
397+
t.Logf("decl code:\n%s", string(decl.DeclCode))
398+
}
399+
if goodRegex.Match(decl.DeclCode) {
400+
goodFound = true
401+
}
402+
}
403+
if !goodFound {
404+
t.Error("parenthesized length not found")
405+
}
406+
}
407+
363408
func compareOrder(t *testing.T, sourceFiles []srctesting.Source, minify bool) {
364409
t.Helper()
365410
outputNormal := compile(t, sourceFiles, minify)

compiler/expressions.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,10 @@ func (fc *funcContext) translateBuiltin(name string, sig *types.Signature, args
982982
case "len":
983983
switch argType := fc.typeOf(args[0]).Underlying().(type) {
984984
case *types.Basic:
985+
// If the argument is a concatenation of strings, then add parentheses.
986+
if _, ok := args[0].(*ast.BinaryExpr); ok {
987+
return fc.formatExpr("(%e).length", args[0])
988+
}
985989
return fc.formatExpr("%e.length", args[0])
986990
case *types.Slice:
987991
return fc.formatExpr("%e.$length", args[0])

0 commit comments

Comments
 (0)