Example #1
0
// - test hashcodes are consistent with equals for a range of types
//   (e.g. all types generated by type-checking some body of real code).

import (
	"testing"

	"github.com/gordonklaus/flux/go/types"
	"golang.org/x/tools/go/types/typemap"
)

var (
	tStr      = types.Typ[types.String]             // string
	tPStr1    = types.NewPointer(tStr)              // *string
	tPStr2    = types.NewPointer(tStr)              // *string, again
	tInt      = types.Typ[types.Int]                // int
	tChanInt1 = types.NewChan(types.RecvOnly, tInt) // <-chan int
	tChanInt2 = types.NewChan(types.RecvOnly, tInt) // <-chan int, again
)

func checkEqualButNotIdentical(t *testing.T, x, y types.Type, comment string) {
	if !types.IsIdentical(x, y) {
		t.Errorf("%s: not equal: %s, %s", comment, x, y)
	}
	if x == y {
		t.Errorf("%s: identical: %v, %v", comment, x, y)
	}
}

func TestAxioms(t *testing.T) {
	checkEqualButNotIdentical(t, tPStr1, tPStr2, "tPstr{1,2}")
	checkEqualButNotIdentical(t, tChanInt1, tChanInt2, "tChanInt{1,2}")
Example #2
0
func (r *reader) typ(x ast.Expr) types.Type {
	switch x := x.(type) {
	case *ast.Ident:
		if t, ok := r.scope.LookupParent(x.Name).(*types.TypeName); ok {
			return t.Type
		}
		return types.NewNamed(types.NewTypeName(0, r.pkg, x.Name, nil), types.Typ[types.Invalid], nil) //unknown(t.Obj) == true
	case *ast.SelectorExpr:
		pkg := r.scope.LookupParent(name(x.X)).(*types.PkgName).Pkg
		if t, ok := pkg.Scope().Lookup(x.Sel.Name).(*types.TypeName); ok {
			return t.Type
		}
		return types.NewNamed(types.NewTypeName(0, r.pkg, x.Sel.Name, nil), types.Typ[types.Invalid], nil) //unknown(t.Obj) == true
	case *ast.StarExpr:
		return types.NewPointer(r.typ(x.X))
	case *ast.ArrayType:
		elem := r.typ(x.Elt)
		if x.Len != nil {
			// TODO: x.Len
			return types.NewArray(elem, 0)
		}
		return types.NewSlice(elem)
	case *ast.Ellipsis:
		return types.NewSlice(r.typ(x.Elt))
	case *ast.MapType:
		return types.NewMap(r.typ(x.Key), r.typ(x.Value))
	case *ast.ChanType:
		dir := types.SendRecv
		if x.Dir&ast.SEND == 0 {
			dir = types.RecvOnly
		}
		if x.Dir&ast.RECV == 0 {
			dir = types.SendOnly
		}
		return types.NewChan(dir, r.typ(x.Value))
	case *ast.FuncType:
		var params, results []*types.Var
		for _, f := range x.Params.List {
			t := r.typ(f.Type)
			if f.Names == nil {
				params = append(params, types.NewParam(0, r.pkg, "", t))
			}
			for _, n := range f.Names {
				params = append(params, types.NewParam(0, r.pkg, n.Name, t))
			}
		}
		variadic := false
		if x.Results != nil {
			for _, f := range x.Results.List {
				t := r.typ(f.Type)
				if f.Names == nil {
					results = append(results, types.NewParam(0, r.pkg, "", t))
				}
				for _, n := range f.Names {
					results = append(results, types.NewParam(0, r.pkg, n.Name, t))
				}
				_, variadic = f.Type.(*ast.Ellipsis)
			}
		}
		return types.NewSignature(nil, nil, params, results, variadic)
	case *ast.StructType:
		var fields []*types.Var
		if x.Fields != nil {
			for _, f := range x.Fields.List {
				t := r.typ(f.Type)
				if f.Names == nil {
					fields = append(fields, types.NewField(0, r.pkg, "", t, true))
				}
				for _, n := range f.Names {
					fields = append(fields, types.NewField(0, r.pkg, n.Name, t, false))
				}
			}
		}
		return types.NewStruct(fields, nil)
	case *ast.InterfaceType:
		var methods []*types.Func
		var embeddeds []*types.Named
		if x.Methods != nil {
			for _, f := range x.Methods.List {
				switch t := r.typ(f.Type).(type) {
				case *types.Signature:
					methods = append(methods, types.NewFunc(0, r.pkg, f.Names[0].Name, t))
				case *types.Named:
					embeddeds = append(embeddeds, t)
				}
			}
		}
		return types.NewInterface(methods, embeddeds)
	}
	panic("unreachable")
}