~mna/snow unlisted

0008f4dd231ef02d5676ecfc7d643bf9949b5f8c — Martin Angers 9 months ago 3218da6
pkg/semantic: type-check the interface declarations
M pkg/parser/parser.go => pkg/parser/parser.go +3 -0
@@ 804,6 804,9 @@ func (p *parser) parseInterfaceDecl() *ast.InterfaceDecl {
		if len(fn.Attrs) > 0 {
			p.error(fn.Pos(), "interface method cannot have attributes")
		}
		if fn.Ref.IsValid() {
			p.error(fn.Pos(), "interface method cannot be marked as ref")
		}
		if fn.Body != nil {
			p.error(fn.Pos(), "interface method cannot have a body")
		}

M pkg/parser/testdata/interface.snow.err => pkg/parser/testdata/interface.snow.err +1 -0
@@ 0,0 1,1 @@
testdata/interface.snow:4:3: interface method cannot be marked as ref

M pkg/semantic/semantic.go => pkg/semantic/semantic.go +3 -2
@@ 152,8 152,9 @@ type Fn struct {
	ReturnExpr Expr   // possibly nil, not a resolved Type, but the Expr of the return
	Body       *Block // possibly nil

	MethodOf *Struct // set during translation pass
	IsRef    bool    // set during translation pass
	MethodOf         *Struct    // set during translation pass
	AbstractMethodOf *Interface // set during translation pass
	IsRef            bool       // set during translation pass
	commonDecl
}


A pkg/semantic/testdata/check/generic_interface.snow.err => pkg/semantic/testdata/check/generic_interface.snow.err +1 -0
@@ 0,0 1,1 @@
main function missing

A pkg/semantic/testdata/check/generic_interface.snow.want => pkg/semantic/testdata/check/generic_interface.snow.want +9 -0
@@ 0,0 1,9 @@
file testdata/generic_interface.snow [0, 0, 0, 1]
  interface I [2, $2] [type: interface I]
    generic type $T [type: $T]
    generic type $U [type: $U]
    fn get_t [let: () -> $T]
      ident $T [type: $T]
    fn set_u [let: ($U) -> void]
      let: u [let: $U]
        ident $U [type: $U]

A pkg/semantic/testdata/check/interface.snow.err => pkg/semantic/testdata/check/interface.snow.err +1 -0
@@ 0,0 1,1 @@
main function missing

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

R pkg/semantic/testdata/generic_interface.snow.notyet => pkg/semantic/testdata/generic_interface.snow +1 -1
@@ 1,4 1,4 @@
interface I[$T, $U] {
  fn get_t() -> $T
  ref fn set_u(u: $U)
  fn set_u(u: $U)
}

R pkg/semantic/testdata/interface.snow.notyet => pkg/semantic/testdata/interface.snow +0 -0

A pkg/semantic/testdata/static/generic_interface.snow.err => pkg/semantic/testdata/static/generic_interface.snow.err +1 -0
@@ 0,0 1,1 @@
main function missing

A pkg/semantic/testdata/static/generic_interface.snow.want => pkg/semantic/testdata/static/generic_interface.snow.want +0 -0

A pkg/semantic/testdata/static/interface.snow.err => pkg/semantic/testdata/static/interface.snow.err +1 -0
@@ 0,0 1,1 @@
main function missing

A pkg/semantic/testdata/static/interface.snow.want => pkg/semantic/testdata/static/interface.snow.want +0 -0

M pkg/semantic/testdata/types/generic_interface.snow.want => pkg/semantic/testdata/types/generic_interface.snow.want +1 -1
@@ 4,6 4,6 @@ file testdata/generic_interface.snow [0, 0, 0, 1]
    generic type $U [type: $U]
    fn get_t [let: () -> $T]
      ident $T [type: $T]
    ref fn set_u [let: ($U) -> void]
    fn set_u [let: ($U) -> void]
      let: u [let: $U]
        ident $U [type: $U]

M pkg/semantic/translate_pass.go => pkg/semantic/translate_pass.go +9 -2
@@ 116,8 116,12 @@ func (t *translateVisitor) Visit(n ast.Node) ast.Visitor {
		// return type could be $T, and if so it must refer to its generic clause
		// (unless it is a method, in which case it should resolve to the struct's
		// generic clause).
		if str, ok := fn.scope.Owner.(*Struct); ok {
			fn.MethodOf = str
		// TODO: keep track of current struct in visitor instead, do not rely on Scope's internals?
		switch owner := fn.scope.Owner.(type) {
		case *Struct:
			fn.MethodOf = owner
		case *Interface:
			fn.AbstractMethodOf = owner
		}

		tgen := t


@@ 168,9 172,12 @@ func (t *translateVisitor) Visit(n ast.Node) ast.Visitor {
				ast.Walk(t, vd.Value)
				v.Value = t.generated.(Expr)
			}

			// TODO: keep track of current struct in visitor instead, do not rely on Scope's internals?
			if str, ok := v.scope.Owner.(*Struct); ok {
				v.PropOf = str
			}

			list[i] = v
		}
		t.generated = list

M pkg/semantic/type.go => pkg/semantic/type.go +2 -0
@@ 607,6 607,8 @@ func (i *InterfaceType) isSatisfiedBy(T Type) bool {
		resolve func(Type) Type
	)

	// TODO: for struct to satisfy an interface, if a method is ref, it should only be able
	// to satisfy if the struct value is mutable (type context should come into play).
	switch T := T.(type) {
	case *StructType:
		tfns = T.Decl.Fns

M pkg/semantic/typecheck_pass.go => pkg/semantic/typecheck_pass.go +20 -2
@@ 138,6 138,8 @@ func (t *typecheckVisitor) Visit(n Node) Visitor {
			Walk(t, attr)
		}

		// if the function is generic, maintain a set of generic placeholder names that must be used
		// in the signature.
		var set map[string]bool
		if n.GenericParams != nil {
			set = make(map[string]bool, len(n.GenericParams.Elems))


@@ 219,6 221,19 @@ func (t *typecheckVisitor) Visit(n Node) Visitor {
		var st *StructType
		t.expectTypeCtx(n, &st, Typ)

	case *Interface:
		if n.GenericParams != nil {
			for _, ge := range n.GenericParams.Elems {
				Walk(t, ge)
			}
		}
		for _, fn := range n.Methods {
			Walk(t, fn)
		}

		var it *InterfaceType
		t.expectTypeCtx(n, &it, Typ)

	case *GenericElem:
		var gt *GenericType
		t.expectTypeCtx(n, &gt, Typ)


@@ 422,7 437,8 @@ func (t *typecheckVisitor) Visit(n Node) Visitor {
	case *GenericInst:
		var T Type
		t.expectTypeCtx(n, &T, Typ, Value)
		// TODO: also, should the number of types be validated here instead? Conceptually would make more sense.
		// TODO: also, should the number of types be validated here instead? Conceptually would make more sense,
		// but currently done in type-assign and it works well.

	case *Ident:
		// check that it has a valid type and context


@@ 529,7 545,7 @@ func (t *typecheckVisitor) typecheckFnAttrs(fn *Fn) {
	}

	// @extern-specific validations
	if fn.Body == nil && extern == nil {
	if fn.Body == nil && extern == nil && fn.AbstractMethodOf == nil {
		t.errh(fn.Pos(), fmt.Sprintf("function %s must have a body", fn.Ident()))
	}
	if extern != nil {


@@ 678,6 694,8 @@ func (t *typecheckVisitor) typecheckFnCall(n *Call) {
		return
	}

	// TODO: for calls via interface, the labels are not allowed?

	// if labels are allowed, collect the expected labels
	var expectedLabels []string
	if fn := asFnDeclRef(n.Fun); fn != nil {

M pkg/semantic/visitor.go => pkg/semantic/visitor.go +4 -2
@@ 51,8 51,8 @@ func Walk(v Visitor, node Node) {
		if n.Body != nil {
			Walk(v, n.Body)
		}
		// n.MethodOf is a reference to a struct that exists elsewhere, don't visit
		// it separately here.
		// n.MethodOf and n.AbstractMethodOf are references to nodes that exist elsewhere, don't visit
		// them separately here.

	case *Var:
		if n.TypeExpr != nil {


@@ 61,6 61,8 @@ func Walk(v Visitor, node Node) {
		if n.Value != nil {
			Walk(v, n.Value)
		}
		// n.PropOf and n.ParamOf are references to nodes that exist elsewhere, don't visit
		// them separately here.

	case *Struct:
		if n.GenericParams != nil {