Repository: traefik/yaegi (Go)

Issue:
Type alias
The following program `sample.go` triggers a panic:

```go
package main

import "fmt"

type Root struct {
	Name string
}

func (r *Root) Hello() {
	fmt.Println("Hello", r.Name)
}

type One = Root

type Hi interface {
	Hello()
}

func main() {
	one := &One{Name: "test"}

	fmt.Println(one)
}

// Output:
// &{test}

```

Expected result:
```console
$ go run ./sample.go
&{test}
```

Got:
```console
$ dyngo ./sample.go
panic: reflect: call of reflect.Append on struct Value [recovered]
	panic: reflect: call of reflect.Append on struct Value

goroutine 1 [running]:
github.com/containous/dyngo/interp.runCfg.func1(0xc00019a500)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:103 +0x134
panic(0xbdc840, 0xc000188b80)
	/home/ldez/.gvm/gos/go1.11.5/src/runtime/panic.go:513 +0x1b9
reflect.flag.mustBe(0x199, 0x17)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/value.go:207 +0xb4
reflect.Append(0xc000207020, 0xc00018c8c0, 0x199, 0xc00021dd10, 0x1, 0x1, 0x0, 0x23, 0x7463757274732a2a)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/value.go:1891 +0x3e
github.com/containous/dyngo/interp.arrayLit.func2(0xc00019a500, 0xc000194640)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:944 +0x11d
github.com/containous/dyngo/interp.runCfg(0xc00025c360, 0xc00019a500)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:108 +0x62
github.com/containous/dyngo/interp.(*Interpreter).run(0xc000208070, 0xc00025b680, 0xc00019a4b0)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:90 +0xa6
github.com/containous/dyngo/interp.(*Interpreter).Eval(0xc000208070, 0xc00020c000, 0xff, 0xca583f, 0x4, 0xc000208070, 0x0, 0x115f2e0)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:236 +0x4c3
main.main()
	/home/ldez/sources/go/src/github.com/containous/dyngo/dyngo.go:50 +0x334
exit status 2

```



Discussion:

Patch:
diff --git a/interp/cfg.go b/interp/cfg.go
index 17c3f5557..63fae686e 100644
--- a/interp/cfg.go
+++ b/interp/cfg.go
@@ -643,20 +643,7 @@ func (interp *Interpreter) Cfg(root *Node) ([]*Node, error) {
 				n.findex = scope.add(n.typ)
 			}
 			// TODO: Check that composite literal expr matches corresponding type
-			switch n.typ.cat {
-			case ArrayT:
-				n.gen = arrayLit
-			case MapT:
-				n.gen = mapLit
-			case StructT:
-				if n.lastChild().kind == KeyValueExpr {
-					n.gen = compositeSparse
-				} else {
-					n.gen = compositeLit
-				}
-			case ValueT:
-				n.gen = compositeBin
-			}
+			n.gen = compositeGenerator(n)
 
 		case Continue:
 			n.tnext = loopRestart
@@ -1384,3 +1371,24 @@ func typeSwichAssign(n *Node) bool {
 	ts := n.anc.anc.anc
 	return ts.kind == TypeSwitch && ts.child[1].action == Assign
 }
+
+func compositeGenerator(n *Node) (gen BuiltinGenerator) {
+	switch n.typ.cat {
+	case AliasT:
+		n.typ = n.typ.val
+		gen = compositeGenerator(n)
+	case ArrayT:
+		gen = arrayLit
+	case MapT:
+		gen = mapLit
+	case StructT:
+		if n.lastChild().kind == KeyValueExpr {
+			gen = compositeSparse
+		} else {
+			gen = compositeLit
+		}
+	case ValueT:
+		gen = compositeBin
+	}
+	return
+}
diff --git a/interp/run.go b/interp/run.go
index e4eb73f69..ff8e224e6 100644
--- a/interp/run.go
+++ b/interp/run.go
@@ -1115,7 +1115,11 @@ func compositeSparse(n *Node) {
 	for _, c := range child {
 		field := n.typ.fieldIndex(c.child[0].ident)
 		convertLiteralValue(c.child[1], n.typ.field[field].typ.TypeOf())
-		values[field] = genValue(c.child[1])
+		if c.typ.cat == FuncT {
+			values[field] = genNodeWrapper(c.child[1])
+		} else {
+			values[field] = genValue(c.child[1])
+		}
 	}
 
 	n.exec = func(f *Frame) Builtin {


Test patch:
diff --git a/_test/alias0.go b/_test/alias0.go
new file mode 100644
index 000000000..4186ce369
--- /dev/null
+++ b/_test/alias0.go
@@ -0,0 +1,37 @@
+package main
+
+import "fmt"
+
+type Root struct {
+	Name string
+}
+
+func (r *Root) Hello() {
+	fmt.Println("Hello", r.Name)
+}
+
+type One = Root
+
+func main() {
+	one := &One{Name: "one"}
+	displayOne(one)
+	displayRoot(one)
+
+	root := &Root{Name: "root"}
+	displayOne(root)
+	displayRoot(root)
+}
+
+func displayOne(val *One) {
+	fmt.Println(val)
+}
+
+func displayRoot(val *Root) {
+	fmt.Println(val)
+}
+
+// Output:
+// &{one}
+// &{one}
+// &{root}
+// &{root}
diff --git a/interp/interp_test.go b/interp/interp_test.go
index 8d8ad79a3..1a149f37f 100644
--- a/interp/interp_test.go
+++ b/interp/interp_test.go
@@ -519,6 +519,54 @@ func main() {
 	// [1]
 }
 
+func Example_alias0() {
+	src := `
+package main
+
+import "fmt"
+
+type Root struct {
+	Name string
+}
+
+func (r *Root) Hello() {
+	fmt.Println("Hello", r.Name)
+}
+
+type One = Root
+
+func main() {
+	one := &One{Name: "one"}
+	displayOne(one)
+	displayRoot(one)
+
+	root := &Root{Name: "root"}
+	displayOne(root)
+	displayRoot(root)
+}
+
+func displayOne(val *One) {
+	fmt.Println(val)
+}
+
+func displayRoot(val *Root) {
+	fmt.Println(val)
+}
+`
+	i := interp.New(interp.Opt{Entry: "main"})
+	i.Use(stdlib.Value)
+	_, err := i.Eval(src)
+	if err != nil {
+		panic(err)
+	}
+
+	// Output:
+	// &{one}
+	// &{one}
+	// &{root}
+	// &{root}
+}
+
 func Example_and() {
 	src := `
 package main