func TestMismatchCompType(t *testing.T) {
	incompat := `(new a,b)(a(b,c).0 | a<>)`
	proc, err := asyncpi.Parse(strings.NewReader(incompat))
	if err != nil {
		t.Fatal(err)
	}
	if err := Infer(proc); err != nil {
		t.Fatal(err)
	}
	err = Unify(proc)
	if err, ok := err.(errors.Causer); ok {
		if _, ok := err.Cause().(*TypeArityError); !ok {
			t.Fatalf("Unify: Expecting type error (mismatched args in a) but got %v", err)
		}
	}
}
Test mismatched comptype (different number of args).
a,b are concrete, and a is bound. a cannot have both 2 args and 0 args.
both a are compType because of the binding, but the args mismatches.
package types
import (
	"strings"
	"testing"
	"go.nickng.io/asyncpi"
	"go.nickng.io/asyncpi/internal/errors"
)
func TestBasicInferOnly(t *testing.T) {
	input := "(new a)(new b)(new c:T)(a<b,c>|a(y,z).b<z>)"
	atype := "chan struct{e0 chan interface{};e1 T}"
	btype := "chan interface{}"  
	ctype := "T"                 
	ytype := "interface{}"       
	ztype := "interface{}"       
	proc, err := asyncpi.Parse(strings.NewReader(input))
	if err != nil {
		t.Fatal(err)
	}
	Infer(proc)
	resa, ok := proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: expected (new a)P but got `%s`", proc)
	}
	if resa.Name.(TypedName).Type().String() != atype {
		t.Errorf("Infer: expected a typed `%s` but got `%s` %#v",
			atype, resa.Name.(TypedName).Type().String(), resa.Name)
	}
	resb, ok := resa.Proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: expected (new b)P but got `%s`", resa.Proc)
	}
	if resb.Name.(TypedName).Type().String() != btype {
		t.Errorf("Infer: expected b typed `%s` but got `%s`",
			btype, resb.Name.(TypedName).Type().String())
	}
	resc, ok := resb.Proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: expected (new c)P but got `%s`", resb.Proc)
	}
	if resc.Name.(TypedName).Type().String() != ctype {
		t.Errorf("Infer: expected c typed `%s` but got `%s`",
			ctype, resc.Name.(TypedName).Type().String())
	}
	par, ok := resc.Proc.(*asyncpi.Par)
	if !ok {
		t.Errorf("Parse: expected P|Q but got `%s`", resc.Proc)
	}
	recva, ok := par.Procs[1].(*asyncpi.Recv)
	if !ok {
		t.Errorf("Parse: expected a() but got `%s`", par.Procs[1])
	}
	if len(recva.Vars) != 2 {
		t.Errorf("Parse: expected a(y,z) but got a %d-tuple", len(recva.Vars))
	}
	if recva.Vars[0].(TypedName).Type().String() != ytype {
		t.Errorf("Infer: expected y typed `%s` but got `%s`",
			ytype, recva.Vars[0].(TypedName).Type().String())
	}
	sendb, ok := recva.Cont.(*asyncpi.Send)
	if !ok {
		t.Errorf("Parse: expected b<z> but got `%s`", recva.Cont)
	}
	if len(sendb.Vals) != 1 {
		t.Errorf("Parse: expected b<z> but got a %d-tuple", len(sendb.Vals))
	}
	if sendb.Vals[0].(TypedName).Type().String() != ztype {
		t.Errorf("Infer: expected z typed `%s` but got `%s`",
			ztype, sendb.Vals[0].(TypedName).Type().String())
	}
}
func TestBasicInferUnify(t *testing.T) {
	input := "(new a)(new b)(new c:T)(a<b,c>|a(y,z).b<z>)"
	atype := "chan struct{e0 chan T;e1 T}"
	btype := "chan T"  
	ctype := "T"       
	ytype := "chan T"  
	ztype := "T"       
	proc, err := asyncpi.Parse(strings.NewReader(input))
	if err != nil {
		t.Fatal(err)
	}
	Infer(proc)
	Unify(proc)
	resa, ok := proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: expected (new a)P but got `%s`", resa)
	}
	if resa.Name.(TypedName).Type().String() != atype {
		t.Errorf("Infer: expected a typed `%s` but got `%s`",
			atype, resa.Name.(TypedName).Type().String())
	}
	resb, ok := resa.Proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: expected (new b)P but got `%s`", resb)
	}
	if resb.Name.(TypedName).Type().String() != btype {
		t.Errorf("Infer: expected b typed `%s` but got `%s`",
			btype, resb.Name.(TypedName).Type().String())
	}
	resc, ok := resb.Proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: expected (new c)P but got `%s`", resc)
	}
	if resc.Name.(TypedName).Type().String() != ctype {
		t.Errorf("Infer: expected c typed `%s` but got `%s`",
			ctype, resc.Name.(TypedName).Type().String())
	}
	par, ok := resc.Proc.(*asyncpi.Par)
	if !ok {
		t.Errorf("Parse: expected P|Q but got `%s`", par)
	}
	recva, ok := par.Procs[1].(*asyncpi.Recv)
	if !ok {
		t.Errorf("Infer: expected a() but got `%s`", recva)
	}
	if len(recva.Vars) != 2 {
		t.Errorf("Parse: expected a(y,z) but got a %d-tuple", len(recva.Vars))
	}
	if recva.Vars[0].(TypedName).Type().String() != ytype {
		t.Errorf("Infer: expected y typed `%s` but got `%s`",
			ytype, recva.Vars[0].(TypedName).Type().String())
	}
	sendb, ok := recva.Cont.(*asyncpi.Send)
	if !ok {
		t.Errorf("Infer: expected b<z> but got `%s`", sendb)
	}
	if len(sendb.Vals) != 1 {
		t.Errorf("Parse: expected b<z> but got a %d-tuple", len(sendb.Vals))
	}
	if sendb.Vals[0].(TypedName).Type().String() != ztype {
		t.Errorf("Infer: expected z typed `%s` but got `%s`",
			ztype, sendb.Vals[0].(TypedName).Type().String())
	}
}
func TestWrongHintInferOnly(t *testing.T) {
	simple := "(new a:TA)(new b:T)(new c)(a<b,c>|a(x,y).0)"
	atype := "chan struct{e0 T;e1 interface{}}"
	btype := "T"  
	ctype := "interface{}"
	xtype := "interface{}"  
	ytype := "interface{}"  
	proc, err := asyncpi.Parse(strings.NewReader(simple))
	if err != nil {
		t.Fatal(err)
	}
	Infer(proc)
	resa, ok := proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: expected (new a)P but got `%s`", proc)
	}
	if resa.Name.(TypedName).Type().String() != atype {
		t.Errorf("Infer: expected a typed `%s` but got `%s`",
			atype, resa.Name.(TypedName).Type().String())
	}
	resb, ok := resa.Proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: expected (new b)P but got `%s`", resa.Proc)
	}
	if resb.Name.(TypedName).Type().String() != btype {
		t.Errorf("Infer: expected b typed `%s` but got `%s`",
			btype, resb.Name.(TypedName).Type().String())
	}
	resc, ok := resb.Proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse expected (new c)P but got `%s`", resb.Proc)
	}
	if resc.Name.(TypedName).Type().String() != ctype {
		t.Errorf("Infer: expected c typed `%s` but got `%s`",
			ctype, resc.Name.(TypedName).Type().String())
	}
	par, ok := resc.Proc.(*asyncpi.Par)
	if !ok {
		t.Errorf("Parse: expected P|Q but got `%s`", resc.Proc)
	}
	recva, ok := par.Procs[1].(*asyncpi.Recv)
	if !ok {
		t.Errorf("Parse: expected a(x,y) but got `%s`", par.Procs[1])
	}
	if len(recva.Vars) != 2 {
		t.Errorf("Parse: expected a(x,y) but got a %d-tuple", len(recva.Vars))
	}
	if recva.Vars[0].(TypedName).Type().String() != xtype {
		t.Errorf("Infer: expected y typed `%s` but got `%s`",
			xtype, recva.Vars[0].(TypedName).Type().String())
	}
	if recva.Vars[1].(TypedName).Type().String() != ytype {
		t.Errorf("Infer: expected y typed `%s` but got `%s`",
			ytype, recva.Vars[1].(TypedName).Type().String())
	}
}
func TestWrongHintInferUnify(t *testing.T) {
	simple := "(new a:TA)(new b:T)(new c)(a<b,c>|a(x,y).0)"
	atype := "chan struct{e0 T;e1 interface{}}"
	btype := "T"  
	ctype := "interface{}"
	xtype := "T"            
	ytype := "interface{}"  
	proc, err := asyncpi.Parse(strings.NewReader(simple))
	if err != nil {
		t.Fatal(err)
	}
	Infer(proc)
	Unify(proc)
	resa, ok := proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: expected (new a)P but got `%s`", proc)
	}
	if resa.Name.(TypedName).Type().String() != atype {
		t.Errorf("Infer: expected a typed `%s` but got `%s`",
			atype, resa.Name.(TypedName).Type().String())
	}
	resb, ok := resa.Proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: expected (new b)P but got `%s`", resa.Proc)
	}
	if resb.Name.(TypedName).Type().String() != btype {
		t.Errorf("Infer: expected b typed `%s` but got `%s`",
			btype, resb.Name.(TypedName).Type().String())
	}
	resc, ok := resb.Proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse expected (new c)P but got `%s`", resb.Proc)
	}
	if resc.Name.(TypedName).Type().String() != ctype {
		t.Errorf("Infer: expected c typed `%s` but got `%s`",
			ctype, resc.Name.(TypedName).Type().String())
	}
	par, ok := resc.Proc.(*asyncpi.Par)
	if !ok {
		t.Errorf("Parse: expected P|Q but got `%s`", resc.Proc)
	}
	recva, ok := par.Procs[1].(*asyncpi.Recv)
	if !ok {
		t.Errorf("Parse: expected a(x,y) but got `%s`", par.Procs[1])
	}
	if len(recva.Vars) != 2 {
		t.Errorf("Parse: expected a(x,y) but got a %d-tuple", len(recva.Vars))
	}
	if recva.Vars[0].(TypedName).Type().String() != xtype {
		t.Errorf("Infer: expected y typed `%s` but got `%s`",
			xtype, recva.Vars[0].(TypedName).Type().String())
	}
	if recva.Vars[1].(TypedName).Type().String() != ytype {
		t.Errorf("Infer: expected y typed `%s` but got `%s`",
			ytype, recva.Vars[1].(TypedName).Type().String())
	}
}
func TestHigherOrderInferOnly(t *testing.T) {
	input := "(new a)(new b)(a<b>|a(x).x().0)"
	atype := "chan interface{}"  
	btype := "interface{}"       
	xtype := "chan struct{}"
	proc, err := asyncpi.Parse(strings.NewReader(input))
	if err != nil {
		t.Fatal(err)
	}
	Infer(proc)
	resa, ok := proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: expected (new a)P but got `%s`", proc)
	}
	if resa.Name.(TypedName).Type().String() != atype {
		t.Errorf("Infer: expected a typed `%s` but got `%s`",
			atype, resa.Name.(TypedName).Type().String())
	}
	resb, ok := resa.Proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: expected (new b)P but got `%s`", resa.Proc)
	}
	if resb.Name.(TypedName).Type().String() != btype {
		t.Errorf("Infer: expected b typed `%s` but got `%s`",
			btype, resb.Name.(TypedName).Type().String())
	}
	par, ok := resb.Proc.(*asyncpi.Par)
	if !ok {
		t.Errorf("Parse: expected P|Q but got `%s`", resb.Proc)
	}
	recva, ok := par.Procs[1].(*asyncpi.Recv)
	if !ok {
		t.Errorf("Parse: expected a(x) but got `%s`", par.Procs[1])
	}
	if len(recva.Vars) != 1 {
		t.Errorf("Parse: expected a(x) but got a %d-tuple", len(recva.Vars))
	}
	if recva.Vars[0].(TypedName).Type().String() != xtype {
		t.Errorf("Infer: expected x typed `%s` but got `%s`",
			xtype, recva.Vars[0].(TypedName).Type().String())
	}
}
func TestHigherOrderInferUnify(t *testing.T) {
	input := "(new a)(new b)(a<b>|a(x).x().0)"
	atype := "chan chan struct{}"  
	btype := "chan struct{}"       
	xtype := "chan struct{}"
	proc, err := asyncpi.Parse(strings.NewReader(input))
	if err != nil {
		t.Fatal(err)
	}
	Infer(proc)
	Unify(proc)
	resa, ok := proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: expected (new a)P but got `%s`", proc)
	}
	if resa.Name.(TypedName).Type().String() != atype {
		t.Errorf("Infer: expected a typed `%s` but got `%s`",
			atype, resa.Name.(TypedName).Type().String())
	}
	resb, ok := resa.Proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: expected (new b)P but got `%s`", resa.Proc)
	}
	if resb.Name.(TypedName).Type().String() != btype {
		t.Errorf("Infer: expected b typed `%s` but got `%s`",
			btype, resb.Name.(TypedName).Type().String())
	}
	par, ok := resb.Proc.(*asyncpi.Par)
	if !ok {
		t.Errorf("Parse: expected P|Q but got `%s`", resb.Proc)
	}
	recva, ok := par.Procs[1].(*asyncpi.Recv)
	if !ok {
		t.Errorf("Parse: expected a(x) but got `%s`", par.Procs[1])
	}
	if len(recva.Vars) != 1 {
		t.Errorf("Parse: expected a(x) but got a %d-tuple", len(recva.Vars))
	}
	if recva.Vars[0].(TypedName).Type().String() != xtype {
		t.Errorf("Infer: expected x typed `%s` but got `%s`",
			xtype, recva.Vars[0].(TypedName).Type().String())
	}
}
func TestInferUnifyNested(t *testing.T) {
	nested := "(new a)(new b)(new c:T)(a<b,c> | a(y,z).b<c,z>)"
	atype := "chan struct{e0 chan struct{e0 T;e1 T};e1 T}"
	btype := "chan struct{e0 T;e1 T}"
	proc, err := asyncpi.Parse(strings.NewReader(nested))
	if err != nil {
		t.Fatal(err)
	}
	processAttachType(proc)
	resa, ok := proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: `%s` does not begin with restriction", nested)
	}
	if _, ok := resa.Name.(TypedName).Type().(*anyType); !ok {
		t.Errorf("Infer: Type of `a` is not %s\n got: %s",
			atype, resa.Name.(TypedName).Type())
	}
	if err := Infer(proc); err != nil {
		t.Fatal(err)
	}
	if err := Unify(proc); err != nil {
		t.Fatal(err)
	}
	inferredResa, ok := proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: `%s` does not begin with restriction", nested)
	}
	if inferredResa.Name.(TypedName).Type().String() != atype {
		t.Errorf("Infer: Type of `a` is not %s\ngot: %s",
			atype, inferredResa.Name.(TypedName).Type())
	}
	inferredResb, ok := inferredResa.Proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: `%s` does not begin with restriction",
			inferredResa.Calculi())
	}
	if inferredResb.Name.(TypedName).Type().String() != btype {
		t.Errorf("Infer: Type of `b` is not %s\ngot: %s",
			btype, inferredResb.Name.(TypedName).Type())
	}
}
func TestInferUnifyNamePassing(t *testing.T) {
	namePassing := "(new a)(new b)(new c:T)(a<b,c> | a(y,z).y<c,z>)"
	atype := "chan struct{e0 chan struct{e0 T;e1 T};e1 T}"
	btype := "chan struct{e0 T;e1 T}"
	proc, err := asyncpi.Parse(strings.NewReader(namePassing))
	if err != nil {
		t.Fatal(err)
	}
	_, ok := proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: `%s` does not begin with restriction", namePassing)
	}
	if err := Infer(proc); err != nil {
		t.Fatal(err)
	}
	if err := Unify(proc); err != nil {
		t.Fatal(err)
	}
	inferredResa, ok := proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: `%s` does not begin with restriction", namePassing)
	}
	if inferredResa.Name.(TypedName).Type().String() != atype {
		t.Errorf("Infer: Type of `a` is not %s\ngot: %s",
			atype, inferredResa.Name.(TypedName).Type())
	}
	inferredResb, ok := inferredResa.Proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: `%s` does not begin with restriction",
			inferredResa.Calculi())
	}
	if inferredResb.Name.(TypedName).Type().String() != btype {
		t.Errorf("Infer: Type of `b` is not %s\ngot: %s",
			btype, inferredResb.Name.(TypedName).Type())
	}
}
func TestInferNested(t *testing.T) {
	nested := "(new a)(new b)(new c:T)(a<b,c> | a(y,z).y<z>)"
	atype := "chan struct{e0 chan T;e1 T}"
	btype := "chan T"
	proc, err := asyncpi.Parse(strings.NewReader(nested))
	if err != nil {
		t.Fatal(err)
	}
	processAttachType(proc)
	resa, ok := proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: `%s` does not begin with restriction", nested)
	}
	if _, ok := resa.Name.(TypedName).Type().(*anyType); !ok {
		t.Errorf("Infer: Type of `a` is not %s\n got: %s",
			atype, resa.Name.(TypedName).Type())
	}
	if err := Infer(proc); err != nil {
		t.Fatal(err)
	}
	if err := Unify(proc); err != nil {
		t.Fatal(err)
	}
	inferredResa, ok := proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: `%s` does not begin with restriction", nested)
	}
	if inferredResa.Name.(TypedName).Type().String() != atype {
		t.Errorf("Infer: Type of `a` is not %s\ngot: %s",
			atype, inferredResa.Name.(TypedName).Type())
	}
	inferredResb, ok := inferredResa.Proc.(*asyncpi.Restrict)
	if !ok {
		t.Errorf("Parse: `%s` does not begin with restriction",
			inferredResa.Calculi())
	}
	if inferredResb.Name.(TypedName).Type().String() != btype {
		t.Errorf("Infer: Type of `b` is not %s\ngot: %s",
			btype, inferredResb.Name.(TypedName).Type())
	}
}