Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

recursive type error cases: call of reflect.Value.Interface on zero Value #133

Closed
flamelx opened this issue Aug 7, 2022 · 6 comments
Closed
Assignees
Labels

Comments

@flamelx
Copy link

flamelx commented Aug 7, 2022

case

package main

import (
	"github.com/cosmos72/gomacro/fast"
)

func main() {
	// case1() // as expected
	// case2() // panic: reflect: call of reflect.Value.Interface on zero Value
	// case3() // panic: reflect: call of reflect.Value.Interface on zero Value
	// case4() // as expected
	// case5() // panic: reflect: call of reflect.Value.Interface on zero Value
	// case6() // as expected
	// case7() // as expected
}
func case1(){
	type RR struct {
		// A *RR diff
		B int
	}
	interp := fast.New()
	interp.DeclType(interp.Comp.TypeOf(RR{}))
	script:=`func Execute()([]*RR,error){
			return nil,nil
		}`
	interp.Eval(script)
}

func case2(){
	type RR struct {
		A *RR // diff
		B int
	}
	interp := fast.New()
	interp.DeclType(interp.Comp.TypeOf(RR{}))
	script:=`func Execute()([]*RR,error){
			return nil,nil
		}`
	interp.Eval(script)
}

func case3(){
	type RR struct {
		A *RR
		B int
	}
	interp := fast.New()
	interp.DeclType(interp.Comp.TypeOf(RR{}))
	script:=`func Execute()[]*RR{ // diff
			return nil
		}`
	interp.Eval(script)
}

func case4(){
	type RR struct {
		A *RR
		B int
	}
	interp := fast.New()
	interp.DeclType(interp.Comp.TypeOf(RR{}))
	script:=`func Execute()[]*RR{ // diff
			var rr []*RR
			return rr
		}`
	interp.Eval(script)
}

func case5(){
	type RR struct {
		A *RR
		B int
	}
	interp := fast.New()
	interp.DeclType(interp.Comp.TypeOf(RR{}))
	script:=`func Execute()([]*RR, error){ // diff
			var rr []*RR 
			return rr,nil
		}`
	interp.Eval(script)
}

func case6(){
	type RR struct {
		A *RR
		B int
	}
	interp := fast.New()
	interp.DeclType(interp.Comp.TypeOf(RR{}))
	script:=`func Execute()(*RR, error){ // diff
			var rr *RR 
			return rr,nil
		}`
	interp.Eval(script)
}

func case7(){
	type RR struct {
		A *RR
		B int
	}
	interp := fast.New()
	interp.DeclType(interp.Comp.TypeOf(RR{}))
	script:=`import "fmt"
	func Execute()([]*RR, error){ // diff
			var rr []*RR 
			return rr,fmt.Errorf("1")
		}`
	interp.Eval(script)
}

description

hi, firstly thank you for a great go interpreter, secondly I encountered unexpected errors while writing case5 above. Here I have made more attempts to give the above example and look forward to your reply.

@cosmos72 cosmos72 self-assigned this Aug 22, 2022
@cosmos72 cosmos72 added the bug label Aug 22, 2022
@cosmos72
Copy link
Owner

Thanks for spotting this!

The Go package reflect has some missing features - namely, it cannot create new recursive types, new interfaces or new named types at runtime.
Gomacro has a package github.com/cosmos72/gomacro/xreflect which emulates such missing features, but it's really complicated and error-prone.
The bugs you found are in such package - I will need some time to find a way to fix them without introducing regressions,
and (possibly) without further complicating it.

@cosmos72
Copy link
Owner

cosmos72 commented Aug 22, 2022

Update: to be precise, there's a flag OptIncomplete that is set in a named type while constructing it.
The flag gets cleared once the named type is complete, but related types (such as pointers to the named type) created while the type is not yet complete, inherit the flag but don't clear it once the named type is completed.
It's a classic cache invalidation bug.

cosmos72 added a commit that referenced this issue Aug 22, 2022
cosmos72 added a commit that referenced this issue Aug 22, 2022
@cosmos72
Copy link
Owner

Fixed in commit 1f88d82
Also, commit af24dc3 adds a test for this issue, to detect any future regression

@flamelx
Copy link
Author

flamelx commented Aug 25, 2022

Great! Thank a million for the prompt fix.

@flamelx
Copy link
Author

flamelx commented Oct 20, 2022

func case8() {
	type RR struct {
		A []*RR // diff
		B int
	}
	interp := fast.New()
	interp.DeclType(interp.Comp.TypeOf(RR{}))
	script := `func Execute()([]*RR,error){
			return nil,nil
		}`
	interp.Eval(script)
}

@cosmos72 The problem still occurs when a field is a slice. Could you help to see it again?

@flamelx
Copy link
Author

flamelx commented Oct 23, 2022

func case8() {
	type RR struct {
		A []*RR // diff
		B int
	}
	interp := fast.New()
	interp.DeclType(interp.Comp.TypeOf(RR{}))
	script := `func Execute()([]*RR,error){
			return nil,nil
		}`
	interp.Eval(script)
}

@cosmos72 The problem still occurs when a field is a slice. Could you help to see it again? :p~

func case9() {
	type RR struct {
		A []*RR // diff
		B int
	}
	interp := fast.New()
	interp.DeclType(interp.Comp.TypeOf(RR{}))
	script := `func Execute()[]*RR{ 
			var rr []*RR
                         r:=&RR{} // r:=&RR{B:1} success
                         rr=append(rr,r)
			return rr
		}`
	interp.Eval(script)
	v, _ := interp.Eval("Execute()")
        // reflect.Value.Convert: value of type []xreflect.Forward cannot be converted to type []*RR
	v[0].Convert(reflect.TypeOf([]*RR{}))
        // success
	v[0].Index(0).Convert(reflect.TypeOf(&RR{}))
}

This is another issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants