A source to source translator for error-propagating in golang.
The implementation of Proposal: A built-in Go error check function, try.
Create source files ending with _try.go
/ _try_test.go
.
Build tag //go:build try
required.
Then go generate -tags try ./...
(or run by IDE whatever).
And it is a good idea to switch custom build tag to try
when working in goland or vscode,
so IDE will be happy to index and check your code.
Create file copyfile_try.go
.
//go:build try
//go:generate go install github.com/goghcrow/go-try/cmd/trygen@main
//go:generate trygen
package example
import (
"fmt"
"io"
"os"
. "github.com/goghcrow/go-try"
)
// CopyFile example
// from https://github.com/golang/proposal/blob/master/design/32437-try-builtin.md#examples
//
//goland:noinspection GoUnhandledErrorResult
func CopyFile(src, dst string) (err error) {
defer HandleErrorf(&err, "copy %s %s", src, dst)
r := Try(os.Open(src))
defer r.Close()
w := Try(os.Create(dst))
defer func() {
w.Close()
if err != nil {
os.Remove(dst) // only if a โtryโ fails
}
}()
Try(io.Copy(w, r))
Try0(w.Close())
return nil
}
func HandleErrorf(err *error, format string, args ...any) {
if *err != nil {
*err = fmt.Errorf(format+": %v", append(args, *err)...)
}
}
run go:generate and output copyfile.go
.
//go:build !try
// Code generated by github.com/goghcrow/go-try DO NOT EDIT.
package example
import (
"fmt"
"io"
"os"
)
func CopyFile(src, dst string) (err error) {
defer HandleErrorf(&err, "copy %s %s", src, dst)
๐๐ฎ๐น๐ญ, ๐ฒ๐ฟ๐ฟ๐ญ := os.Open(src)
if ๐ฒ๐ฟ๐ฟ๐ญ != nil {
err = ๐ฒ๐ฟ๐ฟ๐ญ
return
}
r := ๐๐ฎ๐น๐ญ
defer r.Close()
๐๐ฎ๐น๐ฎ, ๐ฒ๐ฟ๐ฟ๐ฎ := os.Create(dst)
if ๐ฒ๐ฟ๐ฟ๐ฎ != nil {
err = ๐ฒ๐ฟ๐ฟ๐ฎ
return
}
w := ๐๐ฎ๐น๐ฎ
defer func() {
w.Close()
if err != nil {
os.Remove(dst)
}
}()
_, ๐ฒ๐ฟ๐ฟ๐ฏ := io.Copy(w, r)
if ๐ฒ๐ฟ๐ฟ๐ฏ != nil {
err = ๐ฒ๐ฟ๐ฟ๐ฏ
return
}
๐ฒ๐ฟ๐ฟ๐ฐ := w.Close()
if ๐ฒ๐ฟ๐ฟ๐ฐ != nil {
err = ๐ฒ๐ฟ๐ฟ๐ฐ
return
}
return nil
}
func HandleErrorf(err *error, format string, args ...any) {
if *err != nil {
*err = fmt.Errorf(format+": %v", append(args, *err)...)
}
}
package test
func func1[A, R any](a A) (_ R, _ error) { return }
func return1[A any]() (_ A) { return }
func ret0Err() (_ error) { return }
func ret1Err[A any]() (_ A, _ error) { return }
func ret2Err[A, B any]() (_ A, _ B, _ error) { return }
func ret3Err[A, B, C any]() (_ A, _ B, _ C, _ error) { return }
func consume1[A any](A) {}
func consume2[A, B any](A, B) {}
func consume3[A, B, C any](A, B, C) {}
func id[A any](a A) A { return a }
func handleErrorf(err *error, format string, args ...interface{}) {
if *err != nil {
*err = fmt.Errorf(format+": %v", append(args, *err)...)
}
}
Before |
After |
func error_wrapping() (a int, err error) {
defer handleErrorf(&err, "something wrong")
Try(ret1Err[bool]())
a = 42
return
} |
func error_wrapping() (a int, err error) {
defer handleErrorf(&err, "something wrong")
_, ๐ฒ๐ฟ๐ฟ๐ญ := ret1Err[bool]()
if ๐ฒ๐ฟ๐ฟ๐ญ != nil {
err = ๐ฒ๐ฟ๐ฟ๐ญ
return
}
a = 42
return
} |
Before |
After |
type (
A = int
B = int
C = int
)
println(
[]func(int) int{}[id[int](0)+Try(ret1Err[A]())](
id[int](1)+Try(ret1Err[B]()),
) + Try(ret1Err[C]()) + id[int](2),
) |
๐๐ฎ๐น๐ญ := id[int](0)
๐๐ฎ๐น๐ฎ, ๐ฒ๐ฟ๐ฟ๐ญ := ret1Err[A]()
if ๐ฒ๐ฟ๐ฟ๐ญ != nil {
return ๐ฒ๐ฟ๐ฟ๐ญ
}
๐๐ฎ๐น๐ฏ := []func(int) int{}[๐๐ฎ๐น๐ญ+๐๐ฎ๐น๐ฎ]
๐๐ฎ๐น๐ฐ := id[int](1)
๐๐ฎ๐น๐ฑ, ๐ฒ๐ฟ๐ฟ๐ฎ := ret1Err[B]()
if ๐ฒ๐ฟ๐ฟ๐ฎ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฎ
}
๐๐ฎ๐น๐ฒ := ๐๐ฎ๐น๐ฏ(๐๐ฎ๐น๐ฐ + ๐๐ฎ๐น๐ฑ)
๐๐ฎ๐น๐ณ, ๐ฒ๐ฟ๐ฟ๐ฏ := ret1Err[C]()
if ๐ฒ๐ฟ๐ฟ๐ฏ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฏ
}
๐๐ฎ๐น๐ด := id[int](2)
println(๐๐ฎ๐น๐ฒ + ๐๐ฎ๐น๐ณ + ๐๐ฎ๐น๐ด) |
Before |
After |
_ = id(true) || Try(func1[int, bool](2)) || id(false) |
๐๐ฎ๐น๐ญ := id(true)
if !๐๐ฎ๐น๐ญ {
๐๐ฎ๐น๐ฎ, ๐ฒ๐ฟ๐ฟ๐ญ := func1[int, bool](2)
if ๐ฒ๐ฟ๐ฟ๐ญ != nil {
return ๐ฒ๐ฟ๐ฟ๐ญ
}
๐๐ฎ๐น๐ญ = ๐๐ฎ๐น๐ฎ
}
if !๐๐ฎ๐น๐ญ {
๐๐ฎ๐น๐ญ = id(false)
}
_ = ๐๐ฎ๐น๐ญ |
Before |
After |
_ = id(true) && Try(func1[int, bool](2)) && id(false) |
๐๐ฎ๐น๐ญ := id(true)
if ๐๐ฎ๐น๐ญ {
๐๐ฎ๐น๐ฎ, ๐ฒ๐ฟ๐ฟ๐ญ := func1[int, bool](2)
if ๐ฒ๐ฟ๐ฟ๐ญ != nil {
return ๐ฒ๐ฟ๐ฟ๐ญ
}
๐๐ฎ๐น๐ญ = ๐๐ฎ๐น๐ฎ
}
if ๐๐ฎ๐น๐ญ {
๐๐ฎ๐น๐ญ = id(false)
}
_ = ๐๐ฎ๐น๐ญ |
Before |
After |
if Try(func1[int, bool](1)) {
} else if false {
} else if a := Try(func1[int, bool](2)); a {
} else if Try(func1[int, bool](3)) {
} else if true {
} |
๐๐ฎ๐น๐ญ, ๐ฒ๐ฟ๐ฟ๐ญ := func1[int, bool](1)
if ๐ฒ๐ฟ๐ฟ๐ญ != nil {
return ๐ฒ๐ฟ๐ฟ๐ญ
}
if ๐๐ฎ๐น๐ญ {
} else if false {
} else {
๐๐ฎ๐น๐ฎ, ๐ฒ๐ฟ๐ฟ๐ฎ := func1[int, bool](2)
if ๐ฒ๐ฟ๐ฟ๐ฎ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฎ
}
if a := ๐๐ฎ๐น๐ฎ; a {
} else {
๐๐ฎ๐น๐ฏ, ๐ฒ๐ฟ๐ฟ๐ฏ := func1[int, bool](3)
if ๐ฒ๐ฟ๐ฟ๐ฏ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฏ
}
if ๐๐ฎ๐น๐ฏ {
} else if true {
}
}
} |
Before |
After |
for i := Try(ret1Err[A]());
Try(func1[int, bool](i)); Try(func1[A, C](i)) {
println(i)
} |
๐๐ฎ๐น๐ญ, ๐ฒ๐ฟ๐ฟ๐ญ := ret1Err[A]()
if ๐ฒ๐ฟ๐ฟ๐ญ != nil {
err = ๐ฒ๐ฟ๐ฟ๐ญ
return
}
for i := ๐๐ฎ๐น๐ญ; ; {
๐ฝ๐ผ๐๐๐ญ := func() (_ E๐ฟ๐ฟ๐ผ๐ฟ) {
_, ๐ฒ๐ฟ๐ฟ๐ญ := func1[A, C](i)
if ๐ฒ๐ฟ๐ฟ๐ญ != nil {
return ๐ฒ๐ฟ๐ฟ๐ญ
}
return
}
๐๐ฎ๐น๐ฎ, ๐ฒ๐ฟ๐ฟ๐ฎ := func1[int, bool](i)
if ๐ฒ๐ฟ๐ฟ๐ฎ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฎ
}
if !๐๐ฎ๐น๐ฎ {
break
}
println(i)
๐ฒ๐ฟ๐ฟ๐ฏ := ๐ฝ๐ผ๐๐๐ญ()
if ๐ฒ๐ฟ๐ฟ๐ฏ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฏ
}
} |
Before |
After |
Outer:
for range Try(ret1Err[[]int]()) {
Inner:
for range Try(ret1Err[[]string]()) {
switch a {
case 1:
goto Inner
case 2:
goto Outer
case 3:
break Inner
case 4:
break Outer
case 5:
continue Inner
case 6:
continue Outer
}
}
} |
๐_๐๐ผ๐๐ผ_๐ข๐๐๐ฒ๐ฟ๐ญ:
{
๐๐ฎ๐น๐ญ, ๐ฒ๐ฟ๐ฟ๐ญ := ret1Err[[]int]()
if ๐ฒ๐ฟ๐ฟ๐ญ != nil {
return ๐ฒ๐ฟ๐ฟ๐ญ
}
Outer:
for range ๐๐ฎ๐น๐ญ {
๐_๐๐ผ๐๐ผ_๐๐ป๐ป๐ฒ๐ฟ๐ญ:
{
๐๐ฎ๐น๐ฎ, ๐ฒ๐ฟ๐ฟ๐ฎ := ret1Err[[]string]()
if ๐ฒ๐ฟ๐ฟ๐ฎ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฎ
}
Inner:
for range ๐๐ฎ๐น๐ฎ {
switch a {
case 1:
goto ๐_๐๐ผ๐๐ผ_๐๐ป๐ป๐ฒ๐ฟ๐ญ
case 2:
goto ๐_๐๐ผ๐๐ผ_๐ข๐๐๐ฒ๐ฟ๐ญ
case 3:
break Inner
case 4:
break Outer
case 5:
continue Inner
case 6:
continue Outer
}
}
}
}
} |
Before |
After |
switch i := Try(func1[int, A](0)); Try(func1[int, A](i)) {
case Try(func1[int, B](i)):
println("B")
case id[int](i):
println("C")
case Try(func1[int, D](i)):
println("D1")
case id[int](i):
println("E")
case Try(func1[int, D](i)):
println("D2")
default:
println("default")
} |
{
๐๐ฎ๐น๐ฎ, ๐ฒ๐ฟ๐ฟ๐ญ := func1[int, A](0)
if ๐ฒ๐ฟ๐ฟ๐ญ != nil {
return ๐ฒ๐ฟ๐ฟ๐ญ
}
i := ๐๐ฎ๐น๐ฎ
๐๐ฎ๐น๐ฏ, ๐ฒ๐ฟ๐ฟ๐ฎ := func1[int, A](i)
if ๐ฒ๐ฟ๐ฟ๐ฎ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฎ
}
๐๐ฎ๐น๐ญ := ๐๐ฎ๐น๐ฏ
๐๐ฎ๐น๐ฐ, ๐ฒ๐ฟ๐ฟ๐ฏ := func1[int, B](i)
if ๐ฒ๐ฟ๐ฟ๐ฏ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฏ
}
if ๐๐ฎ๐น๐ญ == ๐๐ฎ๐น๐ฐ {
println("B")
} else if ๐๐ฎ๐น๐ญ == id[int](i) {
println("C")
} else {
๐๐ฎ๐น๐ฑ, ๐ฒ๐ฟ๐ฟ๐ฐ := func1[int, D](i)
if ๐ฒ๐ฟ๐ฟ๐ฐ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฐ
}
if ๐๐ฎ๐น๐ญ == ๐๐ฎ๐น๐ฑ {
println("D1")
} else if ๐๐ฎ๐น๐ญ == id[int](i) {
println("E")
} else {
๐๐ฎ๐น๐ฒ, ๐ฒ๐ฟ๐ฟ๐ฑ := func1[int, D](i)
if ๐ฒ๐ฟ๐ฟ๐ฑ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฑ
}
if ๐๐ฎ๐น๐ญ == ๐๐ฎ๐น๐ฒ {
println("D2")
} else {
println("default")
}
}
}
} |
Before |
After |
outer:
switch {
case Try(func1[int, A](1)) == 42:
println("outer")
inner:
switch {
case Try(func1[int, B](1)) == 42:
break inner
case Try(func1[int, C](1)) == 42:
goto inner
case Try(func1[int, D](1)) == 42:
println("inner")
break outer
case Try(func1[int, E](1)) == 42:
println("inner")
goto outer
}
default:
println("default")
} |
outer:
{
๐๐ฎ๐น๐ญ, ๐ฒ๐ฟ๐ฟ๐ญ := func1[int, A](1)
if ๐ฒ๐ฟ๐ฟ๐ญ != nil {
return ๐ฒ๐ฟ๐ฟ๐ญ
}
if ๐๐ฎ๐น๐ญ == 42 {
println("outer")
inner:
{
๐๐ฎ๐น๐ฎ, ๐ฒ๐ฟ๐ฟ๐ฎ := func1[int, B](1)
if ๐ฒ๐ฟ๐ฟ๐ฎ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฎ
}
if ๐๐ฎ๐น๐ฎ == 42 {
goto ๐_๐๐ฟ๐ธ๐ง๐ผ_๐ถ๐ป๐ป๐ฒ๐ฟ๐ญ
} else {
๐๐ฎ๐น๐ฏ, ๐ฒ๐ฟ๐ฟ๐ฏ := func1[int, C](1)
if ๐ฒ๐ฟ๐ฟ๐ฏ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฏ
}
if ๐๐ฎ๐น๐ฏ == 42 {
goto inner
} else {
๐๐ฎ๐น๐ฐ, ๐ฒ๐ฟ๐ฟ๐ฐ := func1[int, D](1)
if ๐ฒ๐ฟ๐ฟ๐ฐ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฐ
}
if ๐๐ฎ๐น๐ฐ == 42 {
println("inner")
goto ๐_๐๐ฟ๐ธ๐ง๐ผ_๐ผ๐๐๐ฒ๐ฟ๐ญ
} else {
๐๐ฎ๐น๐ฑ, ๐ฒ๐ฟ๐ฟ๐ฑ := func1[int, E](1)
if ๐ฒ๐ฟ๐ฟ๐ฑ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฑ
}
if ๐๐ฎ๐น๐ฑ == 42 {
println("inner")
goto outer
}
}
}
}
๐_๐๐ฟ๐ธ๐ง๐ผ_๐ถ๐ป๐ป๐ฒ๐ฟ๐ญ:
}
} else {
println("default")
}
๐_๐๐ฟ๐ธ๐ง๐ผ_๐ผ๐๐๐ฒ๐ฟ๐ญ:
} |
Before |
After |
type (
A = int
B = int
C = int
D = int
E = int
F = int
)
switch i {
case Try(ret1Err[A]()):
Try(ret1Err[B]())
fallthrough
case Try(ret1Err[C]()):
Try(ret1Err[D]())
fallthrough
case Try(ret1Err[E]()):
Try(ret1Err[F]())
} |
type (
A = int
B = int
C = int
D = int
E = int
F = int
)
{
๐๐ฎ๐น๐ญ := i
๐๐ฎ๐น๐ฎ, ๐ฒ๐ฟ๐ฟ๐ญ := ret1Err[A]()
if ๐ฒ๐ฟ๐ฟ๐ญ != nil {
err = ๐ฒ๐ฟ๐ฟ๐ญ
return
}
if ๐๐ฎ๐น๐ญ == ๐๐ฎ๐น๐ฎ {
{
_, ๐ฒ๐ฟ๐ฟ๐ฎ := ret1Err[B]()
if ๐ฒ๐ฟ๐ฟ๐ฎ != nil {
err = ๐ฒ๐ฟ๐ฟ๐ฎ
return
}
}
{
_, ๐ฒ๐ฟ๐ฟ๐ฏ := ret1Err[D]()
if ๐ฒ๐ฟ๐ฟ๐ฏ != nil {
err = ๐ฒ๐ฟ๐ฟ๐ฏ
return
}
}
{
_, ๐ฒ๐ฟ๐ฟ๐ฐ := ret1Err[F]()
if ๐ฒ๐ฟ๐ฟ๐ฐ != nil {
err = ๐ฒ๐ฟ๐ฟ๐ฐ
return
}
}
} else {
๐๐ฎ๐น๐ฏ, ๐ฒ๐ฟ๐ฟ๐ฑ := ret1Err[C]()
if ๐ฒ๐ฟ๐ฟ๐ฑ != nil {
err = ๐ฒ๐ฟ๐ฟ๐ฑ
return
}
if ๐๐ฎ๐น๐ญ == ๐๐ฎ๐น๐ฏ {
{
_, ๐ฒ๐ฟ๐ฟ๐ฒ := ret1Err[D]()
if ๐ฒ๐ฟ๐ฟ๐ฒ != nil {
err = ๐ฒ๐ฟ๐ฟ๐ฒ
return
}
}
{
_, ๐ฒ๐ฟ๐ฟ๐ณ := ret1Err[F]()
if ๐ฒ๐ฟ๐ฟ๐ณ != nil {
err = ๐ฒ๐ฟ๐ฟ๐ณ
return
}
}
} else {
๐๐ฎ๐น๐ฐ, ๐ฒ๐ฟ๐ฟ๐ด := ret1Err[E]()
if ๐ฒ๐ฟ๐ฟ๐ด != nil {
err = ๐ฒ๐ฟ๐ฟ๐ด
return
}
if ๐๐ฎ๐น๐ญ == ๐๐ฎ๐น๐ฐ {
_, ๐ฒ๐ฟ๐ฟ๐ต := ret1Err[F]()
if ๐ฒ๐ฟ๐ฟ๐ต != nil {
err = ๐ฒ๐ฟ๐ฟ๐ต
return
}
}
}
}
} |
Before |
After |
type (
A = int
B = int
C = int
D = int
E = int
F = int
G = int
H = int
)
select {
case <-Try(ret1Err[chan A]()):
case *Try(ret1Err[*B]()), *Try(ret1Err[*bool]()) =
<-Try(ret1Err[chan C]()):
case Try(ret1Err[chan D]())
<- Try(ret1Err[E]()):
case Try(ret1Err[[]F]())[Try(ret1Err[G]())] =
<-Try(ret1Err[chan H]()):
default:
} |
type (
A = int
B = int
C = int
D = int
E = int
F = int
G = int
H = int
)
๐๐ฎ๐น๐ญ, ๐ฒ๐ฟ๐ฟ๐ญ := ret1Err[chan A]()
if ๐ฒ๐ฟ๐ฟ๐ญ != nil {
return ๐ฒ๐ฟ๐ฟ๐ญ
}
๐๐ฎ๐น๐ฎ, ๐ฒ๐ฟ๐ฟ๐ฎ := ret1Err[chan C]()
if ๐ฒ๐ฟ๐ฟ๐ฎ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฎ
}
๐๐ฎ๐น๐ฒ, ๐ฒ๐ฟ๐ฟ๐ฑ := ret1Err[chan D]()
if ๐ฒ๐ฟ๐ฟ๐ฑ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฑ
}
๐๐ฎ๐น๐ณ, ๐ฒ๐ฟ๐ฟ๐ฒ := ret1Err[E]()
if ๐ฒ๐ฟ๐ฟ๐ฒ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฒ
}
๐๐ฎ๐น๐ด, ๐ฒ๐ฟ๐ฟ๐ณ := ret1Err[chan H]()
if ๐ฒ๐ฟ๐ฟ๐ณ != nil {
return ๐ฒ๐ฟ๐ฟ๐ณ
}
select {
case <-๐๐ฎ๐น๐ญ:
case ๐๐ฎ๐น๐ฐ, ๐ผ๐ธ๐ญ := <-๐๐ฎ๐น๐ฎ:
๐๐ฎ๐น๐ฏ, ๐ฒ๐ฟ๐ฟ๐ฏ := ret1Err[*B]()
if ๐ฒ๐ฟ๐ฟ๐ฏ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฏ
}
*๐๐ฎ๐น๐ฏ = ๐๐ฎ๐น๐ฐ
๐๐ฎ๐น๐ฑ, ๐ฒ๐ฟ๐ฟ๐ฐ := ret1Err[*bool]()
if ๐ฒ๐ฟ๐ฟ๐ฐ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฐ
}
*๐๐ฎ๐น๐ฑ = ๐ผ๐ธ๐ญ
case ๐๐ฎ๐น๐ฒ <- ๐๐ฎ๐น๐ณ:
case ๐๐ฎ๐น๐ญ๐ญ := <-๐๐ฎ๐น๐ด:
๐๐ฎ๐น๐ต, ๐ฒ๐ฟ๐ฟ๐ด := ret1Err[[]F]()
if ๐ฒ๐ฟ๐ฟ๐ด != nil {
return ๐ฒ๐ฟ๐ฟ๐ด
}
๐๐ฎ๐น๐ญ๐ฌ, ๐ฒ๐ฟ๐ฟ๐ต := ret1Err[G]()
if ๐ฒ๐ฟ๐ฟ๐ต != nil {
return ๐ฒ๐ฟ๐ฟ๐ต
}
๐๐ฎ๐น๐ต[๐๐ฎ๐น๐ญ๐ฌ] = ๐๐ฎ๐น๐ญ๐ญ
default:
} |
Before |
After |
L:
var a = Try(ret1Err[int]())
goto L
println(a) |
L:
๐๐ฎ๐น๐ญ, ๐ฒ๐ฟ๐ฟ๐ญ := ret1Err[int]()
if ๐ฒ๐ฟ๐ฟ๐ญ != nil {
return ๐ฒ๐ฟ๐ฟ๐ญ
}
var a = ๐๐ฎ๐น๐ญ
goto L
println(a) |
Before |
After |
*id(&i) = Try(ret1Err[int]()) |
๐๐ฎ๐น๐ญ := id(&i)
๐๐ฎ๐น๐ฎ, ๐ฒ๐ฟ๐ฟ๐ญ := ret1Err[int]()
if ๐ฒ๐ฟ๐ฟ๐ญ != nil {
return
}
*๐๐ฎ๐น๐ญ = ๐๐ฎ๐น๐ฎ |
Before |
After |
// panic when writting nil map
{
var m map[int]int
m[Try(ret1Err[int]())] = 1
}
// won't panic when reading nil map
{
var m map[int]int
println(m[0], Try(ret1Err[int]()))
}
// panic when reading map[any]T
{
var m map[any]int
println(m[0], Try(ret1Err[int]()))
} |
{
var m map[int]int
๐๐ฎ๐น๐ญ, ๐ฒ๐ฟ๐ฟ๐ญ := ret1Err[int]()
if ๐ฒ๐ฟ๐ฟ๐ญ != nil {
return ๐ฒ๐ฟ๐ฟ๐ญ
}
m[๐๐ฎ๐น๐ญ] = 1
}
{
var m map[int]int
๐๐ฎ๐น๐ฎ, ๐ฒ๐ฟ๐ฟ๐ฎ := ret1Err[int]()
if ๐ฒ๐ฟ๐ฟ๐ฎ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฎ
}
println(m[0], ๐๐ฎ๐น๐ฎ)
}
{
var m map[any]int
๐๐ฎ๐น๐ฏ := m[0]
๐๐ฎ๐น๐ฐ, ๐ฒ๐ฟ๐ฟ๐ฏ := ret1Err[int]()
if ๐ฒ๐ฟ๐ฟ๐ฏ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฏ
}
println(๐๐ฎ๐น๐ฏ, ๐๐ฎ๐น๐ฐ)
} |
Before |
After |
expr, ok := Try(ret1Err[ast.Node]()).(ast.Expr)
_, _ = expr, ok |
๐๐ฎ๐น๐ญ, ๐ฒ๐ฟ๐ฟ๐ญ := ret1Err[ast.Node]()
if ๐ฒ๐ฟ๐ฟ๐ญ != nil {
return ๐ฒ๐ฟ๐ฟ๐ญ
}
expr, ok := ๐๐ฎ๐น๐ญ.(ast.Expr)
_, _ = expr, ok |
Before |
After |
_, _ = map[int]int{}[Try(ret1Err[int]())] |
๐๐ฎ๐น๐ญ, ๐ฒ๐ฟ๐ฟ๐ญ := ret1Err[int]()
if ๐ฒ๐ฟ๐ฟ๐ญ != nil {
return ๐ฒ๐ฟ๐ฟ๐ญ
}
_, _ = map[int]int{}[๐๐ฎ๐น๐ญ] |
Before |
After |
func rewrite_ptr_selector_expr() error {
var x *ast.CallExpr
{
// MAY PANIC
consume2(x.Args, Try(ret1Err[string]()))
}
{
// MUST NOT PANIC
consume2(x.Pos, Try(ret1Err[string]()))
}
{
// MAY PANIC
consume2(x.Pos(), Try(ret1Err[string]()))
}
return nil
}
func rewrite_iface_selector_expr() error {
var x ast.Node
{
// MAY PANIC
consume2(x.Pos, Try(ret1Err[string]()))
}
{
// MAY PANIC
consume2(x.Pos(), Try(ret1Err[string]()))
}
return nil
} |
func rewrite_ptr_selector_expr() error {
var x *ast.CallExpr
{
๐๐ฎ๐น๐ญ := x.Args
๐๐ฎ๐น๐ฎ, ๐ฒ๐ฟ๐ฟ๐ญ := ret1Err[string]()
if ๐ฒ๐ฟ๐ฟ๐ญ != nil {
return ๐ฒ๐ฟ๐ฟ๐ญ
}
consume2(๐๐ฎ๐น๐ญ, ๐๐ฎ๐น๐ฎ)
}
{
๐๐ฎ๐น๐ฏ, ๐ฒ๐ฟ๐ฟ๐ฎ := ret1Err[string]()
if ๐ฒ๐ฟ๐ฟ๐ฎ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฎ
}
consume2(x.Pos, ๐๐ฎ๐น๐ฏ)
}
{
๐๐ฎ๐น๐ฐ := x.Pos()
๐๐ฎ๐น๐ฑ, ๐ฒ๐ฟ๐ฟ๐ฏ := ret1Err[string]()
if ๐ฒ๐ฟ๐ฟ๐ฏ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฏ
}
consume2(๐๐ฎ๐น๐ฐ, ๐๐ฎ๐น๐ฑ)
}
return nil
}
func rewrite_iface_selector_expr() error {
var x ast.Node
{
๐๐ฎ๐น๐ญ := x.Pos
๐๐ฎ๐น๐ฎ, ๐ฒ๐ฟ๐ฟ๐ญ := ret1Err[string]()
if ๐ฒ๐ฟ๐ฟ๐ญ != nil {
return ๐ฒ๐ฟ๐ฟ๐ญ
}
consume2(๐๐ฎ๐น๐ญ, ๐๐ฎ๐น๐ฎ)
}
{
๐๐ฎ๐น๐ฏ := x.Pos()
๐๐ฎ๐น๐ฐ, ๐ฒ๐ฟ๐ฟ๐ฎ := ret1Err[string]()
if ๐ฒ๐ฟ๐ฟ๐ฎ != nil {
return ๐ฒ๐ฟ๐ฟ๐ฎ
}
consume2(๐๐ฎ๐น๐ฏ, ๐๐ฎ๐น๐ฐ)
}
return nil
} |
Before |
After |
type X struct{ x int }
{
var x X
_ = x.x + Try(ret1Err[int]())
}
{
var x *X
_ = x.x + Try(ret1Err[int]())
} |
type X struct{ x int }
{
var x X
๐๐ฎ๐น๐ญ, ๐ฒ๐ฟ๐ฟ๐ญ := ret1Err[int]()
if ๐ฒ๐ฟ๐ฟ๐ญ != nil {
return
}
_ = x.x + ๐๐ฎ๐น๐ญ
}
{
var x *X
๐๐ฎ๐น๐ฎ := x.x
๐๐ฎ๐น๐ฏ, ๐ฒ๐ฟ๐ฟ๐ฎ := ret1Err[int]()
if ๐ฒ๐ฟ๐ฟ๐ฎ != nil {
return
}
_ = ๐๐ฎ๐น๐ฎ + ๐๐ฎ๐น๐ฏ
} |