~mna/snow unlisted

361d6471578e5f95e0d6e909e6942b7684e48be7 — Martin Angers 9 months ago 9e09834
pkg/semantic: start translating and type-assigning interfaces
M pkg/printer/printer.go => pkg/printer/printer.go +9 -0
@@ 185,6 185,15 @@ func (p *semanticPrinter) Visit(n semantic.Node) semantic.Visitor {
		}
		format += "]"
		p.printMsg(fmt.Sprintf(format, args...), true)
	case *semantic.Interface:
		format := "interface %s [%d"
		args := []interface{}{n.Ident(), len(n.Methods)}
		if n.GenericParams != nil {
			format += ", $%d"
			args = append(args, len(n.GenericParams.Elems))
		}
		format += "]"
		p.printMsg(fmt.Sprintf(format, args...), true)
	case *semantic.Block:
		p.printMsg(fmt.Sprintf("block [%d]", len(n.Stmts)), true)
	case *semantic.Return:

M pkg/semantic/scope.go => pkg/semantic/scope.go +1 -1
@@ 101,7 101,7 @@ func newScope(owner Node, parent *Scope) *Scope {
		}
		orderInd = true

	case *Fn, *If, *Guard, *Block:
	case *Fn, *If, *Guard, *Block, *Interface:
		if parent == nil {
			panic(fmt.Sprintf("universe scope created with invalid owner %T", owner))
		}

M pkg/semantic/semantic.go => pkg/semantic/semantic.go +33 -7
@@ 129,9 129,10 @@ type Unit struct {
}

type File struct {
	Vars    []*Var
	Fns     []*Fn
	Structs []*Struct
	Vars       []*Var
	Fns        []*Fn
	Structs    []*Struct
	Interfaces []*Interface
	commonNode
}



@@ 180,14 181,16 @@ func (v *Var) TypeContext() TypeContext { return v.Ctx }
// Struct is also used to declare the pre-defined attributes (currently just
// @extern), even though just Vars can be declared on those. This is TBD if
// it stays this way, but the current thinking is that attributes will be
// structs with a special trait.
// structs with some compiler magic.
type Struct struct {
	GenericParams *GenericClause          // set during translation pass
	GenericInsts  map[*GenericInst][]Type // set during type-assign pass, each distinct instantiation is recorded here

	Vars    []*Var
	Fns     []*Fn
	Structs []*Struct
	Vars       []*Var
	Fns        []*Fn
	Structs    []*Struct
	Interfaces []*Interface

	// BodyScope is the scope for the content of the struct (unlike Struct.Scope
	// which is the scope where the struct is defined).
	BodyScope *Scope


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

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

	Methods []*Fn
	commonDecl
}

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 {
		gis = append(gis, gi)
	}
	sort.Slice(gis, func(i, j int) bool {
		l, r := gis[i], gis[j]
		return l.Pos() < r.Pos()
	})
	return gis, i.GenericInsts
}

type GenericElem struct {
	commonDecl
}

A pkg/semantic/testdata/interface.snow => pkg/semantic/testdata/interface.snow +3 -0
@@ 0,0 1,3 @@
interface I {
  fn foo()
}

A pkg/semantic/testdata/scopes/interface.snow.err => pkg/semantic/testdata/scopes/interface.snow.err +0 -0

A pkg/semantic/testdata/scopes/interface.snow.want => pkg/semantic/testdata/scopes/interface.snow.want +34 -0
@@ 0,0 1,34 @@
1 *semantic.Unit {
.  bool
.  extern
.  f32
.  f64
.  false
.  float
.  i16
.  i32
.  i64
.  i8
.  int
.  string
.  true
.  u16
.  u32
.  u64
.  u8
.  uint
.  void
.  2 *semantic.Struct {
.  .  import
.  .  pkg
.  .  symbol
.  }
.  3 *semantic.File {
.  .  I
.  .  4 *semantic.Interface {
.  .  .  foo
.  .  .  5 *semantic.Fn {
.  .  .  }
.  .  }
.  }
}

A pkg/semantic/testdata/types/interface.snow.err => pkg/semantic/testdata/types/interface.snow.err +0 -0

A pkg/semantic/testdata/types/interface.snow.want => pkg/semantic/testdata/types/interface.snow.want +3 -0
@@ 0,0 1,3 @@
file testdata/interface.snow [0, 0, 0]
  interface I [1] [type: interface I]
    fn foo [let: () -> void]

M pkg/semantic/translate_pass.go => pkg/semantic/translate_pass.go +22 -0
@@ 82,6 82,8 @@ func (t *translateVisitor) Visit(n ast.Node) ast.Visitor {
				f.Fns = append(f.Fns, gn)
			case *Struct:
				f.Structs = append(f.Structs, gn)
			case *Interface:
				f.Interfaces = append(f.Interfaces, gn)
			default:
				panic(fmt.Sprintf("invalid top-level declaration in file: %T", gn))
			}


@@ 196,12 198,32 @@ func (t *translateVisitor) Visit(n ast.Node) ast.Visitor {
				str.Fns = append(str.Fns, gn)
			case *Struct:
				str.Structs = append(str.Structs, gn)
			case *Interface:
				str.Interfaces = append(str.Interfaces, gn)
			default:
				panic(fmt.Sprintf("invalid declaration in struct %s: %T", str.ident, gn))
			}
		}
		t.generated = &str

	case *ast.InterfaceDecl:
		var iface Interface
		iface.pos = n.Name.Pos()
		iface.scope = t.scope
		iface.ident = n.Name.Name
		t.registerSymbol(n.Name, &iface, token.Interface.String())

		tt := t.cloneNewScope(&iface)
		if gp := n.GenericParams; gp != nil {
			iface.GenericParams = tt.buildExplicitGenericClause(gp)
		}

		for _, m := range n.Methods {
			ast.Walk(tt, m)
			iface.Methods = append(iface.Methods, tt.generated.(*Fn))
		}
		t.generated = &iface

		// ************** STATEMENTS *****************

	case *ast.IfStmt:

M pkg/semantic/type.go => pkg/semantic/type.go +82 -4
@@ 56,13 56,19 @@ type (
		lookup map[*GenericType]Type
	}

	// GenericType is the type of a generic placeholder, e.g. $T. Its
	// capabilities represent the operations allowed for this type.
	// InterfaceType represents a named interface type.
	InterfaceType struct {
		// Decl represents the interface declaration of this type.
		Decl *Interface
		// Inst is the list of types used in a generic instantiation, if the
		// interface declaration is generic.
		Inst []Type
	}

	// GenericType is the type of a generic placeholder, e.g. $T.
	GenericType struct {
		Name    string
		ScopeID int
		// TODO: eventually
		//Capabilities []*TraitType
	}

	// marker type for "unresolved", e.g. when an identifier is encountered before


@@ 78,6 84,13 @@ func AsStructType(T Type) *StructType {
	return nil
}

func AsInterfaceType(T Type) *InterfaceType {
	if it, ok := T.(*InterfaceType); ok {
		return it
	}
	return nil
}

func AsBasicType(T Type) *BasicType {
	if bt, ok := T.(*BasicType); ok {
		return bt


@@ 444,6 457,71 @@ func makeGenericResolveMap(gc *GenericClause, types []Type) map[*GenericType]Typ
	return resolve
}

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

// TODO: should be 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) }
func (i *InterfaceType) Valid() bool              { return true }

func (i *InterfaceType) String() string {
	var buf strings.Builder
	buf.WriteString("interface " + i.Decl.Ident())
	if len(i.Inst) > 0 {
		buf.WriteString("[")
		for i, t := range i.Inst {
			if i > 0 {
				buf.WriteString(", ")
			}
			buf.WriteString(t.String())
		}
		buf.WriteString("]")
	}
	return buf.String()
}

func (i *InterfaceType) IdenticalTo(T Type) bool {
	i2 := AsInterfaceType(T)
	if i2 == nil {
		return false
	}
	if i.Decl != i2.Decl {
		return false
	}
	if len(i.Inst) != len(i2.Inst) {
		return false
	}
	for i, t1 := range i.Inst {
		t2 := i2.Inst[i]
		if !t1.IdenticalTo(t2) {
			return false
		}
	}
	return true
}

func (i *InterfaceType) ResolveGeneric(resolve map[*GenericType]Type) Type {
	var diff bool
	ift := &InterfaceType{
		Decl: i.Decl,
		Inst: make([]Type, len(i.Inst)),
	}
	for i, it := range i.Inst {
		if gt := AsGenericType(it); gt != nil {
			if newt := resolve[gt]; newt != nil {
				ift.Inst[i] = newt
				diff = true
				continue
			}
		}
		ift.Inst[i] = it
	}
	if diff {
		return ift
	}
	return i
}

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

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

M pkg/semantic/typeassign_pass.go => pkg/semantic/typeassign_pass.go +13 -0
@@ 130,6 130,19 @@ func (t *typeassignVisitor) Visit(n Node) Visitor {
		}
		n.typ = st

	case *Interface:
		it := &InterfaceType{Decl: n}

		if n.GenericParams != nil {
			for _, elem := range n.GenericParams.Elems {
				Walk(t, elem)
			}
		}
		for _, fn := range n.Methods {
			Walk(t, fn)
		}
		n.typ = it

	case *GenericElem:
		// TODO: when traits/capabilities are added, this would lookup the matching
		// generic clause on the parent, and add the specific traits constraints on

M pkg/semantic/visitor.go => pkg/semantic/visitor.go +16 -0
@@ 29,6 29,9 @@ func Walk(v Visitor, node Node) {
		for _, str := range n.Structs {
			Walk(v, str)
		}
		for _, iface := range n.Interfaces {
			Walk(v, iface)
		}

	case *Fn:
		for _, attr := range n.Attrs {


@@ 74,6 77,19 @@ func Walk(v Visitor, node Node) {
		for _, str := range n.Structs {
			Walk(v, str)
		}
		for _, iface := range n.Interfaces {
			Walk(v, iface)
		}

	case *Interface:
		if n.GenericParams != nil {
			for _, elem := range n.GenericParams.Elems {
				Walk(v, elem)
			}
		}
		for _, m := range n.Methods {
			Walk(v, m)
		}

	case *Block:
		for _, stmt := range n.Stmts {