~mna/snow unlisted

31fec457d658ed22bbd21c3cb32a245e2ca76e1d — Martin Angers 9 months ago 985e6c8
pkg/semantic: refactor and finish type-assign for interfaces
M pkg/semantic/semantic.go => pkg/semantic/semantic.go +32 -0
@@ 93,6 93,11 @@ type GenericDecl interface {
	// values. This is so that the caller can loop over the sorted slice and
	// process the map in deterministic order.
	GenInsts() ([]*GenericInst, map[*GenericInst][]Type)

	// Instantiate returns the type of the GenericDecl on which it is called once
	// instantiated by the GenericInst, with the specified Types and the map of
	// generic type to resolved type.
	Instantiate(*GenericInst, []Type, map[*GenericType]Type) Type
}

type commonDecl struct {


@@ 155,6 160,7 @@ type Fn struct {
func (fn *Fn) TypeContext() TypeContext  { return Immutable }
func (fn *Fn) IsGeneric() bool           { return fn.GenericParams != nil }
func (fn *Fn) GenClause() *GenericClause { return fn.GenericParams }

func (fn *Fn) GenInsts() ([]*GenericInst, map[*GenericInst][]Type) {
	gis := make([]*GenericInst, 0, len(fn.GenericInsts))
	for gi := range fn.GenericInsts {


@@ 167,6 173,14 @@ func (fn *Fn) GenInsts() ([]*GenericInst, map[*GenericInst][]Type) {
	return gis, fn.GenericInsts
}

func (fn *Fn) Instantiate(gi *GenericInst, types []Type, resolve map[*GenericType]Type) Type {
	if fn.GenericInsts == nil {
		fn.GenericInsts = make(map[*GenericInst][]Type)
	}
	fn.GenericInsts[gi] = types
	return fn.Type().ResolveGeneric(resolve)
}

type Var struct {
	Ctx      TypeContext // only mutable or immutable for Var, set during translation pass
	TypeExpr Expr        // possibly nil, not a resolved Type, but the Expr assigned to var in `var x: int`


@@ 200,6 214,7 @@ type Struct struct {
func (s *Struct) TypeContext() TypeContext  { return Typ }
func (s *Struct) IsGeneric() bool           { return s.GenericParams != nil }
func (s *Struct) GenClause() *GenericClause { return s.GenericParams }

func (s *Struct) GenInsts() ([]*GenericInst, map[*GenericInst][]Type) {
	gis := make([]*GenericInst, 0, len(s.GenericInsts))
	for gi := range s.GenericInsts {


@@ 212,6 227,14 @@ func (s *Struct) GenInsts() ([]*GenericInst, map[*GenericInst][]Type) {
	return gis, s.GenericInsts
}

func (s *Struct) Instantiate(gi *GenericInst, types []Type, resolve map[*GenericType]Type) Type {
	if s.GenericInsts == nil {
		s.GenericInsts = make(map[*GenericInst][]Type)
	}
	s.GenericInsts[gi] = types
	return &StructType{Decl: s, Inst: types}
}

type Interface struct {
	GenericParams *GenericClause          // set during translation pass
	GenericInsts  map[*GenericInst][]Type // set during type-assign pass, each distinct instantiation is recorded here


@@ 223,6 246,7 @@ type Interface struct {
func (i *Interface) TypeContext() TypeContext  { return Typ }
func (i *Interface) IsGeneric() bool           { return i.GenericParams != nil }
func (i *Interface) GenClause() *GenericClause { return i.GenericParams }

func (i *Interface) GenInsts() ([]*GenericInst, map[*GenericInst][]Type) {
	gis := make([]*GenericInst, 0, len(i.GenericInsts))
	for gi := range i.GenericInsts {


@@ 235,6 259,14 @@ func (i *Interface) GenInsts() ([]*GenericInst, map[*GenericInst][]Type) {
	return gis, i.GenericInsts
}

func (i *Interface) Instantiate(gi *GenericInst, types []Type, resolve map[*GenericType]Type) Type {
	if i.GenericInsts == nil {
		i.GenericInsts = make(map[*GenericInst][]Type)
	}
	i.GenericInsts[gi] = types
	return &InterfaceType{Decl: i, Inst: types}
}

type GenericElem struct {
	commonDecl
}

M pkg/semantic/type.go => pkg/semantic/type.go +67 -10
@@ 72,6 72,10 @@ type (
		// Inst is the list of types used in a generic instantiation, if the
		// interface declaration is generic.
		Inst []Type

		// lookup cache of GenericType to instantiated type, nil until the first
		// call to typeOfSel.
		lookup map[*GenericType]Type
	}

	// GenericType is the type of a generic placeholder, e.g. $T.


@@ 387,11 391,11 @@ func (t *TupleType) typeof(sel *Ident, ctxHint TypeContext) (Type, TypeContext) 
// ========> implement Type for StructType

func (s *StructType) AssignableTo(T Type) bool {
	switch T.(type) {
	switch T := T.(type) {
	case *StructType:
		return s.IdenticalTo(T)
	case *InterfaceType:
		// TODO : struct can be assignable to an interface type if it satisfies it
		return T.isSatisfiedBy(s)
	}
	return false
}


@@ 493,10 497,13 @@ func makeGenericResolveMap(gc *GenericClause, types []Type) map[*GenericType]Typ

// ========> implement Type for InterfaceType

// TODO: should be assignable to any interface type that is a subset
// of this interface (or identical).
// Assignable to any interface type that is a subset of this interface (or
// identical).
func (i *InterfaceType) AssignableTo(T Type) bool {
	return i.IdenticalTo(T)
	if i2 := AsInterfaceType(T); i2 != nil {
		return i2.isSatisfiedBy(i)
	}
	return false
}

// an interface type is valid if all of its methods' types are valid.


@@ 567,18 574,68 @@ func (i *InterfaceType) ResolveGeneric(resolve map[*GenericType]Type) Type {
	return i
}

func (i *InterfaceType) typeof(sel *Ident, ctxHint TypeContext) (Type, TypeContext) {
func (i *InterfaceType) typeof(sel *Ident, _ TypeContext) (Type, TypeContext) {
	for _, m := range i.Decl.Methods {
		if m.Ident() == sel.Name {
			// TODO: first, the type must be generic-resolved much like typeOfSel for SturctType,
			// then the TypeContext might not be ok, this would always give immutable (the method
			// is a func decl). Maybe it should be ctxHint? TBD...
			return m.Type(), m.TypeContext()
			return i.typeOfSel(m.Type()), m.TypeContext()
		}
	}
	return nil, Invalid
}

// typeOfSel returns the actual type of a selection inside the interface.
// If the method is not generic, then T is returned unchanged, otherwise
// if T is a GenericType it is replaced by the type of its corresponding
// instantiation.
func (i *InterfaceType) typeOfSel(T Type) Type {
	if !i.Decl.IsGeneric() {
		return T
	}

	if i.lookup == nil {
		i.lookup = makeGenericResolveMap(i.Decl.GenericParams, i.Inst)
	}
	return T.ResolveGeneric(i.lookup)
}

// TODO: eventually, for better error reporting, should return the missing method names
// or the invalid method types. Could also return the mapping of functions on T that
// satisfy each required method of i, might be useful in later stages.
func (i *InterfaceType) isSatisfiedBy(T Type) bool {
	var (
		tfns    []*Fn
		resolve func(Type) Type
	)

	switch T := T.(type) {
	case *StructType:
		tfns = T.Decl.Fns
		resolve = T.typeOfSel
	case *InterfaceType:
		tfns = T.Decl.Methods
		resolve = T.typeOfSel
	default:
		return false
	}

	// build the map of required fn names to corresponding type
	req := make(map[string]Type, len(i.Decl.Methods))
	for _, m := range i.Decl.Methods {
		req[m.Ident()] = i.typeOfSel(m.Type())
	}

	for _, fn := range tfns {
		// if this fn is part of the required methods set, check if the types match
		if reqt := req[fn.Ident()]; reqt != nil {
			if !reqt.IdenticalTo(resolve(fn.Type())) {
				return false
			}
			delete(req, fn.Ident())
		}
	}
	return len(req) == 0
}

// ========> implement Type for GenericType

func (g *GenericType) String() string { return g.Name }

M pkg/semantic/typeassign_pass.go => pkg/semantic/typeassign_pass.go +1 -19
@@ 331,25 331,7 @@ func (t *typeassignVisitor) instantiateGeneric(gi *GenericInst, gen GenericDecl,
	if count := len(types); count < len(gc.Elems) || len(types) > len(gc.Elems) {
		t.errh(gi.Pos(), fmt.Sprintf("wrong number of types provided in generic instantiation, want %d, got %d", len(gc.Elems), len(types)))
	}

	// TODO: need to support Interface too, could be methods on the semantic.Decl instead
	switch gen := gen.(type) {
	case *Fn:
		if gen.GenericInsts == nil {
			gen.GenericInsts = make(map[*GenericInst][]Type)
		}
		gen.GenericInsts[gi] = types
		return gen.Type().ResolveGeneric(resolve)
	case *Struct:
		if gen.GenericInsts == nil {
			gen.GenericInsts = make(map[*GenericInst][]Type)
		}
		gen.GenericInsts[gi] = types
		return &StructType{Decl: gen, Inst: types}
	default:
		t.errh(gi.Pos(), fmt.Sprintf("invalid generic declaration type: %T", gen))
	}
	return unresolvedType{}
	return gen.Instantiate(gi, types, resolve)
}

func (t *typeassignVisitor) typeAssignGenericInst(gi *GenericInst) {

M pkg/semantic/typecheck_pass.go => pkg/semantic/typecheck_pass.go +0 -2
@@ 422,8 422,6 @@ func (t *typecheckVisitor) Visit(n Node) Visitor {
	case *GenericInst:
		var T Type
		t.expectTypeCtx(n, &T, Typ, Value)
		// TODO: Number of types already validated in type-assign, only check
		// remaining would be the constraints, when we add that.
		// TODO: also, should the number of types be validated here instead? Conceptually would make more sense.

	case *Ident: