𝐖𝐡𝐚𝐭 𝐢𝐬 𝕘𝕠-𝕥𝕣𝕪
A source to source translator for error-propagating in golang.
The implementation of Proposal: A built-in Go error check function, try.
Quick Start
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.
Example
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)...)
}
}Translating Examples
prelude
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)...)
}
}Error Handling
|
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
} |
Order of Evaluation
|
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(𝘃𝗮𝗹𝟲 + 𝘃𝗮𝗹𝟳 + 𝘃𝗮𝗹𝟴) |
Logical Operator Or
|
Before |
After |
_ = id(true) || Try(func1[int, bool](2)) || id(false) |
𝘃𝗮𝗹𝟭 := id(true)
if !𝘃𝗮𝗹𝟭 {
𝘃𝗮𝗹𝟮, 𝗲𝗿𝗿𝟭 := func1[int, bool](2)
if 𝗲𝗿𝗿𝟭 != nil {
return 𝗲𝗿𝗿𝟭
}
𝘃𝗮𝗹𝟭 = 𝘃𝗮𝗹𝟮
}
if !𝘃𝗮𝗹𝟭 {
𝘃𝗮𝗹𝟭 = id(false)
}
_ = 𝘃𝗮𝗹𝟭 |
Logical Operator And
|
Before |
After |
_ = id(true) && Try(func1[int, bool](2)) && id(false) |
𝘃𝗮𝗹𝟭 := id(true)
if 𝘃𝗮𝗹𝟭 {
𝘃𝗮𝗹𝟮, 𝗲𝗿𝗿𝟭 := func1[int, bool](2)
if 𝗲𝗿𝗿𝟭 != nil {
return 𝗲𝗿𝗿𝟭
}
𝘃𝗮𝗹𝟭 = 𝘃𝗮𝗹𝟮
}
if 𝘃𝗮𝗹𝟭 {
𝘃𝗮𝗹𝟭 = id(false)
}
_ = 𝘃𝗮𝗹𝟭 |
If Stmt
|
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 {
}
}
} |
For Stmt
|
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 𝗲𝗿𝗿𝟯
}
} |
Range Stmt
|
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
}
}
}
}
} |
Switch Stmt
|
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")
}
}
}
} |
Switch Stmt
|
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")
}
𝗟_𝗕𝗿𝗸𝗧𝗼_𝗼𝘂𝘁𝗲𝗿𝟭:
} |
Switch Stmt
|
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
}
}
}
}
} |
Select Stmt
|
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:
} |
Goto Stmt
|
Before |
After |
L:
var a = Try(ret1Err[int]())
goto L
println(a) |
L:
𝘃𝗮𝗹𝟭, 𝗲𝗿𝗿𝟭 := ret1Err[int]()
if 𝗲𝗿𝗿𝟭 != nil {
return 𝗲𝗿𝗿𝟭
}
var a = 𝘃𝗮𝗹𝟭
goto L
println(a) |
Assign Stmt
|
Before |
After |
*id(&i) = Try(ret1Err[int]()) |
𝘃𝗮𝗹𝟭 := id(&i)
𝘃𝗮𝗹𝟮, 𝗲𝗿𝗿𝟭 := ret1Err[int]()
if 𝗲𝗿𝗿𝟭 != nil {
return
}
*𝘃𝗮𝗹𝟭 = 𝘃𝗮𝗹𝟮 |
Map Index Expr
|
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(𝘃𝗮𝗹𝟯, 𝘃𝗮𝗹𝟰)
} |
Type Assert
|
Before |
After |
expr, ok := Try(ret1Err[ast.Node]()).(ast.Expr)
_, _ = expr, ok |
𝘃𝗮𝗹𝟭, 𝗲𝗿𝗿𝟭 := ret1Err[ast.Node]()
if 𝗲𝗿𝗿𝟭 != nil {
return 𝗲𝗿𝗿𝟭
}
expr, ok := 𝘃𝗮𝗹𝟭.(ast.Expr)
_, _ = expr, ok |
Tuple Assign
|
Before |
After |
_, _ = map[int]int{}[Try(ret1Err[int]())] |
𝘃𝗮𝗹𝟭, 𝗲𝗿𝗿𝟭 := ret1Err[int]()
if 𝗲𝗿𝗿𝟭 != nil {
return 𝗲𝗿𝗿𝟭
}
_, _ = map[int]int{}[𝘃𝗮𝗹𝟭] |
Selector Expr
|
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
} |
Runtime Panic
|
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
}
_ = 𝘃𝗮𝗹𝟮 + 𝘃𝗮𝗹𝟯
} |
On this page
Contributors
MIT License
Created February 11, 2024
Updated May 10, 2024