diff --git a/src/text/template/parse/parse.go b/src/text/template/parse/parse.go index efdad3297c..5195694d42 100644 --- a/src/text/template/parse/parse.go +++ b/src/text/template/parse/parse.go @@ -385,6 +385,7 @@ func (t *Tree) pipeline(context string) (pipe *PipeNode) { token := t.peekNonSpace() pos := token.pos // Are there declarations or assignments? + // TODO(mvdan): simplify the loop break/continue logic for { if v := t.peekNonSpace(); v.typ == itemVariable { t.next() @@ -406,7 +407,12 @@ func (t *Tree) pipeline(context string) (pipe *PipeNode) { } if next.typ == itemChar && next.val == "," { if context == "range" && len(vars) < 2 { - continue + switch t.peekNonSpace().typ { + case itemVariable, itemRightDelim, itemRightParen: + continue + default: + t.errorf("range can only initialize variables") + } } t.errorf("too many declarations in %s", context) } diff --git a/src/text/template/parse/parse_test.go b/src/text/template/parse/parse_test.go index d03987581c..15cc65670a 100644 --- a/src/text/template/parse/parse_test.go +++ b/src/text/template/parse/parse_test.go @@ -450,18 +450,37 @@ var errorTests = []parseTest{ {"multilinerawstring", "{{ $v := `\n` }} {{", hasError, `multilinerawstring:2: unexpected unclosed action`}, + {"rangeundefvar", + "{{range $k}}{{end}}", + hasError, `undefined variable`}, + {"rangeundefvars", + "{{range $k, $v}}{{end}}", + hasError, `undefined variable`}, + {"rangemissingvalue1", + "{{range $k,}}{{end}}", + hasError, `missing value for range`}, + {"rangemissingvalue2", + "{{range $k, $v := }}{{end}}", + hasError, `missing value for range`}, + {"rangenotvariable1", + "{{range $k, .}}{{end}}", + hasError, `range can only initialize variables`}, + {"rangenotvariable2", + "{{range $k, 123 := .}}{{end}}", + hasError, `range can only initialize variables`}, } func TestErrors(t *testing.T) { for _, test := range errorTests { - _, err := New(test.name).Parse(test.input, "", "", make(map[string]*Tree)) - if err == nil { - t.Errorf("%q: expected error", test.name) - continue - } - if !strings.Contains(err.Error(), test.result) { - t.Errorf("%q: error %q does not contain %q", test.name, err, test.result) - } + t.Run(test.name, func(t *testing.T) { + _, err := New(test.name).Parse(test.input, "", "", make(map[string]*Tree)) + if err == nil { + t.Fatalf("expected error %q, got nil", test.result) + } + if !strings.Contains(err.Error(), test.result) { + t.Fatalf("error %q does not contain %q", err, test.result) + } + }) } }