nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: mvdan/sh
Pull request #1004 (2023-05-24 19:25:07)

CI: bump to macos-latest again, updating go-internal
(see commit message)




Patch:
diff --git a/go.mod b/go.mod
index 337dd581..b1988799 100644
--- a/go.mod
+++ b/go.mod
@@ -8,7 +8,7 @@ require (
 	github.com/google/go-cmp v0.5.9
 	github.com/google/renameio/v2 v2.0.0
 	github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e
-	github.com/rogpeppe/go-internal v1.10.0
+	github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97
 	golang.org/x/sync v0.1.0
 	golang.org/x/sys v0.7.0
 	golang.org/x/term v0.7.0
@@ -18,4 +18,5 @@ require (
 require (
 	github.com/kr/pretty v0.3.1 // indirect
 	github.com/kr/text v0.2.0 // indirect
+	golang.org/x/tools v0.1.12 // indirect
 )
diff --git a/go.sum b/go.sum
index e9e8aea5..8bdd903b 100644
--- a/go.sum
+++ b/go.sum
@@ -14,13 +14,15 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A=
 github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
 github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
-github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
-github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
+github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97 h1:3RPlVWzZ/PDqmVuf/FKHARG5EMid/tl7cv54Sw/QRVY=
+github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
 golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
 golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
 golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
 golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
+golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 mvdan.cc/editorconfig v0.2.0 h1:XL+7ys6ls/RKrkUNFQvEwIvNHh+JKx8Mj1pUV5wQxQE=
 mvdan.cc/editorconfig v0.2.0/go.mod h1:lvnnD3BNdBYkhq+B4uBuFFKatfp02eB6HixDvEz91C0=


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 47ad05a8..8edc8065 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -5,13 +5,14 @@ jobs:
     strategy:
       matrix:
         go-version: [1.19.x, 1.20.x]
-        os: [ubuntu-latest, macos-11, windows-latest]
+        os: [ubuntu-latest, macos-latest, windows-latest]
     runs-on: ${{ matrix.os }}
     steps:
-    - uses: actions/setup-go@v3
+    - uses: actions/checkout@v3
+    - uses: actions/setup-go@v4
       with:
         go-version: ${{ matrix.go-version }}
-    - uses: actions/checkout@v3
+        cache: false
 
     - run: go test ./...
Repository: mvdan/gofumpt
Pull request #167 (2021-11-10 22:39:28)

avoid using sign.Results.Closing when it's invalid
(see commit message)

mvdan: Merging given it's a panic, so it's relatively urgent. The reporter confirmed the fix works for them.

Patch:
diff --git a/format/format.go b/format/format.go
index 012b602..9ab1db8 100644
--- a/format/format.go
+++ b/format/format.go
@@ -50,6 +50,11 @@ type Options struct {
 // source file.
 func Source(src []byte, opts Options) ([]byte, error) {
 	fset := token.NewFileSet()
+
+	// Ensure our parsed files never start with base 1,
+	// to ensure that using token.NoPos+1 will panic.
+	fset.AddFile("gofumpt_base.go", 1, 10)
+
 	file, err := parser.ParseFile(fset, "", src, parser.ParseComments)
 	if err != nil {
 		return nil, err
@@ -553,10 +558,14 @@ func (f *fumpter) applyPre(c *astutil.Cursor) {
 				// The body is preceded by a multi-line function
 				// signature, we move the `) {` to avoid the empty line.
 				switch {
-				case isThereAnEmptyLine && sign.Results != nil && !resultClosingIsFirstCharOnEndLine:
+				case isThereAnEmptyLine && sign.Results != nil &&
+					!resultClosingIsFirstCharOnEndLine &&
+					sign.Results.Closing.IsValid(): // there may be no ")"
 					sign.Results.Closing += 1
 					f.addNewline(sign.Results.Closing)
-				case isThereAnEmptyLine && sign.Params != nil && !paramClosingIsFirstCharOnEndLine:
+
+				case isThereAnEmptyLine && sign.Params != nil &&
+					!paramClosingIsFirstCharOnEndLine:
 					sign.Params.Closing += 1
 					f.addNewline(sign.Params.Closing)
 				}
diff --git a/gofmt.go b/gofmt.go
index eedb60a..58a63e6 100644
--- a/gofmt.go
+++ b/gofmt.go
@@ -197,6 +197,10 @@ func main() {
 }
 
 func gofumptMain() {
+	// Ensure our parsed files never start with base 1,
+	// to ensure that using token.NoPos+1 will panic.
+	fileSet.AddFile("gofumpt_base.go", 1, 10)
+
 	flag.Usage = usage
 	flag.Parse()
 


Test patch:
diff --git a/testdata/scripts/func-newlines.txt b/testdata/scripts/func-newlines.txt
index 1b15615..caa0ce1 100644
--- a/testdata/scripts/func-newlines.txt
+++ b/testdata/scripts/func-newlines.txt
@@ -249,6 +249,15 @@ func multilineParamsWithoutEmptyLineWithComment(p1 string,
 	// comment
 	println("body")
 }
+
+// Same as the others above, but with a single result parameter without
+// parentheses. This used to cause token.File.Offset crashes.
+func f(p1 string,
+	p2 string) int {
+
+	println("body")
+	return 0
+}
 -- foo.go.golden --
 package p
 
@@ -449,3 +458,12 @@ func multilineParamsWithoutEmptyLineWithComment(p1 string,
 	// comment
 	println("body")
 }
+
+// Same as the others above, but with a single result parameter without
+// parentheses. This used to cause token.File.Offset crashes.
+func f(p1 string,
+	p2 string,
+) int {
+	println("body")
+	return 0
+}
Repository: mvdan/gofumpt
Pull request #179 (2021-12-16 12:05:30)

format: treat `noinspection` as comment directive
Used by some versions of GoLand and friends,
https://www.jetbrains.com/help/go/disabling-and-enabling-inspections.html

New versions use `//goland:noinspection` instead/additionally, but it doesn't hurt much to support the older (and still the only documented) one.


Patch:
diff --git a/format/format.go b/format/format.go
index 522ce83..e4154d2 100644
--- a/format/format.go
+++ b/format/format.go
@@ -306,17 +306,18 @@ func (f *fumpter) lineEnd(line int) token.Pos {
 
 // rxCommentDirective covers all common Go comment directives:
 //
-//   //go:         | standard Go directives, like go:noinline
-//   //some-words: | similar to the syntax above, like lint:ignore or go-sumtype:decl
-//   //line        | inserted line information for cmd/compile
-//   //export      | to mark cgo funcs for exporting
-//   //extern      | C function declarations for gccgo
-//   //sys(nb)?    | syscall function wrapper prototypes
-//   //nolint      | nolint directive for golangci
+//   //go:          | standard Go directives, like go:noinline
+//   //some-words:  | similar to the syntax above, like lint:ignore or go-sumtype:decl
+//   //line         | inserted line information for cmd/compile
+//   //export       | to mark cgo funcs for exporting
+//   //extern       | C function declarations for gccgo
+//   //sys(nb)?     | syscall function wrapper prototypes
+//   //nolint       | nolint directive for golangci
+//   //noinspection | noinspection directive for GoLand and friends
 //
 // Note that the "some-words:" matching expects a letter afterward, such as
 // "go:generate", to prevent matching false positives like "https://site".
-var rxCommentDirective = regexp.MustCompile(`^([a-z-]+:[a-z]+|line\b|export\b|extern\b|sys(nb)?\b|nolint\b)`)
+var rxCommentDirective = regexp.MustCompile(`^([a-z-]+:[a-z]+|line\b|export\b|extern\b|sys(nb)?\b|no(lint|inspection)\b)`)
 
 func (f *fumpter) applyPre(c *astutil.Cursor) {
 	f.splitLongLine(c)


Test patch:
diff --git a/testdata/scripts/comment-spaced.txt b/testdata/scripts/comment-spaced.txt
index c3ca9ce..e97fce5 100644
--- a/testdata/scripts/comment-spaced.txt
+++ b/testdata/scripts/comment-spaced.txt
@@ -24,6 +24,10 @@ package p
 
 //nolint:somelinter // explanation
 
+//noinspection ALL
+
+//noinspection foo,bar
+
 //not actually: a directive
 
 //https://just.one/url
@@ -83,6 +87,10 @@ package p
 
 //nolint:somelinter // explanation
 
+//noinspection ALL
+
+//noinspection foo,bar
+
 // not actually: a directive
 
 // https://just.one/url
Repository: mvdan/gofumpt
Pull request #191 (2022-02-12 11:12:16)

fix panic with go1.18 workspaces
This PR fixes a panic in projects that use go1.18 workspace—`go list -m -f {{.Version}}` returns a newline-separated list of Go versions for all modules in the workspace, and it panics on semver check. Now, instead of using `go list`, we extract Go version from `go mod edit -json` output.

https://github.com/mvdan/gofumpt/blob/f32c372f2e95fd5c97be3e6f2585ee7571b68846/format/format.go#L96-L98

<details>


```
panic: invalid semver string: "v1.18\n1.18"

goroutine 1 [running]:
mvdan.cc/gofumpt/format.File(0xc0001065c0, 0xc000168100, {{0xc000014927?, 0xc000121400?}, 0xa?})
        mvdan.cc/gofumpt@v0.2.1/format/format.go:97 +0x3b4
main.processFile({0x7fff9795d60a, 0x4}, {0x0?, 0x0?}, {0x6b26d8, 0xc00000e018}, 0x38?)
        mvdan.cc/gofumpt@v0.2.1/gofmt.go:144 +0x385
main.gofumptMain()
        mvdan.cc/gofumpt@v0.2.1/gofmt.go:268 +0x4e5
main.main()
        mvdan.cc/gofumpt@v0.2.1/gofmt.go:209 +0x19
```
</details>


Patch:
diff --git a/gofmt.go b/gofmt.go
index d7391bb..d6677e3 100644
--- a/gofmt.go
+++ b/gofmt.go
@@ -6,6 +6,7 @@ package main
 
 import (
 	"bytes"
+	"encoding/json"
 	"flag"
 	"fmt"
 	"go/ast"
@@ -134,10 +135,11 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
 	// Apply gofumpt's changes before we print the code in gofumpt's format.
 
 	if *langVersion == "" {
-		out, err := exec.Command("go", "list", "-m", "-f", "{{.GoVersion}}").Output()
-		out = bytes.TrimSpace(out)
+		out, err := exec.Command("go", "mod", "edit", "-json").Output()
 		if err == nil && len(out) > 0 {
-			*langVersion = string(out)
+			var mod struct{ Go string }
+			_ = json.Unmarshal(out, &mod)
+			*langVersion = mod.Go
 		}
 	}
 


Test patch:
diff --git a/testdata/scripts/workspaces.txt b/testdata/scripts/workspaces.txt
new file mode 100644
index 0000000..5a3ca87
--- /dev/null
+++ b/testdata/scripts/workspaces.txt
@@ -0,0 +1,33 @@
+[!go1.18] skip
+
+# Octal literal prefixes were introduced in Go 1.13. If we are outside of the
+# module, language version should not be set.
+gofumpt a/go112
+cmp stdout a/go112
+
+cd a
+gofumpt go112
+cmp stdout go113
+
+-- a/go112 --
+package main
+
+const x = 0777
+-- a/go113 --
+package main
+
+const x = 0o777
+-- go.work --
+go 1.18
+use ./a
+use ./b
+-- a/go.mod --
+module a
+go 1.18
+-- a/a.go --
+package a
+-- b/go.mod --
+module b
+go 1.18
+-- b/b.go --
+package b
Repository: mvdan/gofumpt
Pull request #210 (2022-03-18 11:14:14)

remove unintentional debug prints
(see commit message)




Patch:
diff --git a/format/format.go b/format/format.go
index 8651085..727acce 100644
--- a/format/format.go
+++ b/format/format.go
@@ -912,7 +912,6 @@ func (f *fumpter) joinStdImports(d *ast.GenDecl) {
 		periodIndex := strings.IndexByte(path, '.')
 		slashIndex := strings.IndexByte(path, '/')
 		switch {
-
 		// Imports with a period in the first path element are third party.
 		// Note that this includes "foo.com" and excludes "foo/bar.com/baz".
 		case periodIndex > 0 && (slashIndex == -1 || periodIndex < slashIndex),
diff --git a/gofmt.go b/gofmt.go
index ca60bc3..4d29520 100644
--- a/gofmt.go
+++ b/gofmt.go
@@ -502,9 +502,7 @@ func gofmtMain(s *sequencer) {
 		case !info.IsDir():
 			// Non-directory arguments are always formatted.
 			arg := arg
-			println(arg)
 			s.Add(fileWeight(arg, info), func(r *reporter) error {
-				println(arg)
 				return processFile(arg, info, nil, r, true)
 			})
 		default:


Test patch:
diff --git a/testdata/scripts/ignore-implicit-vendor.txt b/testdata/scripts/ignore-implicit-vendor.txt
index ac53ef2..23f622d 100644
--- a/testdata/scripts/ignore-implicit-vendor.txt
+++ b/testdata/scripts/ignore-implicit-vendor.txt
@@ -5,21 +5,25 @@ cp orig.go.golden vendor/foo/foo.go
 
 # format explicit vendor dir
 gofumpt -l vendor
-stdout 'vendor[/\\]foo[/\\]foo.go'
+stdout -count=1 'vendor[/\\]foo[/\\]foo.go'
+! stderr .
 
 # format explicit vendor file
 gofumpt -l vendor/foo/foo.go
-stdout 'vendor[/\\]foo[/\\]foo.go'
+stdout -count=1 'vendor[/\\]foo[/\\]foo.go'
+! stderr .
 
 # ignore implicit vendor call
 gofumpt -l .
 ! stdout .
+! stderr .
 
 # format explicit vendor pkg while ignoring rest
 mkdir vendor/ignore
 cp orig.go.golden vendor/ignore/ignore.go
 gofumpt -l vendor/foo .
-stdout 'vendor[/\\]foo[/\\]foo.go'
+stdout -count=1 'vendor[/\\]foo[/\\]foo.go'
+! stderr .
 
 -- orig.go.golden --
 package p
Repository: mvdan/gofumpt
Pull request #268 (2023-04-13 07:58:42)

Don't add whitespaceto //NOSONAR comments
When using sonarqube, the `//NOSONAR` can be used to disable SONAR parsing for this line on false-positives.

See [here](https://docs.sonarcloud.io/appendices/frequently-asked-questions/).

This only works if there is no space between the slashes and the `NOSONAR`.


Just another exception to the rule :)


Patch:
diff --git a/format/format.go b/format/format.go
index 7875617..1fe4b23 100644
--- a/format/format.go
+++ b/format/format.go
@@ -305,10 +305,11 @@ func (f *fumpter) lineEnd(line int) token.Pos {
 //	//sys(nb)?     | syscall function wrapper prototypes
 //	//nolint       | nolint directive for golangci
 //	//noinspection | noinspection directive for GoLand and friends
+//	//NOSONAR      | NOSONAR directive for SonarQube
 //
 // Note that the "some-words:" matching expects a letter afterward, such as
 // "go:generate", to prevent matching false positives like "https://site".
-var rxCommentDirective = regexp.MustCompile(`^([a-z-]+:[a-z]+|line\b|export\b|extern\b|sys(nb)?\b|no(lint|inspection)\b)`)
+var rxCommentDirective = regexp.MustCompile(`^([a-z-]+:[a-z]+|line\b|export\b|extern\b|sys(nb)?\b|no(lint|inspection)\b)|NOSONAR\b`)
 
 func (f *fumpter) applyPre(c *astutil.Cursor) {
 	f.splitLongLine(c)


Test patch:
diff --git a/testdata/script/comment-spaced.txtar b/testdata/script/comment-spaced.txtar
index 9f330fc..aac33b1 100644
--- a/testdata/script/comment-spaced.txtar
+++ b/testdata/script/comment-spaced.txtar
@@ -24,6 +24,10 @@ package p
 
 //nolint:somelinter // explanation
 
+//NOSONAR
+
+//NOSONAR // explanation
+
 //noinspection ALL
 
 //noinspection foo,bar
@@ -87,6 +91,10 @@ package p
 
 //nolint:somelinter // explanation
 
+//NOSONAR
+
+//NOSONAR // explanation
+
 //noinspection ALL
 
 //noinspection foo,bar
Repository: mvdan/sh
Pull request #499 (2020-02-11 01:10:51)

interp: copy Runner.exit in SubShell
Other environment variables are copied in Runner.SubShell, but $? is special (stored in Runner.exit) and was missed.

This may or may not be behavior explicit in the bash manpage; tbh I haven't checked.  But it is what bash _does_:

```sh
bash-3.2$ false ; ( echo $? )
1
```


Patch:
diff --git a/interp/interp.go b/interp/interp.go
index 000fb1fa..5f600191 100644
--- a/interp/interp.go
+++ b/interp/interp.go
@@ -824,6 +824,7 @@ func (r *Runner) Subshell() *Runner {
 		filename:    r.filename,
 		opts:        r.opts,
 		usedNew:     r.usedNew,
+		exit:        r.exit,
 
 		origStdout: r.origStdout, // used for process substitutions
 	}


Test patch:
diff --git a/interp/interp_test.go b/interp/interp_test.go
index bd6295a6..7ba40c83 100644
--- a/interp/interp_test.go
+++ b/interp/interp_test.go
@@ -704,6 +704,7 @@ var runTests = []runTest{
 		"set -- a; echo $1; (echo $1; set -- b; echo $1); echo $1",
 		"a\na\nb\na\n",
 	},
+	{"false; ( echo $? )", "1\n"},
 
 	// cd/pwd
 	{"[[ fo~ == 'fo~' ]]", ""},
Repository: mvdan/sh
Pull request #510 (2020-02-18 17:10:14)

Fix issue with readonly and naked export.
Doing the following should not return a readonly variable error

```
readonly foo=bar
export foo
```


Patch:
diff --git a/interp/interp.go b/interp/interp.go
index 73f87fbd..fd7f84c2 100644
--- a/interp/interp.go
+++ b/interp/interp.go
@@ -1102,7 +1102,11 @@ func (r *Runner) cmd(ctx context.Context, cm syntax.Command) {
 						vr.ReadOnly = true
 					}
 				}
-				r.setVar(name, as.Index, vr)
+				if as.Naked {
+					r.setVarInternal(name, vr)
+				} else {
+					r.setVar(name, as.Index, vr)
+				}
 			}
 		}
 	case *syntax.TimeClause:


Test patch:
diff --git a/interp/interp_test.go b/interp/interp_test.go
index ee88ccbd..6add2323 100644
--- a/interp/interp_test.go
+++ b/interp/interp_test.go
@@ -2155,6 +2155,8 @@ set +o pipefail
 	// read-only vars
 	{"declare -r foo=bar; echo $foo", "bar\n"},
 	{"readonly foo=bar; echo $foo", "bar\n"},
+	{"readonly foo=bar; export foo; echo $foo", "bar\n"},
+	{"readonly foo=bar; readonly bar=foo; export foo bar; echo $bar", "foo\n"},
 	{
 		"a=b; a=c; echo $a; readonly a; a=d",
 		"c\na: readonly variable\nexit status 1 #JUSTERR",
@@ -2163,6 +2165,10 @@ set +o pipefail
 		"declare -r foo=bar; foo=etc",
 		"foo: readonly variable\nexit status 1 #JUSTERR",
 	},
+	{
+		"declare -r foo=bar; export foo=",
+		"foo: readonly variable\nexit status 1 #JUSTERR",
+	},
 	{
 		"readonly foo=bar; foo=etc",
 		"foo: readonly variable\nexit status 1 #JUSTERR",
Repository: mvdan/sh
Pull request #581 (2020-06-15 18:44:45)

syntax: Record token at which parser stops for default case.
Printing the token where the parser stops can help when debugging why a shell command fails to get parsed, so I'd like to upstream a patch to do so. 

Let me know your thoughts on this.

Thanks,
Hamza


Patch:
diff --git a/syntax/parser.go b/syntax/parser.go
index f58762a9..2bd441c0 100644
--- a/syntax/parser.go
+++ b/syntax/parser.go
@@ -2274,7 +2274,7 @@ loop:
 			}
 			fallthrough
 		default:
-			p.curErr("a command can only contain words and redirects")
+			p.curErr("a command can only contain words and redirects; encountered %s", p.tok)
 		}
 	}
 	if len(ce.Assigns) == 0 && len(ce.Args) == 0 {


Test patch:
diff --git a/syntax/parser_test.go b/syntax/parser_test.go
index e54dba13..746f62c7 100644
--- a/syntax/parser_test.go
+++ b/syntax/parser_test.go
@@ -481,7 +481,7 @@ var shellTests = []errorCase{
 	},
 	{
 		in:     "a=b foo() { bar; }",
-		common: `1:8: a command can only contain words and redirects`,
+		common: `1:8: a command can only contain words and redirects; encountered (`,
 	},
 	{
 		in:     "a=b if foo; then bar; fi",
@@ -493,7 +493,7 @@ var shellTests = []errorCase{
 	},
 	{
 		in:     ">f foo() { bar; }",
-		common: `1:7: a command can only contain words and redirects`,
+		common: `1:7: a command can only contain words and redirects; encountered (`,
 	},
 	{
 		in:     ">f if foo; then bar; fi",
@@ -643,7 +643,7 @@ var shellTests = []errorCase{
 	},
 	{
 		in:     "echo foo(",
-		common: `1:9: a command can only contain words and redirects`,
+		common: `1:9: a command can only contain words and redirects; encountered (`,
 	},
 	{
 		in:     "echo &&",
@@ -1176,7 +1176,7 @@ var shellTests = []errorCase{
 	},
 	{
 		in:     "case i in 3) foo; 4) bar; esac",
-		common: `1:20: a command can only contain words and redirects`,
+		common: `1:20: a command can only contain words and redirects; encountered )`,
 	},
 	{
 		in:     "case i in 3&) foo;",
@@ -1259,7 +1259,7 @@ var shellTests = []errorCase{
 	{
 		in:    "]] )",
 		bsmk:  `1:1: "]]" can only be used to close a test`,
-		posix: `1:4: a command can only contain words and redirects`,
+		posix: `1:4: a command can only contain words and redirects; encountered )`,
 	},
 	{
 		in:    "((foo",
@@ -1690,7 +1690,7 @@ var shellTests = []errorCase{
 	},
 	{
 		in:    "function foo() { bar; }",
-		posix: `1:13: a command can only contain words and redirects`,
+		posix: `1:13: a command can only contain words and redirects; encountered (`,
 	},
 	{
 		in:    "echo <(",
Repository: mvdan/sh
Pull request #654 (2021-01-07 13:01:49)

interp: Fix panic when trying to `read` and stdin is `nil`

mvdan: Sigh, it appears one of the mac machines got stuck.

Patch:
diff --git a/interp/builtin.go b/interp/builtin.go
index cbd3dc09..9c618ef8 100644
--- a/interp/builtin.go
+++ b/interp/builtin.go
@@ -6,6 +6,7 @@ package interp
 import (
 	"bytes"
 	"context"
+	"errors"
 	"fmt"
 	"io"
 	"os"
@@ -719,6 +720,10 @@ func (r *Runner) printOptLine(name string, enabled bool) {
 }
 
 func (r *Runner) readLine(raw bool) ([]byte, error) {
+	if r.stdin == nil {
+		return nil, errors.New("interp: can't read, there's no stdin")
+	}
+
 	var line []byte
 	esc := false
 


Test patch:
diff --git a/interp/interp_test.go b/interp/interp_test.go
index ca66be3d..30766c60 100644
--- a/interp/interp_test.go
+++ b/interp/interp_test.go
@@ -3548,3 +3548,16 @@ func TestMalformedPathOnWindows(t *testing.T) {
 		t.Fatalf("wrong output:\nwant: %q\ngot:  %q", want, got)
 	}
 }
+
+func TestReadShouldNotPanicWithNilStdin(t *testing.T) {
+	var b bytes.Buffer
+	r, err := New(StdIO(nil, &b, &b))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	f := parse(t, nil, "read foobar")
+	if err := r.Run(context.Background(), f); err == nil {
+		t.Fatal("it should have retuned an error")
+	}
+}