~mna/snow unlisted

c07fb77088a87987b42524357158e118e7e4e1aa — Martin Angers 9 months ago a05fec7 + afd5b87
Merge branch 'wip-interfaces'
296 files changed, 2316 insertions(+), 421 deletions(-)

M cmd/goast/main.go
M pkg/ast/ast.go
M pkg/ast/visitor.go
M pkg/codegen/mangle.go
M pkg/codegen/position.go
A pkg/codegen/testdata/fn_assign_call_interface.snow
A pkg/codegen/testdata/fn_assign_call_interface.snow.err
A pkg/codegen/testdata/fn_assign_call_interface.snow.want
A pkg/codegen/testdata/fn_interface_with_ref_method.snow.notyet
M pkg/codegen/translate.go
M pkg/codegen/treebuild.go
M pkg/grammar/grammar.ebnf
M pkg/parser/parser.go
A pkg/parser/testdata/interface.snow
A pkg/parser/testdata/interface.snow.err
A pkg/parser/testdata/interface.snow.want
A pkg/parser/testdata/invalid_interface.snow
A pkg/parser/testdata/invalid_interface.snow.err
A pkg/parser/testdata/invalid_interface.snow.want
M pkg/parser/testdata/var_kw_as_ident.snow.err
M pkg/parser/testdata/var_kw_as_ident.snow.want
M pkg/printer/printer.go
M pkg/scanner/scanner_test.go
M pkg/semantic/scope.go
M pkg/semantic/semantic.go
M pkg/semantic/testdata/check/cycle.snow.want
M pkg/semantic/testdata/check/empty.snow.want
M pkg/semantic/testdata/check/fn.snow.want
M pkg/semantic/testdata/check/fn_access_invalid_struct_field.snow.want
M pkg/semantic/testdata/check/fn_access_struct_type_field.snow.want
M pkg/semantic/testdata/check/fn_access_var_outside_struct.snow.want
A pkg/semantic/testdata/check/fn_assign_call_interface.snow.err
A pkg/semantic/testdata/check/fn_assign_call_interface.snow.want
M pkg/semantic/testdata/check/fn_assign_invalid.snow.want
M pkg/semantic/testdata/check/fn_assign_let.snow.want
M pkg/semantic/testdata/check/fn_assign_struct_fields.snow.want
M pkg/semantic/testdata/check/fn_assign_struct_method_to_var.snow.want
M pkg/semantic/testdata/check/fn_assign_type.snow.want
M pkg/semantic/testdata/check/fn_assign_unifying_type.snow.want
M pkg/semantic/testdata/check/fn_call_fn_value_with_labels.snow.want
M pkg/semantic/testdata/check/fn_call_struct_init.snow.want
M pkg/semantic/testdata/check/fn_call_struct_init_no_label.snow.want
M pkg/semantic/testdata/check/fn_call_struct_init_only_required_no_order.snow.want
M pkg/semantic/testdata/check/fn_call_struct_method.snow.want
M pkg/semantic/testdata/check/fn_call_unifying_type.snow.want
M pkg/semantic/testdata/check/fn_call_with_invalid_labels.snow.want
M pkg/semantic/testdata/check/fn_call_with_labels.snow.want
M pkg/semantic/testdata/check/fn_call_wrong_arity.snow.want
M pkg/semantic/testdata/check/fn_compare.snow.want
M pkg/semantic/testdata/check/fn_complex_selectors.snow.want
M pkg/semantic/testdata/check/fn_duplicate_param_name.snow.want
M pkg/semantic/testdata/check/fn_explicit_void.snow.want
M pkg/semantic/testdata/check/fn_extern_pkg_before_conflict_name.snow.want
M pkg/semantic/testdata/check/fn_extern_pkg_conflict_name.snow.want
M pkg/semantic/testdata/check/fn_extern_ref_method.snow.want
M pkg/semantic/testdata/check/fn_extern_with_body.snow.want
M pkg/semantic/testdata/check/fn_fn_arg.snow.want
M pkg/semantic/testdata/check/fn_generic_decl_after_inst.snow.want
M pkg/semantic/testdata/check/fn_generic_fn_uses_generic_fn.snow.want
M pkg/semantic/testdata/check/fn_generic_identity.snow.want
A pkg/semantic/testdata/check/fn_generic_interface.snow.err
A pkg/semantic/testdata/check/fn_generic_interface.snow.want
M pkg/semantic/testdata/check/fn_generic_unused_in_signature.snow.want
M pkg/semantic/testdata/check/fn_guard_fallthrough.snow.want
M pkg/semantic/testdata/check/fn_ident_as_type.snow.want
M pkg/semantic/testdata/check/fn_init_order.snow.want
M pkg/semantic/testdata/check/fn_invalid_attr.snow.want
M pkg/semantic/testdata/check/fn_invalid_extern_fields.snow.want
M pkg/semantic/testdata/check/fn_invalid_generic_use_in_fn.snow.want
M pkg/semantic/testdata/check/fn_invalid_main.snow.want
M pkg/semantic/testdata/check/fn_invalid_ref.snow.want
M pkg/semantic/testdata/check/fn_invalid_ref_call.snow.want
M pkg/semantic/testdata/check/fn_invalid_ref_call_via_value.snow.want
M pkg/semantic/testdata/check/fn_invalid_return.snow.want
M pkg/semantic/testdata/check/fn_invalid_tuple_access.snow.want
M pkg/semantic/testdata/check/fn_main_extern.snow.want
M pkg/semantic/testdata/check/fn_many_extern.snow.want
M pkg/semantic/testdata/check/fn_method_explicit_self.snow.want
M pkg/semantic/testdata/check/fn_multi_vars_per_decl.snow.want
M pkg/semantic/testdata/check/fn_nested_block.snow.want
M pkg/semantic/testdata/check/fn_nested_fn.snow.want
M pkg/semantic/testdata/check/fn_nested_fn_init_order.snow.want
M pkg/semantic/testdata/check/fn_nested_generic_fn.snow.want
M pkg/semantic/testdata/check/fn_nested_struct_method.snow.want
M pkg/semantic/testdata/check/fn_nested_struct_self.snow.want
M pkg/semantic/testdata/check/fn_nested_structs.snow.want
M pkg/semantic/testdata/check/fn_nested_tuple_type.snow.want
M pkg/semantic/testdata/check/fn_non_type_selectors.snow.want
M pkg/semantic/testdata/check/fn_param_type_is_var_in_body.snow.want
M pkg/semantic/testdata/check/fn_params.snow.want
M pkg/semantic/testdata/check/fn_params_locals.snow.want
M pkg/semantic/testdata/check/fn_recursion.snow.want
M pkg/semantic/testdata/check/fn_ref_on_fn_nested_in_method.snow.want
M pkg/semantic/testdata/check/fn_return_internal_struct.snow.want
M pkg/semantic/testdata/check/fn_return_missing_value.snow.want
M pkg/semantic/testdata/check/fn_return_struct.snow.want
M pkg/semantic/testdata/check/fn_return_unifying_type.snow.want
M pkg/semantic/testdata/check/fn_struct_main_method.snow.want
M pkg/semantic/testdata/check/fn_struct_method_access_top_level.snow.want
M pkg/semantic/testdata/check/fn_struct_order_independent.snow.want
M pkg/semantic/testdata/check/fn_struct_same_name_diff_scope.snow.want
M pkg/semantic/testdata/check/fn_struct_selector.snow.want
M pkg/semantic/testdata/check/fn_struct_self_shadow.snow.want
M pkg/semantic/testdata/check/fn_struct_self_uses.snow.want
M pkg/semantic/testdata/check/fn_tuple_assign_compatible_types.snow.want
M pkg/semantic/testdata/check/fn_tuple_assign_incompatible_types.snow.want
M pkg/semantic/testdata/check/fn_tuple_expr_select_field.snow.want
M pkg/semantic/testdata/check/fn_type_as_value.snow.want
M pkg/semantic/testdata/check/fn_unknown_symbol.snow.want
M pkg/semantic/testdata/check/fn_var_as_param_type.snow.want
M pkg/semantic/testdata/check/fn_without_body.snow.want
M pkg/semantic/testdata/check/fns.snow.want
A pkg/semantic/testdata/check/generic_interface.snow.err
A pkg/semantic/testdata/check/generic_interface.snow.want
M pkg/semantic/testdata/check/generic_struct_instantiation.snow.want
M pkg/semantic/testdata/check/guard_else.snow.want
M pkg/semantic/testdata/check/if_else_if.snow.want
M pkg/semantic/testdata/check/if_non_bool.snow.want
A pkg/semantic/testdata/check/interface.snow.err
A pkg/semantic/testdata/check/interface.snow.want
A pkg/semantic/testdata/check/interface_satisfied.snow.err
A pkg/semantic/testdata/check/interface_satisfied.snow.want
M pkg/semantic/testdata/check/invalid_binary_op.snow.want
A pkg/semantic/testdata/check/invalid_ref_fn_assign.snow.err
A pkg/semantic/testdata/check/invalid_ref_fn_assign.snow.want
M pkg/semantic/testdata/check/let.snow.want
M pkg/semantic/testdata/check/let_invalid_tuple_type.snow.want
M pkg/semantic/testdata/check/let_invalid_unary.snow.want
M pkg/semantic/testdata/check/let_unary.snow.want
M pkg/semantic/testdata/check/paren_type.snow.want
M pkg/semantic/testdata/check/struct_complex_generic.snow.want
M pkg/semantic/testdata/check/struct_generic.snow.want
M pkg/semantic/testdata/check/struct_simple_generic.snow.want
M pkg/semantic/testdata/check/struct_var_expr_call_method.snow.want
M pkg/semantic/testdata/check/top_level_fn_init_order.snow.want
M pkg/semantic/testdata/check/top_level_init_order.snow.want
M pkg/semantic/testdata/check/tuple_as_struct_generic.snow.want
M pkg/semantic/testdata/check/var.snow.want
M pkg/semantic/testdata/check/var_auto_ref.snow.want
M pkg/semantic/testdata/check/var_bool.snow.want
M pkg/semantic/testdata/check/var_duplicate_symbol.snow.want
M pkg/semantic/testdata/check/var_tuple_type.snow.want
A pkg/semantic/testdata/fn_assign_call_interface.snow
A pkg/semantic/testdata/fn_generic_interface.snow
A pkg/semantic/testdata/generic_interface.snow
A pkg/semantic/testdata/interface.snow
A pkg/semantic/testdata/interface_satisfied.snow
A pkg/semantic/testdata/invalid_ref_fn_assign.snow
A pkg/semantic/testdata/scopes/fn_assign_call_interface.snow.err
A pkg/semantic/testdata/scopes/fn_assign_call_interface.snow.want
A pkg/semantic/testdata/scopes/fn_generic_interface.snow.err
A pkg/semantic/testdata/scopes/fn_generic_interface.snow.want
A pkg/semantic/testdata/scopes/generic_interface.snow.err
A pkg/semantic/testdata/scopes/generic_interface.snow.want
A pkg/semantic/testdata/scopes/interface.snow.err
A pkg/semantic/testdata/scopes/interface.snow.want
A pkg/semantic/testdata/scopes/interface_satisfied.snow.err
A pkg/semantic/testdata/scopes/interface_satisfied.snow.want
A pkg/semantic/testdata/scopes/invalid_ref_fn_assign.snow.err
A pkg/semantic/testdata/scopes/invalid_ref_fn_assign.snow.want
A pkg/semantic/testdata/static/fn_assign_call_interface.snow.err
A pkg/semantic/testdata/static/fn_assign_call_interface.snow.want
A pkg/semantic/testdata/static/fn_generic_interface.snow.err
A pkg/semantic/testdata/static/fn_generic_interface.snow.want
A pkg/semantic/testdata/static/generic_interface.snow.err
A pkg/semantic/testdata/static/generic_interface.snow.want
A pkg/semantic/testdata/static/interface.snow.err
A pkg/semantic/testdata/static/interface.snow.want
A pkg/semantic/testdata/static/interface_satisfied.snow.err
A pkg/semantic/testdata/static/interface_satisfied.snow.want
A pkg/semantic/testdata/static/invalid_ref_fn_assign.snow.err
A pkg/semantic/testdata/static/invalid_ref_fn_assign.snow.want
M pkg/semantic/testdata/types/cycle.snow.want
M pkg/semantic/testdata/types/empty.snow.want
M pkg/semantic/testdata/types/fn.snow.want
M pkg/semantic/testdata/types/fn_access_invalid_struct_field.snow.want
M pkg/semantic/testdata/types/fn_access_struct_type_field.snow.want
M pkg/semantic/testdata/types/fn_access_var_outside_struct.snow.want
A pkg/semantic/testdata/types/fn_assign_call_interface.snow.err
A pkg/semantic/testdata/types/fn_assign_call_interface.snow.want
M pkg/semantic/testdata/types/fn_assign_invalid.snow.want
M pkg/semantic/testdata/types/fn_assign_let.snow.want
M pkg/semantic/testdata/types/fn_assign_struct_fields.snow.want
M pkg/semantic/testdata/types/fn_assign_struct_method_to_var.snow.want
M pkg/semantic/testdata/types/fn_assign_type.snow.want
M pkg/semantic/testdata/types/fn_assign_unifying_type.snow.want
M pkg/semantic/testdata/types/fn_call_fn_value_with_labels.snow.want
M pkg/semantic/testdata/types/fn_call_struct_init.snow.want
M pkg/semantic/testdata/types/fn_call_struct_init_no_label.snow.want
M pkg/semantic/testdata/types/fn_call_struct_init_only_required_no_order.snow.want
M pkg/semantic/testdata/types/fn_call_struct_method.snow.want
M pkg/semantic/testdata/types/fn_call_unifying_type.snow.want
M pkg/semantic/testdata/types/fn_call_with_invalid_labels.snow.want
M pkg/semantic/testdata/types/fn_call_with_labels.snow.want
M pkg/semantic/testdata/types/fn_call_wrong_arity.snow.want
M pkg/semantic/testdata/types/fn_compare.snow.want
M pkg/semantic/testdata/types/fn_complex_selectors.snow.want
M pkg/semantic/testdata/types/fn_duplicate_param_name.snow.want
M pkg/semantic/testdata/types/fn_explicit_void.snow.want
M pkg/semantic/testdata/types/fn_extern_pkg_before_conflict_name.snow.want
M pkg/semantic/testdata/types/fn_extern_pkg_conflict_name.snow.want
M pkg/semantic/testdata/types/fn_extern_ref_method.snow.want
M pkg/semantic/testdata/types/fn_extern_with_body.snow.want
M pkg/semantic/testdata/types/fn_fn_arg.snow.want
M pkg/semantic/testdata/types/fn_generic_decl_after_inst.snow.want
M pkg/semantic/testdata/types/fn_generic_fn_uses_generic_fn.snow.want
M pkg/semantic/testdata/types/fn_generic_identity.snow.want
A pkg/semantic/testdata/types/fn_generic_interface.snow.err
A pkg/semantic/testdata/types/fn_generic_interface.snow.want
M pkg/semantic/testdata/types/fn_generic_unused_in_signature.snow.want
M pkg/semantic/testdata/types/fn_guard_fallthrough.snow.want
M pkg/semantic/testdata/types/fn_ident_as_type.snow.want
M pkg/semantic/testdata/types/fn_init_order.snow.want
M pkg/semantic/testdata/types/fn_invalid_attr.snow.want
M pkg/semantic/testdata/types/fn_invalid_extern_fields.snow.want
M pkg/semantic/testdata/types/fn_invalid_generic_use_in_fn.snow.want
M pkg/semantic/testdata/types/fn_invalid_main.snow.want
M pkg/semantic/testdata/types/fn_invalid_ref.snow.want
M pkg/semantic/testdata/types/fn_invalid_ref_call.snow.want
M pkg/semantic/testdata/types/fn_invalid_ref_call_via_value.snow.want
M pkg/semantic/testdata/types/fn_invalid_return.snow.want
M pkg/semantic/testdata/types/fn_invalid_tuple_access.snow.want
M pkg/semantic/testdata/types/fn_main_extern.snow.want
M pkg/semantic/testdata/types/fn_many_extern.snow.want
M pkg/semantic/testdata/types/fn_method_explicit_self.snow.want
M pkg/semantic/testdata/types/fn_multi_vars_per_decl.snow.want
M pkg/semantic/testdata/types/fn_nested_block.snow.want
M pkg/semantic/testdata/types/fn_nested_fn.snow.want
M pkg/semantic/testdata/types/fn_nested_fn_init_order.snow.want
M pkg/semantic/testdata/types/fn_nested_generic_fn.snow.want
M pkg/semantic/testdata/types/fn_nested_struct_method.snow.want
M pkg/semantic/testdata/types/fn_nested_struct_self.snow.want
M pkg/semantic/testdata/types/fn_nested_structs.snow.want
M pkg/semantic/testdata/types/fn_nested_tuple_type.snow.want
M pkg/semantic/testdata/types/fn_non_type_selectors.snow.want
M pkg/semantic/testdata/types/fn_param_type_is_var_in_body.snow.want
M pkg/semantic/testdata/types/fn_params.snow.want
M pkg/semantic/testdata/types/fn_params_locals.snow.want
M pkg/semantic/testdata/types/fn_recursion.snow.want
M pkg/semantic/testdata/types/fn_ref_on_fn_nested_in_method.snow.want
M pkg/semantic/testdata/types/fn_return_internal_struct.snow.want
M pkg/semantic/testdata/types/fn_return_missing_value.snow.want
M pkg/semantic/testdata/types/fn_return_struct.snow.want
M pkg/semantic/testdata/types/fn_return_unifying_type.snow.want
M pkg/semantic/testdata/types/fn_struct_main_method.snow.want
M pkg/semantic/testdata/types/fn_struct_method_access_top_level.snow.want
M pkg/semantic/testdata/types/fn_struct_order_independent.snow.want
M pkg/semantic/testdata/types/fn_struct_same_name_diff_scope.snow.want
M pkg/semantic/testdata/types/fn_struct_selector.snow.want
M pkg/semantic/testdata/types/fn_struct_self_shadow.snow.want
M pkg/semantic/testdata/types/fn_struct_self_uses.snow.want
M pkg/semantic/testdata/types/fn_tuple_assign_compatible_types.snow.want
M pkg/semantic/testdata/types/fn_tuple_assign_incompatible_types.snow.want
M pkg/semantic/testdata/types/fn_tuple_expr_select_field.snow.want
M pkg/semantic/testdata/types/fn_type_as_value.snow.want
M pkg/semantic/testdata/types/fn_unknown_symbol.snow.want
M pkg/semantic/testdata/types/fn_var_as_param_type.snow.want
M pkg/semantic/testdata/types/fn_without_body.snow.want
M pkg/semantic/testdata/types/fns.snow.want
A pkg/semantic/testdata/types/generic_interface.snow.err
A pkg/semantic/testdata/types/generic_interface.snow.want
M pkg/semantic/testdata/types/generic_struct_instantiation.snow.want
M pkg/semantic/testdata/types/guard_else.snow.want
M pkg/semantic/testdata/types/if_else_if.snow.want
M pkg/semantic/testdata/types/if_non_bool.snow.want
A pkg/semantic/testdata/types/interface.snow.err
A pkg/semantic/testdata/types/interface.snow.want
A pkg/semantic/testdata/types/interface_satisfied.snow.err
A pkg/semantic/testdata/types/interface_satisfied.snow.want
M pkg/semantic/testdata/types/invalid_binary_op.snow.want
A pkg/semantic/testdata/types/invalid_ref_fn_assign.snow.err
A pkg/semantic/testdata/types/invalid_ref_fn_assign.snow.want
M pkg/semantic/testdata/types/let.snow.want
M pkg/semantic/testdata/types/let_invalid_tuple_type.snow.want
M pkg/semantic/testdata/types/let_invalid_unary.snow.want
M pkg/semantic/testdata/types/let_unary.snow.want
M pkg/semantic/testdata/types/paren_type.snow.want
M pkg/semantic/testdata/types/struct_complex_generic.snow.want
M pkg/semantic/testdata/types/struct_generic.snow.want
M pkg/semantic/testdata/types/struct_simple_generic.snow.want
M pkg/semantic/testdata/types/struct_var_expr_call_method.snow.want
M pkg/semantic/testdata/types/top_level_fn_init_order.snow.want
M pkg/semantic/testdata/types/top_level_init_order.snow.want
M pkg/semantic/testdata/types/tuple_as_struct_generic.snow.want
M pkg/semantic/testdata/types/var.snow.want
M pkg/semantic/testdata/types/var_auto_ref.snow.want
M pkg/semantic/testdata/types/var_bool.snow.want
M pkg/semantic/testdata/types/var_duplicate_symbol.snow.want
M pkg/semantic/testdata/types/var_tuple_type.snow.want
M pkg/semantic/translate_pass.go
M pkg/semantic/type.go
M pkg/semantic/typeassign_pass.go
M pkg/semantic/typeassign_pass_test.go
M pkg/semantic/typecheck_pass.go
M pkg/semantic/visitor.go
M pkg/token/token.go
M cmd/goast/main.go => cmd/goast/main.go +4 -2
@@ 10,9 10,11 @@ func main() {
	src := `
package main

type I interface {
	foo(int) int
}

func main() { 
	s := map[string]bool{"a": true}
	_ = s
}
`


M pkg/ast/ast.go => pkg/ast/ast.go +30 -15
@@ 39,7 39,7 @@ type (
		Name          *Ident
		GenericParams *GenericClause // possibly nil
		Signature     *FnSig
		Body          *Block // possibly nil for external func declarations
		Body          *Block // possibly nil for external func declarations or methods in interface decls
	}

	// Block represents a block of statements, including the surrounding braces.


@@ 66,6 66,16 @@ type (
		Rbrace        token.Pos
	}

	// InterfaceDecl represents a InterfaceDecl production.
	InterfaceDecl struct {
		Interface     token.Pos
		Name          *Ident
		GenericParams *GenericClause // possibly nil
		Lbrace        token.Pos
		Methods       []*FnDecl
		Rbrace        token.Pos
	}

	// ReturnStmt represents a ReturnStmt production.
	ReturnStmt struct {
		Ret   token.Pos


@@ 302,16 312,17 @@ type Stmt interface {
	stmtNode()
}

func (f *FnDecl) stmtNode()     {}
func (v *VarDecl) stmtNode()    {}
func (s *StructDecl) stmtNode() {}
func (r *ReturnStmt) stmtNode() {}
func (b *BadStmt) stmtNode()    {}
func (b *Block) stmtNode()      {}
func (a *AssignStmt) stmtNode() {}
func (e *ExprStmt) stmtNode()   {}
func (i *IfStmt) stmtNode()     {}
func (g *GuardStmt) stmtNode()  {}
func (f *FnDecl) stmtNode()        {}
func (v *VarDecl) stmtNode()       {}
func (s *StructDecl) stmtNode()    {}
func (i *InterfaceDecl) stmtNode() {}
func (r *ReturnStmt) stmtNode()    {}
func (b *BadStmt) stmtNode()       {}
func (b *Block) stmtNode()         {}
func (a *AssignStmt) stmtNode()    {}
func (e *ExprStmt) stmtNode()      {}
func (i *IfStmt) stmtNode()        {}
func (g *GuardStmt) stmtNode()     {}

// Decl represents a symbol declaration statement in the AST.
type Decl interface {


@@ 319,10 330,11 @@ type Decl interface {
	declNode()
}

func (f *FnDecl) declNode()     {}
func (v *VarDecl) declNode()    {}
func (s *StructDecl) declNode() {}
func (b *BadStmt) declNode()    {}
func (f *FnDecl) declNode()        {}
func (v *VarDecl) declNode()       {}
func (s *StructDecl) declNode()    {}
func (i *InterfaceDecl) declNode() {}
func (b *BadStmt) declNode()       {}

// The rest of the file implements the Pos and End methods on every node.



@@ 449,6 461,9 @@ func (v *VarDef) End() token.Pos {
func (s *StructDecl) Pos() token.Pos { return s.Struct }
func (s *StructDecl) End() token.Pos { return s.Rbrace + 1 }

func (i *InterfaceDecl) Pos() token.Pos { return i.Interface }
func (i *InterfaceDecl) End() token.Pos { return i.Rbrace + 1 }

func (r *ReturnStmt) Pos() token.Pos { return r.Ret }
func (r *ReturnStmt) End() token.Pos {
	if r.Value != nil {

M pkg/ast/visitor.go => pkg/ast/visitor.go +11 -0
@@ 119,6 119,17 @@ func Walk(v Visitor, node Node) {
			Walk(v, decl)
		}

	case *InterfaceDecl:
		if n.Name != nil {
			Walk(v, n.Name)
		}
		if n.GenericParams != nil {
			Walk(v, n.GenericParams)
		}
		for _, meth := range n.Methods {
			Walk(v, meth)
		}

	case *ReturnStmt:
		if n.Value != nil {
			Walk(v, n.Value)

M pkg/codegen/mangle.go => pkg/codegen/mangle.go +21 -1
@@ 89,6 89,10 @@ func mangle(unit *semantic.Unit) *nameResolver {
			case *semantic.Struct:
				b.withPrefixFor(decl)
				names[decl] = b.get(decl.Ident())

			case *semantic.Interface:
				b.withPrefixFor(decl)
				names[decl] = b.get(decl.Ident())
			}
		}
		return true


@@ 121,6 125,13 @@ func (r *nameResolver) NameForStructType(st *semantic.StructType, resolve map[*s
	return r.NameForGenericDeclAndTypes(st.Decl, st.Inst, resolve)
}

func (r *nameResolver) NameForInterfaceType(it *semantic.InterfaceType, resolve map[*semantic.GenericType]semantic.Type) string {
	if !it.Decl.IsGeneric() {
		return r.NameForDecl(it.Decl)
	}
	return r.NameForGenericDeclAndTypes(it.Decl, it.Inst, resolve)
}

func (r *nameResolver) NameForGenericInst(gi *semantic.GenericInst, resolve map[*semantic.GenericType]semantic.Type) string {
	gd := gi.GenericDecl.Ref.(semantic.GenericDecl)
	_, insts := gd.GenInsts()


@@ 196,7 207,9 @@ type fmtBuilder struct {
func (b *fmtBuilder) withPrefixFor(decl semantic.Decl) {
	switch decl := decl.(type) {
	case *semantic.Fn:
		if decl.Scope().IsTopLevel() || decl.MethodOf != nil {
		if decl.Scope().IsTopLevel() || decl.MethodOf != nil || decl.AbstractMethodOf != nil {
			// TODO: this will be an issue with pub/exported methods eventually: the mangling of
			// an interface method might not match the one of an otherwise matching struct method.
			b.withExport(false)
		}
	case *semantic.Var:


@@ 208,6 221,13 @@ func (b *fmtBuilder) withPrefixFor(decl semantic.Decl) {
		if !decl.Scope().IsTopLevel() {
			b.withScope(decl.Scope())
		}
	case *semantic.Interface:
		b.withExport(false)
		if !decl.Scope().IsTopLevel() {
			b.withScope(decl.Scope())
		}
	default:
		panic(fmt.Sprintf("invalid declaration type for mangler prefix: %T", decl))
	}
}


M pkg/codegen/position.go => pkg/codegen/position.go +2 -0
@@ 130,6 130,8 @@ func (p *positioner) Visit(n goast.Node) goast.Visitor {
		return nil
	case *goast.IfStmt:
		n.If = p.getIncByLen("if ")
	case *goast.InterfaceType:
		n.Interface = p.getIncByLen("interface ")
	}
	return p
}

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

struct S {
  let s: string

  fn foo() {
    println(s)
  }

  struct S2 {
    fn foo() {
      println("s2")
    }
  }
}

@extern(import: "fmt", symbol: "Println")
fn println(s: string)

fn main() {
  var iface: I = S(s: "hello!")
  iface.foo()
  iface = S.S2()
  iface.foo()
}

#=hello!
#=s2

A pkg/codegen/testdata/fn_assign_call_interface.snow.err => pkg/codegen/testdata/fn_assign_call_interface.snow.err +0 -0

A pkg/codegen/testdata/fn_assign_call_interface.snow.want => pkg/codegen/testdata/fn_assign_call_interface.snow.want +58 -0
@@ 0,0 1,58 @@
package main

import "fmt"

type _اS struct {
	_اs string
}

func (
	self _اS,
) _اfoo() {
	_اprintln(self._اs)
}

type _ا6اS2 struct {
}

func (
	self _ا6اS2,
) _اfoo() {
	_اprintln("s2")
}

func _ا6اS2اnew(
	s _ا6اS2,
	m map[string]bool,
) _ا6اS2 {
	var r _ا6اS2
	return r
}

func _اSاnew(
	s _اS,
	m map[string]bool,
) _اS {
	var r _اS
	if m["s"] {
		r._اs = s._اs
	}
	return r
}

func _اprintln(
	s string,
) {
	fmt.Println(s)
}

func main() {
	var iface _اI = _اSاnew(_اS{_اs: "hello!"}, map[string]bool{"s": true})
	iface._اfoo()
	iface = _ا6اS2اnew(_ا6اS2{}, map[string]bool{})
	iface._اfoo()
}

type _اI interface {
	_اfoo()
}

A pkg/codegen/testdata/fn_interface_with_ref_method.snow.notyet => pkg/codegen/testdata/fn_interface_with_ref_method.snow.notyet +28 -0
@@ 0,0 1,28 @@
interface I {
  fn foo()
}

struct S {
  var i: int 
  ref fn foo() {
    i = i + 1
  }
}

fn main() {
  var s = S(i: 0)
  let iface: I = s
  iface.foo()
  println(s.i)

  # this should work, s is mutable
  let tup: (int, I) = (1, s)
  tup.1.foo()
  println(s.i)
}

@extern(import: "fmt", symbol: "Println")
fn println(v: int)

#=1
#=2

M pkg/codegen/translate.go => pkg/codegen/translate.go +84 -10
@@ 124,6 124,9 @@ func (t *translator) Visit(n semantic.Node) semantic.Visitor {
			for _, fn := range n.Fns {
				semantic.Walk(t, fn)
			}
			for _, iface := range n.Interfaces {
				semantic.Walk(t, iface)
			}
		})

		// ************** DECLARATIONS *****************


@@ 169,6 172,16 @@ func (t *translator) Visit(n semantic.Node) semantic.Visitor {
			Specs: []goast.Spec{vs},
		})

	case *semantic.Interface:
		if n.IsGeneric() {
			// go nodes will be generated only on instantiation, create an empty container for now
			m := &mark{list: t.topLevel, elem: t.topLevel.PushBack(newContainer(n))}
			t.genDeclMarks[n] = m
			break
		}
		name := t.resolver.NameForDecl(n)
		t.createInterface(name, semantic.AsInterfaceType(n.Type()))

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

	case *semantic.Block:


@@ 408,21 421,22 @@ func (t *translator) createFn(nm string, fn *semantic.Fn) {

	var body *goast.BlockStmt
	t.withContainer(cont, func() {
		if fn.Body == nil {
			body = createExternalFnBody(ft, t.fnImports[fn])
		} else {
		if fn.Body != nil {
			semantic.Walk(t, fn.Body)
		} else if fn.AbstractMethodOf == nil {
			// this is an external function
			body = createExternalFnBody(ft, t.fnImports[fn])
		}
	})

	// the function declaration is a top-level func statement if it is top-level
	// in snow or is a struct method.
	fd := &goast.FuncDecl{
		Name: &goast.Ident{Name: nm},
		Type: ft,
		Body: body,
	}
	if fn.Scope().IsTopLevel() || fn.MethodOf != nil {
		fd := &goast.FuncDecl{
			Name: &goast.Ident{Name: nm},
			Type: ft,
			Body: body,
		}
		if str := fn.MethodOf; str != nil {
			t.convertFuncToMethod(fd, str, fn.IsRef)
		}


@@ 434,6 448,14 @@ func (t *translator) createFn(nm string, fn *semantic.Fn) {
			t.topLevel.PushBack(cont)
		}
		return

	}
	if fn.AbstractMethodOf != nil {
		// if it is an interface method, create the function declaration inside the
		// interface's container. It cannot be a generic itself (only the interface can).
		cont.nodes = []goast.Node{fd}
		t.parentContainer.PushBack(cont)
		return
	}

	cont.nodes = createFuncLit(nm, ft, body)


@@ 499,13 521,16 @@ func (t *translator) createStruct(nm string, strTyp *semantic.StructType) {
	// generate struct initializer function
	strInit := t.createStructInit(nm, strTyp, propInit)

	// generate methods and nested structs
	// generate methods and nested structs and interfaces
	for _, meth := range strTyp.Decl.Fns {
		semantic.Walk(t, meth)
	}
	for _, str := range strTyp.Decl.Structs {
		semantic.Walk(t, str)
	}
	for _, iface := range strTyp.Decl.Interfaces {
		semantic.Walk(t, iface)
	}

	if mark := t.genDeclMarks[strTyp.Decl]; mark != nil {
		mark.list.InsertBefore(strInit, mark.elem)


@@ 514,6 539,40 @@ func (t *translator) createStruct(nm string, strTyp *semantic.StructType) {
	}
}

func (t *translator) createInterface(nm string, ifaceTyp *semantic.InterfaceType) {
	// all interface declarations are attached to the top-level scope of the file.
	fields := &goast.FieldList{List: make([]*goast.Field, len(ifaceTyp.Decl.Methods))}

	// create the container but don't set its Go node yet, it will be created
	// only after looping over the methods.
	cont := &container{snode: ifaceTyp.Decl, children: list.New()}

	t.withContainer(cont, func() {
		for i, m := range ifaceTyp.Decl.Methods {
			semantic.Walk(t, m)
			node := t.parentContainer.Back().Value
			fnDecl := node.(*container).nodes[0].(*goast.FuncDecl)
			fields.List[i] = &goast.Field{
				Names: []*goast.Ident{fnDecl.Name},
				Type:  fnDecl.Type,
			}
		}
	})

	decl := &goast.GenDecl{
		Tok: gotoken.TYPE,
		Specs: []goast.Spec{
			&goast.TypeSpec{Name: &goast.Ident{Name: nm}, Type: &goast.InterfaceType{Methods: fields}},
		},
	}
	cont.nodes = []goast.Node{decl}
	if mark := t.genDeclMarks[ifaceTyp.Decl]; mark != nil {
		mark.list.InsertBefore(cont, mark.elem)
	} else {
		t.topLevel.PushBack(cont)
	}
}

func (t *translator) addFileImports(f *semantic.File, gof *goast.File) {
	imports := t.fileImports[f]
	set := make(map[string]bool, len(imports))


@@ 569,7 628,6 @@ func (t *translator) goTypeExprFor(T semantic.Type) goast.Expr {
		}
		for i, field := range T.Fields {
			st.Fields.List[i] = &goast.Field{
				// TODO: for now, always unexported?
				Names: []*goast.Ident{{Name: t.resolver.NameForTuple(i, false)}},
				Type:  t.goTypeExprFor(field),
			}


@@ 580,6 638,10 @@ func (t *translator) goTypeExprFor(T semantic.Type) goast.Expr {
		name := t.resolver.NameForStructType(T, t.curGenInst)
		return &goast.Ident{Name: name}

	case *semantic.InterfaceType:
		name := t.resolver.NameForInterfaceType(T, t.curGenInst)
		return &goast.Ident{Name: name}

	default:
		panic(fmt.Sprintf("invalid type: %T", T))
	}


@@ 595,6 657,16 @@ func (t *translator) reconcileExprWith(LT, RT semantic.Type, expr goast.Expr) go
func (t *translator) convertExprFromTo(expr goast.Expr, fromT, toT semantic.Type) goast.Expr {
	var convertCallExpr goast.Expr

	// if toT is an interface, no explicit conversion needed, Go will be able to assign fromT
	// to it (as the rules for assignability are the same). Only thing is if one of the methods
	// is satisfied by a ref function, the address of expr must be returned instead.
	if semantic.AsInterfaceType(toT) != nil {
		if st := semantic.AsStructType(fromT); st != nil && st.Ctx == semantic.Mutable {
			return &goast.UnaryExpr{Op: gotoken.AND, X: expr}
		}
		return expr
	}

	fromTupT, ok1 := fromT.(*semantic.TupleType)
	toTupT, ok2 := toT.(*semantic.TupleType)
	if ok1 && ok2 {


@@ 819,6 891,8 @@ func (t *translator) renderGenInst(gi *semantic.GenericInst, name string) {
		t.createFn(name, decl)
	case *semantic.Struct:
		t.createStruct(name, semantic.AsStructType(gi.Type()))
	case *semantic.Interface:
		t.createInterface(name, semantic.AsInterfaceType(gi.Type()))
	default:
		panic(fmt.Sprintf("invalid generic type to render: %T", decl))
	}

M pkg/codegen/treebuild.go => pkg/codegen/treebuild.go +3 -0
@@ 99,6 99,9 @@ func (tb *treebuilder) Visit(n semantic.Node) semantic.Visitor {
	case *semantic.Struct:
		// a struct container has a single Go node, the struct decl, and it is fully
		// formed, no need to append children, so nothing to do.
	case *semantic.Interface:
		// an interface container has a single Go node, the interface decl, and it is fully
		// formed, no need to append children, so nothing to do.

	case *semantic.Block:
		cont := tb.curContainer

M pkg/grammar/grammar.ebnf => pkg/grammar/grammar.ebnf +5 -1
@@ 20,7 20,7 @@ GenericArgClause = "[" TypeList [ "," ] "]" .
// => Statements
TopLevelStmt = Declaration .
Stmt = Declaration | SimpleStmt | Block | ReturnStmt | BranchStmt .
Declaration = VarDecl | FuncDecl | StructDecl .
Declaration = VarDecl | FuncDecl | StructDecl | InterfaceDecl .
SimpleStmt = ExprStmt | AssignStmt | EmptyStmt .

// => Variable declaration statement


@@ 46,6 46,10 @@ FuncTrailer = "->" Type .
StructDecl = "struct" ident [ GenericParamClause ] "{" StructDeclBody "}" .
StructDeclBody = { Declaration } .

// => Interface type declaration statement
InterfaceDecl = "interface" ident [ GenericParamClause ] "{" InterfaceBody "}" .
InterfaceBody = { FuncDecl } . // the parser will make sure there is no attribute, generic clause and body

// => Assignment statement 
AssignStmt = Expr "=" Expr .


M pkg/parser/parser.go => pkg/parser/parser.go +35 -0
@@ 109,6 109,8 @@ func (p *parser) parseDecl(errLabel string, syncSet map[token.Token]bool) ast.De
		return p.parseFuncDecl()
	case token.Struct:
		return p.parseStructDecl()
	case token.Interface:
		return p.parseInterfaceDecl()
	default:
		pos := p.pos
		p.errorExpected(pos, errLabel)


@@ 786,6 788,39 @@ func (p *parser) parseStructDecl() *ast.StructDecl {
	return str
}

func (p *parser) parseInterfaceDecl() *ast.InterfaceDecl {
	id := &ast.InterfaceDecl{
		Interface: p.expect(token.Interface),
	}
	id.Name = p.parseIdent()
	if p.tok == token.Lbrack {
		id.GenericParams = p.parseGenericClause(genericClauseParams)
	}
	id.Lbrace = p.expect(token.Lbrace)

	var methods []*ast.FnDecl
	for !tokenIn(p.tok, token.Rbrace, token.EOF) {
		fn := p.parseFuncDecl()
		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.GenericParams != nil {
			p.error(fn.Pos(), "interface method cannot have a generic clause (the interface itself can)")
		}
		if fn.Body != nil {
			p.error(fn.Pos(), "interface method cannot have a body")
		}
		methods = append(methods, fn)
	}
	id.Methods = methods
	id.Rbrace = p.expect(token.Rbrace)
	p.expectSemi()
	return id
}

type genericClauseMode int

const (

A pkg/parser/testdata/interface.snow => pkg/parser/testdata/interface.snow +6 -0
@@ 0,0 1,6 @@
interface I {}

interface J[$T, $U] {
  ref fn foo(t: $T, u: $U)
  fn bar() -> ($T, $U)
}

A 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

A pkg/parser/testdata/interface.snow.want => pkg/parser/testdata/interface.snow.want +27 -0
@@ 0,0 1,27 @@
file [2, #0] [0:89]
  interface [0] [0:14]
    ident [I] [10:11]
  interface [2] [16:89]
    ident [J] [26:27]
    generic [27:35]
      param [28:31]
        ident [$T] [28:30]
      param [32:34]
        ident [$U] [32:34]
    ref fn [40:64]
      ident [foo] [47:50]
      sig [2->0] [50:64]
        param [51:57]
          ident [t] [51:52]
          ident [$T] [54:56]
        param [58:63]
          ident [u] [58:59]
          ident [$U] [61:63]
    fn [67:87]
      ident [bar] [70:73]
      sig [0->1] [73:87]
        tuple type [2] [79:87]
          param [80:83]
            ident [$T] [80:82]
          param [84:86]
            ident [$U] [84:86]

A pkg/parser/testdata/invalid_interface.snow => pkg/parser/testdata/invalid_interface.snow +10 -0
@@ 0,0 1,10 @@
interface I {
  @external(x: 1, y: "a")
  fn foo()

  fn bar() {
    foo()
  }

  fn quz[$T](t: $T)
}

A pkg/parser/testdata/invalid_interface.snow.err => pkg/parser/testdata/invalid_interface.snow.err +3 -0
@@ 0,0 1,3 @@
testdata/invalid_interface.snow:2:3: interface method cannot have attributes
testdata/invalid_interface.snow:5:3: interface method cannot have a body
testdata/invalid_interface.snow:9:3: interface method cannot have a generic clause (the interface itself can)

A pkg/parser/testdata/invalid_interface.snow.want => pkg/parser/testdata/invalid_interface.snow.want +30 -0
@@ 0,0 1,30 @@
file [1, #0] [0:101]
  interface [3] [0:101]
    ident [I] [10:11]
    fn [16:50]
      @ [2] [16:39]
        ident [external] [17:25]
        field [26:31]
          ident [x] [26:27]
          int [1] [29:30]
        field [32:38]
          ident [y] [32:33]
          string ["a"] [35:38]
      ident [foo] [45:48]
      sig [0->0] [48:50]
    fn [54:78]
      ident [bar] [57:60]
      sig [0->0] [60:62]
      block [1] [63:78]
        expr [69:74]
          call [0] [69:74]
            ident [foo] [69:72]
    fn [82:99]
      ident [quz] [85:88]
      generic [88:92]
        param [89:91]
          ident [$T] [89:91]
      sig [1->0] [92:99]
        param [93:98]
          ident [t] [93:94]
          ident [$T] [96:98]

M pkg/parser/testdata/var_kw_as_ident.snow.err => pkg/parser/testdata/var_kw_as_ident.snow.err +1 -0
@@ 6,3 6,4 @@ testdata/var_kw_as_ident.snow:5:5: expected 'ident', found 'if'
testdata/var_kw_as_ident.snow:6:5: expected 'ident', found 'guard'
testdata/var_kw_as_ident.snow:7:5: expected 'ident', found 'else'
testdata/var_kw_as_ident.snow:8:5: expected 'ident', found 'struct'
testdata/var_kw_as_ident.snow:23:5: expected 'ident', found 'interface'

M pkg/parser/testdata/var_kw_as_ident.snow.want => pkg/parser/testdata/var_kw_as_ident.snow.want +2 -2
@@ 84,8 84,8 @@ file [28, #0] [0:444]
      ident [import] [314:320]
      ident [f32] [322:325]
  let [327:345]
    interface: [331:345]
      ident [interface] [331:340]
    : [331:345]
      ident [] [331:331]
      ident [f64] [342:345]
  let [347:362]
    map: [351:362]

M pkg/printer/printer.go => pkg/printer/printer.go +15 -3
@@ 155,7 155,8 @@ func (p *semanticPrinter) Visit(n semantic.Node) semantic.Visitor {

	switch n := n.(type) {
	case *semantic.File:
		p.printMsg(fmt.Sprintf("file %s [%d, %d, %d]", p.file.Name(), len(n.Vars), len(n.Fns), len(n.Structs)), true)
		p.printMsg(fmt.Sprintf("file %s [%d, %d, %d, %d]",
			p.file.Name(), len(n.Vars), len(n.Fns), len(n.Structs), len(n.Interfaces)), true)
	case *semantic.Fn:
		format := "fn %s"
		args := []interface{}{n.Ident()}


@@ 177,8 178,17 @@ func (p *semanticPrinter) Visit(n semantic.Node) semantic.Visitor {
		}
		p.printMsg(fmt.Sprintf("%s %s", lbl, n.Ident()), true)
	case *semantic.Struct:
		format := "struct %s [%d, %d, %d"
		args := []interface{}{n.Ident(), len(n.Vars), len(n.Fns), len(n.Structs)}
		format := "struct %s [%d, %d, %d, %d"
		args := []interface{}{n.Ident(), len(n.Vars), len(n.Fns), len(n.Structs), len(n.Interfaces)}
		if n.GenericParams != nil {
			format += ", $%d"
			args = append(args, len(n.GenericParams.Elems))
		}
		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))


@@ 326,6 336,8 @@ func (p *astPrinter) Visit(n ast.Node) ast.Visitor {
		p.printMsg(lbl, true)
	case *ast.StructDecl:
		p.printMsg(fmt.Sprintf("struct [%d]", len(n.Decls)), true)
	case *ast.InterfaceDecl:
		p.printMsg(fmt.Sprintf("interface [%d]", len(n.Methods)), true)
	case *ast.ReturnStmt:
		p.printMsg("return", true)
	case *ast.BinaryExpr:

M pkg/scanner/scanner_test.go => pkg/scanner/scanner_test.go +7 -0
@@ 313,6 313,13 @@ func TestScanner(t *testing.T) {
			},
			1,
		},
		{
			"interface",
			[]tokLit{
				{token.Interface, "interface"},
			},
			0,
		},
	}
	for i, c := range cases {
		t.Run(fmt.Sprintf("%d: %s", i, c.in), func(t *testing.T) {

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 +71 -9
@@ 55,6 55,7 @@ type Typed interface {
	Node
	Type() Type
	TypeContext() TypeContext
	setType(T Type)
}

type Expr interface {


@@ 71,6 72,7 @@ type commonExpr struct {
func (c commonExpr) Type() Type               { return c.typ }
func (c commonExpr) TypeContext() TypeContext { return c.ctx }
func (c commonExpr) expr()                    {}
func (c *commonExpr) setType(T Type)          { c.typ = T }

type Decl interface {
	Typed


@@ 93,6 95,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 {


@@ 105,6 112,7 @@ func (c commonDecl) Ident() string   { return c.ident }
func (c commonDecl) Type() Type      { return c.typ }
func (c commonDecl) IsGeneric() bool { return false }
func (c commonDecl) decl()           {}
func (c *commonDecl) setType(T Type) { c.typ = T }

func AsFnDecl(n Node) *Fn {
	if fn, ok := n.(*Fn); ok {


@@ 129,9 137,10 @@ type Unit struct {
}

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



@@ 146,14 155,16 @@ 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
}

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 {


@@ 166,6 177,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`


@@ 180,14 199,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


@@ 197,6 218,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 {


@@ 209,6 231,46 @@ 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

	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
}

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/testdata/check/cycle.snow.want => pkg/semantic/testdata/check/cycle.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/cycle.snow [3, 0, 0]
file testdata/cycle.snow [3, 0, 0, 0]
  var= A [var: unresolved]
    ident B [var: unresolved]
  var= B [var: unresolved]

M pkg/semantic/testdata/check/empty.snow.want => pkg/semantic/testdata/check/empty.snow.want +1 -1
@@ 1,1 1,1 @@
file testdata/empty.snow [0, 0, 0]
file testdata/empty.snow [0, 0, 0, 0]

M pkg/semantic/testdata/check/fn.snow.want => pkg/semantic/testdata/check/fn.snow.want +1 -1
@@ 1,3 1,3 @@
file testdata/fn.snow [0, 1, 0]
file testdata/fn.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [0]

M pkg/semantic/testdata/check/fn_access_invalid_struct_field.snow.want => pkg/semantic/testdata/check/fn_access_invalid_struct_field.snow.want +2 -2
@@ 1,4 1,4 @@
file testdata/fn_access_invalid_struct_field.snow [0, 1, 1]
file testdata/fn_access_invalid_struct_field.snow [0, 1, 1, 0]
  fn test [let: () -> void]
    block [4]
      var: s [var: struct S]


@@ 16,6 16,6 @@ file testdata/fn_access_invalid_struct_field.snow [0, 1, 1]
        select [invalid: unresolved]
          ident s [var: struct S]
          ident z [invalid: unresolved]
  struct S [1, 0, 0] [type: struct S]
  struct S [1, 0, 0, 0] [type: struct S]
    var: x [var: int]
      ident int [type: int]

M pkg/semantic/testdata/check/fn_access_struct_type_field.snow.want => pkg/semantic/testdata/check/fn_access_struct_type_field.snow.want +2 -2
@@ 1,10 1,10 @@
file testdata/fn_access_struct_type_field.snow [0, 1, 1]
file testdata/fn_access_struct_type_field.snow [0, 1, 1, 0]
  fn test [let: () -> void]
    block [1]
      var= y [var: int]
        select [invalid: int]
          ident Point [type: struct Point]
          ident x [var: int]
  struct Point [1, 0, 0] [type: struct Point]
  struct Point [1, 0, 0, 0] [type: struct Point]
    var: x [var: int]
      ident int [type: int]

M pkg/semantic/testdata/check/fn_access_var_outside_struct.snow.want => pkg/semantic/testdata/check/fn_access_var_outside_struct.snow.want +3 -3
@@ 1,9 1,9 @@
file testdata/fn_access_var_outside_struct.snow [0, 1, 0]
file testdata/fn_access_var_outside_struct.snow [0, 1, 0, 0]
  fn main [let: () -> void]
    block [2]
      var: x [var: int]
        ident int [type: int]
      struct S [1, 1, 1] [type: struct S]
      struct S [1, 1, 1, 0] [type: struct S]
        var: y [var: string]
          ident string [type: string]
        fn get [let: () -> int]


@@ 11,7 11,7 @@ file testdata/fn_access_var_outside_struct.snow [0, 1, 0]
          block [1]
            return
              ident x [var: int]
        struct T [0, 1, 0] [type: struct T]
        struct T [0, 1, 0, 0] [type: struct T]
          fn get [let: () -> string]
            ident string [type: string]
            block [1]

A pkg/semantic/testdata/check/fn_assign_call_interface.snow.err => pkg/semantic/testdata/check/fn_assign_call_interface.snow.err +0 -0

A pkg/semantic/testdata/check/fn_assign_call_interface.snow.want => pkg/semantic/testdata/check/fn_assign_call_interface.snow.want +32 -0
@@ 0,0 1,32 @@
file testdata/fn_assign_call_interface.snow [0, 2, 1, 1]
  fn println [let: (string) -> void]
    @ [import, symbol] [2] [value: struct extern]
      ident extern [type: struct extern]
      string ["fmt"] [const: string]
      string ["Println"] [const: string]
    let: s [let: string]
      ident string [type: string]
  fn main [let: () -> void]
    block [2]
      let:= iface [let: interface I]
        ident I [type: interface I]
        implicit conv [value: interface I]
          call [s] [1] [value: struct S]
            ident S [type: struct S]
            string ["hello!"] [const: string]
      expr
        call [0] [value: void]
          select [let: () -> void]
            ident iface [let: interface I]
            ident foo [let: () -> void]
  struct S [1, 1, 0, 0] [type: struct S]
    let: s [let: string]
      ident string [type: string]
    fn foo [let: () -> void]
      block [1]
        expr
          call [1] [value: void]
            ident println [let: (string) -> void]
            ident s [let: string]
  interface I [1] [type: interface I]
    fn foo [let: () -> void]

M pkg/semantic/testdata/check/fn_assign_invalid.snow.want => pkg/semantic/testdata/check/fn_assign_invalid.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_assign_invalid.snow [0, 1, 0]
file testdata/fn_assign_invalid.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [2]
      var: x [var: f64]

M pkg/semantic/testdata/check/fn_assign_let.snow.want => pkg/semantic/testdata/check/fn_assign_let.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_assign_let.snow [0, 1, 0]
file testdata/fn_assign_let.snow [0, 1, 0, 0]
  fn main [let: () -> void]
    block [2]
      let= x [let: int]

M pkg/semantic/testdata/check/fn_assign_struct_fields.snow.want => pkg/semantic/testdata/check/fn_assign_struct_fields.snow.want +2 -2
@@ 1,4 1,4 @@
file testdata/fn_assign_struct_fields.snow [0, 1, 1]
file testdata/fn_assign_struct_fields.snow [0, 1, 1, 0]
  fn test [let: () -> void]
    block [8]
      var: vs [var: struct S]


@@ 35,7 35,7 @@ file testdata/fn_assign_struct_fields.snow [0, 1, 1]
          ident ls [let: struct S]
          ident z [let: () -> void]
        ident test [let: () -> void]
  struct S [2, 1, 0] [type: struct S]
  struct S [2, 1, 0, 0] [type: struct S]
    let: x [let: int]
      ident int [type: int]
    var: y [var: int]

M pkg/semantic/testdata/check/fn_assign_struct_method_to_var.snow.want => pkg/semantic/testdata/check/fn_assign_struct_method_to_var.snow.want +2 -2
@@ 1,4 1,4 @@
file testdata/fn_assign_struct_method_to_var.snow [0, 1, 1]
file testdata/fn_assign_struct_method_to_var.snow [0, 1, 1, 0]
  fn main [let: () -> void]
    block [6]
      var: s [var: struct S]


@@ 28,7 28,7 @@ file testdata/fn_assign_struct_method_to_var.snow [0, 1, 1]
        select [let: (int) -> void]
          ident s2 [let: struct S]
          ident set [let: (int) -> void]
  struct S [1, 2, 0] [type: struct S]
  struct S [1, 2, 0, 0] [type: struct S]
    var: x [var: int]
      ident int [type: int]
    fn get [let: () -> int]

M pkg/semantic/testdata/check/fn_assign_type.snow.want => pkg/semantic/testdata/check/fn_assign_type.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_assign_type.snow [0, 1, 0]
file testdata/fn_assign_type.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [1]
      assign

M pkg/semantic/testdata/check/fn_assign_unifying_type.snow.want => pkg/semantic/testdata/check/fn_assign_unifying_type.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_assign_unifying_type.snow [0, 1, 0]
file testdata/fn_assign_unifying_type.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [3]
      var: x [var: u8]

M pkg/semantic/testdata/check/fn_call_fn_value_with_labels.snow.want => pkg/semantic/testdata/check/fn_call_fn_value_with_labels.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_call_fn_value_with_labels.snow [0, 2, 0]
file testdata/fn_call_fn_value_with_labels.snow [0, 2, 0, 0]
  fn add [let: (int, int) -> int]
    let: x [let: int]
      ident int [type: int]

M pkg/semantic/testdata/check/fn_call_struct_init.snow.want => pkg/semantic/testdata/check/fn_call_struct_init.snow.want +2 -2
@@ 1,4 1,4 @@
file testdata/fn_call_struct_init.snow [0, 1, 1]
file testdata/fn_call_struct_init.snow [0, 1, 1, 0]
  fn main [let: () -> void]
    block [1]
      var= s [var: struct S]


@@ 6,7 6,7 @@ file testdata/fn_call_struct_init.snow [0, 1, 1]
          ident S [type: struct S]
          int [1] [const: int]
          string ["a"] [const: string]
  struct S [2, 0, 0] [type: struct S]
  struct S [2, 0, 0, 0] [type: struct S]
    var: x [var: int]
      ident int [type: int]
    let: y [let: string]

M pkg/semantic/testdata/check/fn_call_struct_init_no_label.snow.want => pkg/semantic/testdata/check/fn_call_struct_init_no_label.snow.want +2 -2
@@ 1,4 1,4 @@
file testdata/fn_call_struct_init_no_label.snow [0, 1, 1]
file testdata/fn_call_struct_init_no_label.snow [0, 1, 1, 0]
  fn main [let: () -> void]
    block [1]
      var= s [var: struct S]


@@ 6,7 6,7 @@ file testdata/fn_call_struct_init_no_label.snow [0, 1, 1]
          ident S [type: struct S]
          int [1] [const: int]
          string ["a"] [const: string]
  struct S [2, 0, 0] [type: struct S]
  struct S [2, 0, 0, 0] [type: struct S]
    var: x [var: int]
      ident int [type: int]
    let: y [let: string]

M pkg/semantic/testdata/check/fn_call_struct_init_only_required_no_order.snow.want => pkg/semantic/testdata/check/fn_call_struct_init_only_required_no_order.snow.want +2 -2
@@ 1,4 1,4 @@
file testdata/fn_call_struct_init_only_required_no_order.snow [0, 1, 1]
file testdata/fn_call_struct_init_only_required_no_order.snow [0, 1, 1, 0]
  fn main [let: () -> void]
    block [2]
      var= s [var: struct S]


@@ 10,7 10,7 @@ file testdata/fn_call_struct_init_only_required_no_order.snow [0, 1, 1]
        call [b] [1] [value: struct S]
          ident S [type: struct S]
          string ["b"] [const: string]
  struct S [3, 0, 0] [type: struct S]
  struct S [3, 0, 0, 0] [type: struct S]
    var: a [var: int]
      ident int [type: int]
    let: b [let: string]

M pkg/semantic/testdata/check/fn_call_struct_method.snow.want => pkg/semantic/testdata/check/fn_call_struct_method.snow.want +2 -2
@@ 1,4 1,4 @@
file testdata/fn_call_struct_method.snow [0, 1, 1]
file testdata/fn_call_struct_method.snow [0, 1, 1, 0]
  fn test [let: () -> void]
    block [2]
      var: p [var: struct Point]


@@ 9,7 9,7 @@ file testdata/fn_call_struct_method.snow [0, 1, 1]
            ident p [var: struct Point]
            ident add [let: (int) -> void]
          int [1] [const: int]
  struct Point [1, 1, 0] [type: struct Point]
  struct Point [1, 1, 0, 0] [type: struct Point]
    var: x [var: int]
      ident int [type: int]
    fn add [let: (int) -> void]

M pkg/semantic/testdata/check/fn_call_unifying_type.snow.want => pkg/semantic/testdata/check/fn_call_unifying_type.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_call_unifying_type.snow [0, 2, 0]
file testdata/fn_call_unifying_type.snow [0, 2, 0, 0]
  fn add [let: (int, int) -> int]
    let: x [let: int]
      ident int [type: int]

M pkg/semantic/testdata/check/fn_call_with_invalid_labels.snow.want => pkg/semantic/testdata/check/fn_call_with_invalid_labels.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_call_with_invalid_labels.snow [0, 2, 0]
file testdata/fn_call_with_invalid_labels.snow [0, 2, 0, 0]
  fn add [let: (int, int) -> int]
    let: x [let: int]
      ident int [type: int]

M pkg/semantic/testdata/check/fn_call_with_labels.snow.want => pkg/semantic/testdata/check/fn_call_with_labels.snow.want +2 -2
@@ 1,4 1,4 @@
file testdata/fn_call_with_labels.snow [0, 2, 1]
file testdata/fn_call_with_labels.snow [0, 2, 1, 0]
  fn add [let: (int, int) -> int]
    let: x [let: int]
      ident int [type: int]


@@ 45,7 45,7 @@ file testdata/fn_call_with_labels.snow [0, 2, 1]
                ident s [var: struct S]
              ident do [let: (int) -> void]
          int [6] [const: int]
  struct S [0, 1, 0] [type: struct S]
  struct S [0, 1, 0, 0] [type: struct S]
    fn do [let: (int) -> void]
      let: z [let: int]
        ident int [type: int]

M pkg/semantic/testdata/check/fn_call_wrong_arity.snow.want => pkg/semantic/testdata/check/fn_call_wrong_arity.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_call_wrong_arity.snow [0, 2, 0]
file testdata/fn_call_wrong_arity.snow [0, 2, 0, 0]
  fn add [let: (int, int) -> int]
    let: x [let: int]
      ident int [type: int]

M pkg/semantic/testdata/check/fn_compare.snow.want => pkg/semantic/testdata/check/fn_compare.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_compare.snow [0, 1, 0]
file testdata/fn_compare.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [2]
      var= x [var: int]

M pkg/semantic/testdata/check/fn_complex_selectors.snow.want => pkg/semantic/testdata/check/fn_complex_selectors.snow.want +3 -3
@@ 1,4 1,4 @@
file testdata/fn_complex_selectors.snow [0, 2, 1]
file testdata/fn_complex_selectors.snow [0, 2, 1, 0]
  fn create [let: () -> struct S]
    ident S [type: struct S]
    block [2]


@@ 36,12 36,12 @@ file testdata/fn_complex_selectors.snow [0, 2, 1]
                  ident s2 [var: struct T]
                ident do [let: () -> (int, () -> int)]
            ident 1 [value: () -> int]
  struct S [2, 0, 1] [type: struct S]
  struct S [2, 0, 1, 0] [type: struct S]
    var: s1 [var: int]
      ident int [type: int]
    var: s2 [var: struct T]
      ident T [type: struct T]
    struct T [1, 1, 0] [type: struct T]
    struct T [1, 1, 0, 0] [type: struct T]
      var: t1 [var: string]
        ident string [type: string]
      fn do [let: () -> (int, () -> int)]

M pkg/semantic/testdata/check/fn_duplicate_param_name.snow.want => pkg/semantic/testdata/check/fn_duplicate_param_name.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_duplicate_param_name.snow [0, 1, 0]
file testdata/fn_duplicate_param_name.snow [0, 1, 0, 0]
  fn dup [let: (int, string) -> void]
    let: x [let: int]
      ident int [type: int]

M pkg/semantic/testdata/check/fn_explicit_void.snow.want => pkg/semantic/testdata/check/fn_explicit_void.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_explicit_void.snow [0, 3, 0]
file testdata/fn_explicit_void.snow [0, 3, 0, 0]
  fn do_nothing [let: () -> void]
    ident void [type: void]
    block [1]

M pkg/semantic/testdata/check/fn_extern_pkg_before_conflict_name.snow.want => pkg/semantic/testdata/check/fn_extern_pkg_before_conflict_name.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_extern_pkg_before_conflict_name.snow [0, 1, 0]
file testdata/fn_extern_pkg_before_conflict_name.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [4]
      fn print [let: (int) -> void]

M pkg/semantic/testdata/check/fn_extern_pkg_conflict_name.snow.want => pkg/semantic/testdata/check/fn_extern_pkg_conflict_name.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_extern_pkg_conflict_name.snow [0, 1, 0]
file testdata/fn_extern_pkg_conflict_name.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [4]
      var: fmt [var: int]

M pkg/semantic/testdata/check/fn_extern_ref_method.snow.want => pkg/semantic/testdata/check/fn_extern_ref_method.snow.want +2 -2
@@ 1,7 1,7 @@
file testdata/fn_extern_ref_method.snow [0, 1, 0]
file testdata/fn_extern_ref_method.snow [0, 1, 0, 0]
  fn main [let: () -> void]
    block [1]
      struct S [0, 1, 0] [type: struct S]
      struct S [0, 1, 0, 0] [type: struct S]
        ref fn f [let: () -> void]
          @ [import, symbol] [2] [value: struct extern]
            ident extern [type: struct extern]

M pkg/semantic/testdata/check/fn_extern_with_body.snow.want => pkg/semantic/testdata/check/fn_extern_with_body.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_extern_with_body.snow [0, 1, 0]
file testdata/fn_extern_with_body.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    @ [import, symbol] [2] [value: struct extern]
      ident extern [type: struct extern]

M pkg/semantic/testdata/check/fn_fn_arg.snow.want => pkg/semantic/testdata/check/fn_fn_arg.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_fn_arg.snow [0, 3, 0]
file testdata/fn_fn_arg.snow [0, 3, 0, 0]
  fn do [let: (int, (int) -> int) -> int]
    let: x [let: int]
      ident int [type: int]

M pkg/semantic/testdata/check/fn_generic_decl_after_inst.snow.want => pkg/semantic/testdata/check/fn_generic_decl_after_inst.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_generic_decl_after_inst.snow [0, 2, 0]
file testdata/fn_generic_decl_after_inst.snow [0, 2, 0, 0]
  fn main [let: () -> void]
    block [1]
      let= a [let: int]

M pkg/semantic/testdata/check/fn_generic_fn_uses_generic_fn.snow.want => pkg/semantic/testdata/check/fn_generic_fn_uses_generic_fn.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_generic_fn_uses_generic_fn.snow [0, 3, 0]
file testdata/fn_generic_fn_uses_generic_fn.snow [0, 3, 0, 0]
  fn A [$1] [let: ($T) -> $T]
    generic type $T [type: $T]
    let: v [let: $T]

M pkg/semantic/testdata/check/fn_generic_identity.snow.want => pkg/semantic/testdata/check/fn_generic_identity.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_generic_identity.snow [0, 5, 0]
file testdata/fn_generic_identity.snow [0, 5, 0, 0]
  fn id [$1] [let: ($T) -> $T]
    generic type $T [type: $T]
    let: v [let: $T]

A pkg/semantic/testdata/check/fn_generic_interface.snow.err => pkg/semantic/testdata/check/fn_generic_interface.snow.err +1 -0
@@ 0,0 1,1 @@
testdata/fn_generic_interface.snow:23:14: cannot assign type struct G[bool] to variable of type interface I[int]

A pkg/semantic/testdata/check/fn_generic_interface.snow.want => pkg/semantic/testdata/check/fn_generic_interface.snow.want +82 -0
@@ 0,0 1,82 @@
file testdata/fn_generic_interface.snow [0, 1, 2, 1]
  fn main [let: () -> void]
    block [10]
      var:= ifaceInt [var: interface I[int]]
        generic inst [1] [type: interface I[int]]
          ident I [type: interface I]
          ident int [type: int]
        implicit conv [value: interface I[int]]
          call [0] [value: struct S]
            ident S [type: struct S]
      var= res [var: int]
        call [1] [value: int]
          select [let: (int) -> int]
            ident ifaceInt [var: interface I[int]]
            ident foo [let: (int) -> int]
          int [1] [const: int]
      var: gInt [var: struct G[int]]
        generic inst [1] [type: struct G[int]]
          ident G [type: struct G]
          ident int [type: int]
      var= gres [var: int]
        call [1] [value: int]
          select [let: (int) -> int]
            ident gInt [var: struct G[int]]
            ident foo [let: (int) -> int]
          int [1] [const: int]
      assign
        ident ifaceInt [var: interface I[int]]
        implicit conv [value: interface I[int]]
          call [0] [value: struct G[int]]
            generic inst [1] [type: struct G[int]]
              ident G [type: struct G]
              ident int [type: int]
      assign
        ident res [var: int]
        call [1] [value: int]
          select [let: (int) -> int]
            ident ifaceInt [var: interface I[int]]
            ident foo [let: (int) -> int]
          int [2] [const: int]
      assign
        ident ifaceInt [var: interface I[int]]
        call [0] [value: struct G[bool]]
          generic inst [1] [type: struct G[bool]]
            ident G [type: struct G]
            ident bool [type: bool]
      var: ifaceString [var: interface I[string]]
        generic inst [1] [type: interface I[string]]
          ident I [type: interface I]
          ident string [type: string]
      assign
        ident ifaceString [var: interface I[string]]
        implicit conv [value: interface I[string]]
          call [0] [value: struct G[string]]
            generic inst [1] [type: struct G[string]]
              ident G [type: struct G]
              ident string [type: string]
      expr
        call [1] [value: string]
          select [let: (string) -> string]
            ident ifaceString [var: interface I[string]]
            ident foo [let: (string) -> string]
          string ["a"] [const: string]
  struct S [0, 1, 0, 0] [type: struct S]
    fn foo [let: (int) -> int]
      let: i [let: int]
        ident int [type: int]
      ident int [type: int]
      block [0]
  struct G [0, 1, 0, 0, $1] [type: struct G]
    generic type $T [type: $T]
    fn foo [let: ($T) -> $T]
      let: t [let: $T]
        ident $T [type: $T]
      ident $T [type: $T]
      block [0]
  interface I [1, $1] [type: interface I]
    generic type $T [type: $T]
    fn foo [let: ($T) -> $T]
      let: t [let: $T]
        ident $T [type: $T]
      ident $T [type: $T]

M pkg/semantic/testdata/check/fn_generic_unused_in_signature.snow.want => pkg/semantic/testdata/check/fn_generic_unused_in_signature.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_generic_unused_in_signature.snow [0, 6, 0]
file testdata/fn_generic_unused_in_signature.snow [0, 6, 0, 0]
  fn g1 [$2] [let: (int) -> int]
    generic type $T [type: $T]
    generic type $U [type: $U]

M pkg/semantic/testdata/check/fn_guard_fallthrough.snow.want => pkg/semantic/testdata/check/fn_guard_fallthrough.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_guard_fallthrough.snow [0, 1, 0]
file testdata/fn_guard_fallthrough.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [3]
      var: x [var: bool]

M pkg/semantic/testdata/check/fn_ident_as_type.snow.want => pkg/semantic/testdata/check/fn_ident_as_type.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_ident_as_type.snow [1, 1, 0]
file testdata/fn_ident_as_type.snow [1, 1, 0, 0]
  var: x [var: () -> void]
    ident test [let: () -> void]
  fn test [let: () -> void]

M pkg/semantic/testdata/check/fn_init_order.snow.want => pkg/semantic/testdata/check/fn_init_order.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_init_order.snow [0, 1, 0]
file testdata/fn_init_order.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [2]
      var= A [var: unresolved]

M pkg/semantic/testdata/check/fn_invalid_attr.snow.want => pkg/semantic/testdata/check/fn_invalid_attr.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_invalid_attr.snow [0, 1, 0]
file testdata/fn_invalid_attr.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    @ [x] [1] [value: unresolved]
      ident invalid [invalid: unresolved]

M pkg/semantic/testdata/check/fn_invalid_extern_fields.snow.want => pkg/semantic/testdata/check/fn_invalid_extern_fields.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_invalid_extern_fields.snow [0, 3, 0]
file testdata/fn_invalid_extern_fields.snow [0, 3, 0, 0]
  fn test1 [let: () -> void]
    @ [badField] [1] [value: struct extern]
      ident extern [type: struct extern]

M pkg/semantic/testdata/check/fn_invalid_generic_use_in_fn.snow.want => pkg/semantic/testdata/check/fn_invalid_generic_use_in_fn.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_invalid_generic_use_in_fn.snow [0, 1, 0]
file testdata/fn_invalid_generic_use_in_fn.snow [0, 1, 0, 0]
  fn g [$2] [let: ($T, $U) -> void]
    generic type $T [type: $T]
    generic type $U [type: $U]

M pkg/semantic/testdata/check/fn_invalid_main.snow.want => pkg/semantic/testdata/check/fn_invalid_main.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_invalid_main.snow [0, 1, 0]
file testdata/fn_invalid_main.snow [0, 1, 0, 0]
  fn main [let: (int) -> string]
    let: x [let: int]
      ident int [type: int]

M pkg/semantic/testdata/check/fn_invalid_ref.snow.want => pkg/semantic/testdata/check/fn_invalid_ref.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_invalid_ref.snow [0, 1, 0]
file testdata/fn_invalid_ref.snow [0, 1, 0, 0]
  fn main [let: () -> void]
    block [1]
      ref fn test [let: () -> void]

M pkg/semantic/testdata/check/fn_invalid_ref_call.snow.want => pkg/semantic/testdata/check/fn_invalid_ref_call.snow.want +2 -2
@@ 1,7 1,7 @@
file testdata/fn_invalid_ref_call.snow [0, 1, 0]
file testdata/fn_invalid_ref_call.snow [0, 1, 0, 0]
  fn main [let: () -> void]
    block [3]
      struct S [1, 1, 0] [type: struct S]
      struct S [1, 1, 0, 0] [type: struct S]
        var: x [var: int]
          ident int [type: int]
        ref fn set [let: (int) -> void]

M pkg/semantic/testdata/check/fn_invalid_ref_call_via_value.snow.want => pkg/semantic/testdata/check/fn_invalid_ref_call_via_value.snow.want +2 -2
@@ 1,7 1,7 @@
file testdata/fn_invalid_ref_call_via_value.snow [0, 1, 0]
file testdata/fn_invalid_ref_call_via_value.snow [0, 1, 0, 0]
  fn main [let: () -> void]
    block [3]
      struct S [1, 1, 0] [type: struct S]
      struct S [1, 1, 0, 0] [type: struct S]
        var: x [var: int]
          ident int [type: int]
        ref fn set [let: (int) -> void]

M pkg/semantic/testdata/check/fn_invalid_return.snow.want => pkg/semantic/testdata/check/fn_invalid_return.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_invalid_return.snow [0, 1, 0]
file testdata/fn_invalid_return.snow [0, 1, 0, 0]
  fn test [let: () -> uint]
    ident uint [type: uint]
    block [1]

M pkg/semantic/testdata/check/fn_invalid_tuple_access.snow.want => pkg/semantic/testdata/check/fn_invalid_tuple_access.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_invalid_tuple_access.snow [0, 1, 0]
file testdata/fn_invalid_tuple_access.snow [0, 1, 0, 0]
  fn main [let: () -> void]
    block [3]
      var: x [var: (int, string, (bool, uint))]

M pkg/semantic/testdata/check/fn_main_extern.snow.want => pkg/semantic/testdata/check/fn_main_extern.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_main_extern.snow [0, 1, 0]
file testdata/fn_main_extern.snow [0, 1, 0, 0]
  fn main [let: () -> void]
    @ [import, symbol] [2] [value: struct extern]
      ident extern [type: struct extern]

M pkg/semantic/testdata/check/fn_many_extern.snow.want => pkg/semantic/testdata/check/fn_many_extern.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_many_extern.snow [0, 1, 0]
file testdata/fn_many_extern.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    @ [import, symbol] [2] [value: struct extern]
      ident extern [type: struct extern]

M pkg/semantic/testdata/check/fn_method_explicit_self.snow.want => pkg/semantic/testdata/check/fn_method_explicit_self.snow.want +2 -2
@@ 1,4 1,4 @@
file testdata/fn_method_explicit_self.snow [0, 1, 1]
file testdata/fn_method_explicit_self.snow [0, 1, 1, 0]
  fn main [let: () -> void]
    block [2]
      var: s [var: struct S]


@@ 8,7 8,7 @@ file testdata/fn_method_explicit_self.snow [0, 1, 1]
          select [let: () -> int]
            ident s [var: struct S]
            ident getX [let: () -> int]
  struct S [1, 1, 0] [type: struct S]
  struct S [1, 1, 0, 0] [type: struct S]
    var: x [var: int]
      ident int [type: int]
    fn getX [let: () -> int]

M pkg/semantic/testdata/check/fn_multi_vars_per_decl.snow.want => pkg/semantic/testdata/check/fn_multi_vars_per_decl.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_multi_vars_per_decl.snow [0, 1, 0]
file testdata/fn_multi_vars_per_decl.snow [0, 1, 0, 0]
  fn main [let: () -> void]
    block [3]
      var:= x [var: int]

M pkg/semantic/testdata/check/fn_nested_block.snow.want => pkg/semantic/testdata/check/fn_nested_block.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_nested_block.snow [0, 1, 0]
file testdata/fn_nested_block.snow [0, 1, 0, 0]
  fn test [let: (int, int) -> int]
    let: x [let: int]
      ident int [type: int]

M pkg/semantic/testdata/check/fn_nested_fn.snow.want => pkg/semantic/testdata/check/fn_nested_fn.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_nested_fn.snow [0, 1, 0]
file testdata/fn_nested_fn.snow [0, 1, 0, 0]
  fn main [let: () -> void]
    block [4]
      fn add [let: (int, int) -> int]

M pkg/semantic/testdata/check/fn_nested_fn_init_order.snow.want => pkg/semantic/testdata/check/fn_nested_fn_init_order.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_nested_fn_init_order.snow [0, 1, 0]
file testdata/fn_nested_fn_init_order.snow [0, 1, 0, 0]
  fn main [let: () -> void]
    block [3]
      fn A [let: () -> void]

M pkg/semantic/testdata/check/fn_nested_generic_fn.snow.want => pkg/semantic/testdata/check/fn_nested_generic_fn.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_nested_generic_fn.snow [0, 3, 0]
file testdata/fn_nested_generic_fn.snow [0, 3, 0, 0]
  fn call [let: ((bool) -> bool) -> bool]
    let: f [let: (bool) -> bool]
      sig [1->1] [type: (bool) -> bool]

M pkg/semantic/testdata/check/fn_nested_struct_method.snow.want => pkg/semantic/testdata/check/fn_nested_struct_method.snow.want +3 -3
@@ 1,7 1,7 @@
file testdata/fn_nested_struct_method.snow [0, 1, 0]
file testdata/fn_nested_struct_method.snow [0, 1, 0, 0]
  fn main [let: () -> void]
    block [6]
      struct S [1, 1, 1] [type: struct S]
      struct S [1, 1, 1, 0] [type: struct S]
        var: x [var: string]
          ident string [type: string]
        ref fn init [let: () -> void]


@@ 9,7 9,7 @@ file testdata/fn_nested_struct_method.snow [0, 1, 0]
            assign
              ident x [var: string]
              string ["hello"] [const: string]
        struct T [1, 1, 0] [type: struct T]
        struct T [1, 1, 0, 0] [type: struct T]
          var: y [var: string]
            ident string [type: string]
          ref fn append [let: (string) -> void]

M pkg/semantic/testdata/check/fn_nested_struct_self.snow.want => pkg/semantic/testdata/check/fn_nested_struct_self.snow.want +3 -3
@@ 1,8 1,8 @@
file testdata/fn_nested_struct_self.snow [0, 0, 1]
  struct S [1, 0, 1] [type: struct S]
file testdata/fn_nested_struct_self.snow [0, 0, 1, 0]
  struct S [1, 0, 1, 0] [type: struct S]
    var: x [var: string]
      ident string [type: string]
    struct T [1, 1, 0] [type: struct T]
    struct T [1, 1, 0, 0] [type: struct T]
      var: x [var: int]
        ident int [type: int]
      fn negate [let: () -> int]

M pkg/semantic/testdata/check/fn_nested_structs.snow.want => pkg/semantic/testdata/check/fn_nested_structs.snow.want +3 -3
@@ 1,10 1,10 @@
file testdata/fn_nested_structs.snow [0, 1, 0]
file testdata/fn_nested_structs.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [3]
      struct Outer [1, 0, 1] [type: struct Outer]
      struct Outer [1, 0, 1, 0] [type: struct Outer]
        let: x [let: struct Inner]
          ident Inner [type: struct Inner]
        struct Inner [1, 0, 0] [type: struct Inner]
        struct Inner [1, 0, 0, 0] [type: struct Inner]
          let: y [let: int]
            ident int [type: int]
      var: o [var: struct Outer]

M pkg/semantic/testdata/check/fn_nested_tuple_type.snow.want => pkg/semantic/testdata/check/fn_nested_tuple_type.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_nested_tuple_type.snow [0, 1, 0]
file testdata/fn_nested_tuple_type.snow [0, 1, 0, 0]
  fn main [let: () -> void]
    block [1]
      var: x [var: (int, (bool, string))]

M pkg/semantic/testdata/check/fn_non_type_selectors.snow.want => pkg/semantic/testdata/check/fn_non_type_selectors.snow.want +3 -3
@@ 1,4 1,4 @@
file testdata/fn_non_type_selectors.snow [2, 1, 1]
file testdata/fn_non_type_selectors.snow [2, 1, 1, 0]
  var: x [var: int]
    ident int [type: int]
  let: y [let: string]


@@ 40,9 40,9 @@ file testdata/fn_non_type_selectors.snow [2, 1, 1]
              ident S [type: struct S]
              ident T [type: struct T]
            ident tt [var: int]
  struct S [1, 0, 1] [type: struct S]
  struct S [1, 0, 1, 0] [type: struct S]
    var: ss [var: int]
      ident int [type: int]
    struct T [1, 0, 0] [type: struct T]
    struct T [1, 0, 0, 0] [type: struct T]
      var: tt [var: int]
        ident int [type: int]

M pkg/semantic/testdata/check/fn_param_type_is_var_in_body.snow.want => pkg/semantic/testdata/check/fn_param_type_is_var_in_body.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_param_type_is_var_in_body.snow [0, 1, 0]
file testdata/fn_param_type_is_var_in_body.snow [0, 1, 0, 0]
  fn test [let: (int) -> void]
    let: x [let: int]
      ident int [type: int]

M pkg/semantic/testdata/check/fn_params.snow.want => pkg/semantic/testdata/check/fn_params.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_params.snow [0, 1, 0]
file testdata/fn_params.snow [0, 1, 0, 0]
  fn test [let: (int, int) -> int]
    let: x [let: int]
      ident int [type: int]

M pkg/semantic/testdata/check/fn_params_locals.snow.want => pkg/semantic/testdata/check/fn_params_locals.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_params_locals.snow [0, 1, 0]
file testdata/fn_params_locals.snow [0, 1, 0, 0]
  fn test [let: (int, int) -> int]
    let: x [let: int]
      ident int [type: int]

M pkg/semantic/testdata/check/fn_recursion.snow.want => pkg/semantic/testdata/check/fn_recursion.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_recursion.snow [0, 1, 0]
file testdata/fn_recursion.snow [0, 1, 0, 0]
  fn test [let: (int) -> int]
    let: x [let: int]
      ident int [type: int]

M pkg/semantic/testdata/check/fn_ref_on_fn_nested_in_method.snow.want => pkg/semantic/testdata/check/fn_ref_on_fn_nested_in_method.snow.want +2 -2
@@ 1,5 1,5 @@
file testdata/fn_ref_on_fn_nested_in_method.snow [0, 0, 1]
  struct S [1, 1, 0] [type: struct S]
file testdata/fn_ref_on_fn_nested_in_method.snow [0, 0, 1, 0]
  struct S [1, 1, 0, 0] [type: struct S]
    var: x [var: int]
      ident int [type: int]
    ref fn rf [let: () -> void]

M pkg/semantic/testdata/check/fn_return_internal_struct.snow.want => pkg/semantic/testdata/check/fn_return_internal_struct.snow.want +2 -2
@@ 1,8 1,8 @@
file testdata/fn_return_internal_struct.snow [0, 1, 0]
file testdata/fn_return_internal_struct.snow [0, 1, 0, 0]
  fn test [let: () -> unresolved]
    ident S [invalid: unresolved]
    block [3]
      struct S [0, 0, 0] [type: struct S]
      struct S [0, 0, 0, 0] [type: struct S]
      var: s [var: struct S]
        ident S [type: struct S]
      return

M pkg/semantic/testdata/check/fn_return_missing_value.snow.want => pkg/semantic/testdata/check/fn_return_missing_value.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_return_missing_value.snow [0, 1, 0]
file testdata/fn_return_missing_value.snow [0, 1, 0, 0]
  fn test [let: () -> int]
    ident int [type: int]
    block [1]

M pkg/semantic/testdata/check/fn_return_struct.snow.want => pkg/semantic/testdata/check/fn_return_struct.snow.want +2 -2
@@ 1,4 1,4 @@
file testdata/fn_return_struct.snow [0, 2, 1]
file testdata/fn_return_struct.snow [0, 2, 1, 0]
  fn newS [let: () -> struct S]
    ident S [type: struct S]
    block [2]


@@ 42,7 42,7 @@ file testdata/fn_return_struct.snow [0, 2, 1]
            ident newS [let: () -> struct S]
          ident z [let: () -> void]
        ident test [let: () -> void]
  struct S [2, 1, 0] [type: struct S]
  struct S [2, 1, 0, 0] [type: struct S]
    let: x [let: int]
      ident int [type: int]
    var: y [var: int]

M pkg/semantic/testdata/check/fn_return_unifying_type.snow.want => pkg/semantic/testdata/check/fn_return_unifying_type.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_return_unifying_type.snow [0, 1, 0]
file testdata/fn_return_unifying_type.snow [0, 1, 0, 0]
  fn test [let: () -> i16]
    ident i16 [type: i16]
    block [2]

M pkg/semantic/testdata/check/fn_struct_main_method.snow.want => pkg/semantic/testdata/check/fn_struct_main_method.snow.want +2 -2
@@ 1,7 1,7 @@
file testdata/fn_struct_main_method.snow [0, 1, 1]
file testdata/fn_struct_main_method.snow [0, 1, 1, 0]
  fn main [let: () -> void]
    block [0]
  struct S [0, 1, 0] [type: struct S]
  struct S [0, 1, 0, 0] [type: struct S]
    fn main [let: (int) -> void]
      let: x [let: int]
        ident int [type: int]

M pkg/semantic/testdata/check/fn_struct_method_access_top_level.snow.want => pkg/semantic/testdata/check/fn_struct_method_access_top_level.snow.want +2 -2
@@ 1,9 1,9 @@
file testdata/fn_struct_method_access_top_level.snow [1, 1, 1]
file testdata/fn_struct_method_access_top_level.snow [1, 1, 1, 0]
  var: x [var: int]
    ident int [type: int]
  fn main [let: () -> void]
    block [0]
  struct S [0, 1, 0] [type: struct S]
  struct S [0, 1, 0, 0] [type: struct S]
    fn get [let: () -> int]
      ident int [type: int]
      block [1]

M pkg/semantic/testdata/check/fn_struct_order_independent.snow.want => pkg/semantic/testdata/check/fn_struct_order_independent.snow.want +2 -2
@@ 1,5 1,5 @@
file testdata/fn_struct_order_independent.snow [0, 0, 1]
  struct S [2, 1, 0] [type: struct S]
file testdata/fn_struct_order_independent.snow [0, 0, 1, 0]
  struct S [2, 1, 0, 0] [type: struct S]
    var: x [var: int]
      ident int [type: int]
    let: y [let: int]

M pkg/semantic/testdata/check/fn_struct_same_name_diff_scope.snow.want => pkg/semantic/testdata/check/fn_struct_same_name_diff_scope.snow.want +3 -3
@@ 1,11 1,11 @@
file testdata/fn_struct_same_name_diff_scope.snow [0, 1, 0]
file testdata/fn_struct_same_name_diff_scope.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [3]
      struct A [0, 0, 0] [type: struct A]
      struct A [0, 0, 0, 0] [type: struct A]
      var: a [var: struct A]
        ident A [type: struct A]
      block [3]
        struct A [0, 0, 0] [type: struct A]
        struct A [0, 0, 0, 0] [type: struct A]
        var: b [var: struct A]
          ident A [type: struct A]
        assign

M pkg/semantic/testdata/check/fn_struct_selector.snow.want => pkg/semantic/testdata/check/fn_struct_selector.snow.want +2 -2
@@ 1,4 1,4 @@
file testdata/fn_struct_selector.snow [0, 1, 1]
file testdata/fn_struct_selector.snow [0, 1, 1, 0]
  fn test [let: () -> void]
    block [2]
      var: p [var: struct Point]


@@ 7,6 7,6 @@ file testdata/fn_struct_selector.snow [0, 1, 1]
        select [let: int]
          ident p [var: struct Point]
          ident x [let: int]
  struct Point [1, 0, 0] [type: struct Point]
  struct Point [1, 0, 0, 0] [type: struct Point]
    let: x [let: int]
      ident int [type: int]

M pkg/semantic/testdata/check/fn_struct_self_shadow.snow.want => pkg/semantic/testdata/check/fn_struct_self_shadow.snow.want +2 -2
@@ 1,5 1,5 @@
file testdata/fn_struct_self_shadow.snow [0, 0, 1]
  struct S [1, 1, 0] [type: struct S]
file testdata/fn_struct_self_shadow.snow [0, 0, 1, 0]
  struct S [1, 1, 0, 0] [type: struct S]
    var: self [var: int]
      ident int [type: int]
    fn get [let: () -> int]

M pkg/semantic/testdata/check/fn_struct_self_uses.snow.want => pkg/semantic/testdata/check/fn_struct_self_uses.snow.want +2 -2
@@ 1,5 1,5 @@
file testdata/fn_struct_self_uses.snow [0, 0, 1]
  struct S [0, 1, 0] [type: struct S]
file testdata/fn_struct_self_uses.snow [0, 0, 1, 0]
  struct S [0, 1, 0, 0] [type: struct S]
    fn set [let: () -> void]
      block [1]
        var: self [var: int]

M pkg/semantic/testdata/check/fn_tuple_assign_compatible_types.snow.want => pkg/semantic/testdata/check/fn_tuple_assign_compatible_types.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_tuple_assign_compatible_types.snow [0, 1, 0]
file testdata/fn_tuple_assign_compatible_types.snow [0, 1, 0, 0]
  fn main [let: () -> void]
    block [4]
      var: i [var: i16]

M pkg/semantic/testdata/check/fn_tuple_assign_incompatible_types.snow.want => pkg/semantic/testdata/check/fn_tuple_assign_incompatible_types.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_tuple_assign_incompatible_types.snow [0, 1, 0]
file testdata/fn_tuple_assign_incompatible_types.snow [0, 1, 0, 0]
  fn main [let: () -> void]
    block [4]
      var: t [var: (i32, u16, bool)]

M pkg/semantic/testdata/check/fn_tuple_expr_select_field.snow.want => pkg/semantic/testdata/check/fn_tuple_expr_select_field.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_tuple_expr_select_field.snow [0, 1, 0]
file testdata/fn_tuple_expr_select_field.snow [0, 1, 0, 0]
  fn main [let: () -> void]
    block [4]
      var= t1 [var: (int, int, int)]

M pkg/semantic/testdata/check/fn_type_as_value.snow.want => pkg/semantic/testdata/check/fn_type_as_value.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_type_as_value.snow [0, 1, 0]
file testdata/fn_type_as_value.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [1]
      let= res [let: int]

M pkg/semantic/testdata/check/fn_unknown_symbol.snow.want => pkg/semantic/testdata/check/fn_unknown_symbol.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_unknown_symbol.snow [0, 1, 0]
file testdata/fn_unknown_symbol.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [1]
      expr

M pkg/semantic/testdata/check/fn_var_as_param_type.snow.want => pkg/semantic/testdata/check/fn_var_as_param_type.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_var_as_param_type.snow [3, 1, 0]
file testdata/fn_var_as_param_type.snow [3, 1, 0, 0]
  var: x [var: int]
    ident int [type: int]
  var: f [var: (int) -> void]

M pkg/semantic/testdata/check/fn_without_body.snow.want => pkg/semantic/testdata/check/fn_without_body.snow.want +1 -1
@@ 1,2 1,2 @@
file testdata/fn_without_body.snow [0, 1, 0]
file testdata/fn_without_body.snow [0, 1, 0, 0]
  fn test [let: () -> void]

M pkg/semantic/testdata/check/fns.snow.want => pkg/semantic/testdata/check/fns.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fns.snow [0, 3, 0]
file testdata/fns.snow [0, 3, 0, 0]
  fn add [let: (int, int) -> int]
    let: x [let: int]
      ident int [type: int]

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]

M pkg/semantic/testdata/check/generic_struct_instantiation.snow.want => pkg/semantic/testdata/check/generic_struct_instantiation.snow.want +2 -2
@@ 1,4 1,4 @@
file testdata/generic_struct_instantiation.snow [0, 1, 1]
file testdata/generic_struct_instantiation.snow [0, 1, 1, 0]
  fn main [let: () -> void]
    block [2]
      let= g1 [let: struct G[int]]


@@ 11,7 11,7 @@ file testdata/generic_struct_instantiation.snow [0, 1, 1]
        generic inst [1] [type: struct G[string]]
          ident G [type: struct G]
          ident string [type: string]
  struct G [1, 0, 0, $1] [type: struct G]
  struct G [1, 0, 0, 0, $1] [type: struct G]
    generic type $T [type: $T]
    var: x [var: $T]
      ident $T [type: $T]

M pkg/semantic/testdata/check/guard_else.snow.want => pkg/semantic/testdata/check/guard_else.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/guard_else.snow [0, 1, 0]
file testdata/guard_else.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [3]
      var= x [var: bool]

M pkg/semantic/testdata/check/if_else_if.snow.want => pkg/semantic/testdata/check/if_else_if.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/if_else_if.snow [0, 1, 0]
file testdata/if_else_if.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [3]
      var= x [var: bool]

M pkg/semantic/testdata/check/if_non_bool.snow.want => pkg/semantic/testdata/check/if_non_bool.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/if_non_bool.snow [0, 1, 0]
file testdata/if_non_bool.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [2]
      var= x [var: int]

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]

A pkg/semantic/testdata/check/interface_satisfied.snow.err => pkg/semantic/testdata/check/interface_satisfied.snow.err +7 -0
@@ 0,0 1,7 @@
testdata/interface_satisfied.snow:39:11: cannot assign type int to variable of type interface Empty
testdata/interface_satisfied.snow:42:7: cannot assign type struct S2 to variable of type interface Foo
testdata/interface_satisfied.snow:43:7: cannot assign type struct S3 to variable of type interface Foo
testdata/interface_satisfied.snow:51:7: cannot assign type struct S4 to variable of type interface Foo
testdata/interface_satisfied.snow:53:7: cannot assign type struct S4 to variable of type interface Foo
testdata/interface_satisfied.snow:59:9: cannot assign type (int, struct S4) to variable of type (int, interface Foo)
testdata/interface_satisfied.snow:63:10: cannot assign type (int, struct S4, (bool, struct S4)) to variable of type (int, interface Foo, (bool, interface Foo))

A pkg/semantic/testdata/check/interface_satisfied.snow.want => pkg/semantic/testdata/check/interface_satisfied.snow.want +164 -0
@@ 0,0 1,164 @@
file testdata/interface_satisfied.snow [0, 2, 4, 2]
  fn get_s4 [let: () -> struct S4]
    ident S4 [type: struct S4]
    block [1]
      return
        call [0] [value: struct S4]
          ident S4 [type: struct S4]
  fn main [let: () -> void]
    block [25]
      var: empty [var: interface Empty]
        ident Empty [type: interface Empty]
      var: f [var: interface Foo]
        ident Foo [type: interface Foo]
      var: integer [var: int]
        ident int [type: int]
      var: s1 [var: struct S1]
        ident S1 [type: struct S1]
      assign
        ident empty [var: interface Empty]
        ident empty [var: interface Empty]
      assign
        ident empty [var: interface Empty]
        implicit conv [value: interface Empty]
          ident f [var: interface Foo]
      assign
        ident empty [var: interface Empty]
        implicit conv [value: interface Empty]
          ident s1 [var: struct S1]
      assign
        ident empty [var: interface Empty]
        ident integer [var: int]
      assign
        ident f [var: interface Foo]
        implicit conv [value: interface Foo]
          call [0] [value: struct S1]
            ident S1 [type: struct S1]
      assign
        ident f [var: interface Foo]
        call [0] [value: struct S2]
          ident S2 [type: struct S2]
      assign
        ident f [var: interface Foo]
        call [0] [value: struct S3]
          ident S3 [type: struct S3]
      var= vs4 [var: struct S4]
        call [0] [value: struct S4]
          ident S4 [type: struct S4]
      let= ls4 [let: struct S4]
        call [0] [value: struct S4]
          ident S4 [type: struct S4]
      assign
        ident f [var: interface Foo]
        implicit conv [value: interface Foo]
          ident vs4 [var: struct S4]
      assign
        ident f [var: interface Foo]
        ident ls4 [let: struct S4]
      assign
        ident f [var: interface Foo]
        call [0] [value: struct S4]
          ident S4 [type: struct S4]
      var: tup [var: (int, interface Foo)]
        tuple type [2] [type: (int, interface Foo)]
          ident int [type: int]
          ident Foo [type: interface Foo]
      assign
        ident tup [var: (int, interface Foo)]
        implicit conv [value: (int, interface Foo)]
          tuple value [2] [value: (int, struct S4)]
            int [1] [const: int]
            ident vs4 [var: struct S4]
      assign
        ident tup [var: (int, interface Foo)]
        tuple value [2] [value: (int, struct S4)]
          int [1] [const: int]
          ident ls4 [let: struct S4]
      var: tup2 [var: (int, interface Foo, (bool, interface Foo))]
        tuple type [3] [type: (int, interface Foo, (bool, interface Foo))]
          ident int [type: int]
          ident Foo [type: interface Foo]
          tuple type [2] [type: (bool, interface Foo)]
            ident bool [type: bool]
            ident Foo [type: interface Foo]
      assign
        ident tup2 [var: (int, interface Foo, (bool, interface Foo))]
        implicit conv [value: (int, interface Foo, (bool, interface Foo))]
          tuple value [3] [value: (int, struct S4, (bool, struct S4))]
            int [1] [const: int]
            ident vs4 [var: struct S4]
            tuple value [2] [value: (bool, struct S4)]
              ident true [let: bool]
              ident vs4 [var: struct S4]
      assign
        ident tup2 [var: (int, interface Foo, (bool, interface Foo))]
        tuple value [3] [value: (int, struct S4, (bool, struct S4))]
          int [1] [const: int]
          ident ls4 [let: struct S4]
          tuple value [2] [value: (bool, struct S4)]
            ident true [let: bool]
            call [0] [value: struct S4]
              ident get_s4 [let: () -> struct S4]
      var: tup3 [var: (int, (interface Foo, interface Empty))]
        tuple type [2] [type: (int, (interface Foo, interface Empty))]
          ident int [type: int]
          tuple type [2] [type: (interface Foo, interface Empty)]
            ident Foo [type: interface Foo]
            paren [type: interface Empty]
              ident Empty [type: interface Empty]
      assign
        ident tup3 [var: (int, (interface Foo, interface Empty))]
        implicit conv [value: (int, (interface Foo, interface Empty))]
          tuple value [2] [value: (int, (struct S4, struct S4))]
            int [3] [const: int]
            tuple value [2] [value: (struct S4, struct S4)]
              ident vs4 [var: struct S4]
              paren [let: struct S4]
                ident ls4 [let: struct S4]
      assign
        ident tup3 [var: (int, (interface Foo, interface Empty))]
        implicit conv [value: (int, (interface Foo, interface Empty))]
          tuple value [2] [value: (int, (struct S4, struct S4))]
            int [3] [const: int]
            tuple value [2] [value: (struct S4, struct S4)]
              ident vs4 [var: struct S4]
              paren [value: struct S4]
                call [0] [value: struct S4]
                  ident get_s4 [let: () -> struct S4]
  struct S1 [0, 2, 0, 0] [type: struct S1]
    fn foo [let: (int) -> int]
      let: x [let: int]
        ident int [type: int]
      ident int [type: int]
      block [0]
    fn bar [let: (string) -> void]
      let: s [let: string]
        ident string [type: string]
      block [0]
  struct S2 [0, 2, 0, 0] [type: struct S2]
    fn bar [let: (string) -> void]
      let: s [let: string]
        ident string [type: string]
      block [0]
    fn quz [let: (bool) -> void]
      let: b [let: bool]
        ident bool [type: bool]
      block [0]
  struct S3 [0, 1, 0, 0] [type: struct S3]
    fn foo [let: (uint) -> int]
      let: u [let: uint]
        ident uint [type: uint]
      ident int [type: int]
      block [0]
  struct S4 [0, 1, 0, 0] [type: struct S4]
    ref fn foo [let: (int) -> int]
      let: i [let: int]
        ident int [type: int]
      ident int [type: int]
      block [0]
  interface Empty [0] [type: interface Empty]
  interface Foo [1] [type: interface Foo]
    fn foo [let: (int) -> int]
      let: i [let: int]
        ident int [type: int]
      ident int [type: int]

M pkg/semantic/testdata/check/invalid_binary_op.snow.want => pkg/semantic/testdata/check/invalid_binary_op.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/invalid_binary_op.snow [3, 0, 0]
file testdata/invalid_binary_op.snow [3, 0, 0, 0]
  var= x [var: int]
    int [3] [const: int]
  var= y [var: string]

A pkg/semantic/testdata/check/invalid_ref_fn_assign.snow.err => pkg/semantic/testdata/check/invalid_ref_fn_assign.snow.err +2 -0
@@ 0,0 1,2 @@
testdata/invalid_ref_fn_assign.snow:14:16: cannot access ref fn foo; left-hand side must be var, is let
testdata/invalid_ref_fn_assign.snow:15:21: cannot access ref fn foo; left-hand side must be var, is value

A pkg/semantic/testdata/check/invalid_ref_fn_assign.snow.want => pkg/semantic/testdata/check/invalid_ref_fn_assign.snow.want +45 -0
@@ 0,0 1,45 @@
file testdata/invalid_ref_fn_assign.snow [0, 2, 1, 0]
  fn get_s [let: () -> struct S]
    ident S [type: struct S]
    block [1]
      return
        call [0] [value: struct S]
          ident S [type: struct S]
  fn main [let: () -> void]
    block [6]
      var: tup [var: (int, () -> void)]
        tuple type [2] [type: (int, () -> void)]
          ident int [type: int]
          sig [0->1] [type: () -> void]
            ident void [type: void]
      var= s1 [var: struct S]
        call [0] [value: struct S]
          ident S [type: struct S]
      let= s2 [let: struct S]
        call [0] [value: struct S]
          ident S [type: struct S]
      assign
        ident tup [var: (int, () -> void)]
        tuple value [2] [value: (int, () -> void)]
          int [1] [const: int]
          select [let: () -> void]
            ident s1 [var: struct S]
            ident foo [let: () -> void]
      assign
        ident tup [var: (int, () -> void)]
        tuple value [2] [value: (int, () -> void)]
          int [2] [const: int]
          select [let: () -> void]
            ident s2 [let: struct S]
            ident foo [let: () -> void]
      assign
        ident tup [var: (int, () -> void)]
        tuple value [2] [value: (int, () -> void)]
          int [3] [const: int]
          select [value: () -> void]
            call [0] [value: struct S]
              ident get_s [let: () -> struct S]
            ident foo [let: () -> void]
  struct S [0, 1, 0, 0] [type: struct S]
    ref fn foo [let: () -> void]
      block [0]

M pkg/semantic/testdata/check/let.snow.want => pkg/semantic/testdata/check/let.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/let.snow [1, 0, 0]
file testdata/let.snow [1, 0, 0, 0]
  let:= y [let: string]
    ident string [type: string]
    string ["abc"] [const: string]

M pkg/semantic/testdata/check/let_invalid_tuple_type.snow.want => pkg/semantic/testdata/check/let_invalid_tuple_type.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/let_invalid_tuple_type.snow [1, 0, 0]
file testdata/let_invalid_tuple_type.snow [1, 0, 0, 0]
  let: x [let: (int, bool)]
    tuple type [2] [type: (int, bool)]
      ident int [type: int]

M pkg/semantic/testdata/check/let_invalid_unary.snow.want => pkg/semantic/testdata/check/let_invalid_unary.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/let_invalid_unary.snow [1, 0, 0]
file testdata/let_invalid_unary.snow [1, 0, 0, 0]
  let= x [let: unresolved]
    unary [!] [value: unresolved]
      string ["a"] [const: string]

M pkg/semantic/testdata/check/let_unary.snow.want => pkg/semantic/testdata/check/let_unary.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/let_unary.snow [1, 0, 0]
file testdata/let_unary.snow [1, 0, 0, 0]
  let= x [let: int]
    unary [-] [value: int]
      int [1] [const: int]

M pkg/semantic/testdata/check/paren_type.snow.want => pkg/semantic/testdata/check/paren_type.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/paren_type.snow [1, 0, 0]
file testdata/paren_type.snow [1, 0, 0, 0]
  var:= x [var: int]
    paren [type: int]
      ident int [type: int]

M pkg/semantic/testdata/check/struct_complex_generic.snow.want => pkg/semantic/testdata/check/struct_complex_generic.snow.want +3 -3
@@ 1,4 1,4 @@
file testdata/struct_complex_generic.snow [0, 3, 1]
file testdata/struct_complex_generic.snow [0, 3, 1, 0]
  fn str [let: (string) -> string]
    let: s [let: string]
      ident string [type: string]


@@ 29,7 29,7 @@ file testdata/struct_complex_generic.snow [0, 3, 1]
                ident string [type: string]
            ident str [let: (string) -> string]
          ident integer [let: (int) -> int]
  struct A [2, 0, 1, $2] [type: struct A]
  struct A [2, 0, 1, 0, $2] [type: struct A]
    generic type $T [type: $T]
    generic type $U [type: $U]
    var: bb [var: struct B[$U]]


@@ 40,7 40,7 @@ file testdata/struct_complex_generic.snow [0, 3, 1]
      sig [1->1] [type: ($T) -> $T]
        ident $T [type: $T]
        ident $T [type: $T]
    struct B [1, 0, 0, $1] [type: struct B]
    struct B [1, 0, 0, 0, $1] [type: struct B]
      generic type $V [type: $V]
      var: ffb [var: ($V) -> $V]
        sig [1->1] [type: ($V) -> $V]

M pkg/semantic/testdata/check/struct_generic.snow.want => pkg/semantic/testdata/check/struct_generic.snow.want +5 -5
@@ 1,5 1,5 @@
file testdata/struct_generic.snow [0, 0, 4]
  struct A [2, 1, 0] [type: struct A]
file testdata/struct_generic.snow [0, 0, 4, 0]
  struct A [2, 1, 0, 0] [type: struct A]
    var: x [var: unresolved]
      ident $T [invalid: unresolved]
    let: y [let: unresolved]


@@ 14,7 14,7 @@ file testdata/struct_generic.snow [0, 0, 4]
          block [1]
            let: c [let: unresolved]
              ident $W [invalid: unresolved]
  struct B [1, 1, 0, $3] [type: struct B]
  struct B [1, 1, 0, 0, $3] [type: struct B]
    generic type $T [type: $T]
    generic type $U [type: $U]
    generic type $V [type: $V]


@@ 26,7 26,7 @@ file testdata/struct_generic.snow [0, 0, 4]
      block [1]
        var: z [var: $U]
          ident $U [type: $U]
  struct C [2, 0, 0, $3] [type: struct C]
  struct C [2, 0, 0, 0, $3] [type: struct C]
    generic type $T [type: $T]
    generic type $U [type: $U]
    generic type $T [type: $T]


@@ 34,7 34,7 @@ file testdata/struct_generic.snow [0, 0, 4]
      ident $T [type: $T]
    let: y [let: $U]
      ident $U [type: $U]
  struct D [3, 0, 0, $2] [type: struct D]
  struct D [3, 0, 0, 0, $2] [type: struct D]
    generic type $T [type: $T]
    generic type $U [type: $U]
    var: v [var: $T]

M pkg/semantic/testdata/check/struct_simple_generic.snow.want => pkg/semantic/testdata/check/struct_simple_generic.snow.want +2 -2
@@ 1,4 1,4 @@
file testdata/struct_simple_generic.snow [0, 2, 1]
file testdata/struct_simple_generic.snow [0, 2, 1, 0]
  fn main [let: () -> void]
    block [2]
      let= a [let: struct A[int]]


@@ 20,7 20,7 @@ file testdata/struct_simple_generic.snow [0, 2, 1]
      string ["Println"] [const: string]
    let: i [let: int]
      ident int [type: int]
  struct A [1, 0, 0, $1] [type: struct A]
  struct A [1, 0, 0, 0, $1] [type: struct A]
    generic type $T [type: $T]
    var: x [var: $T]
      ident $T [type: $T]

M pkg/semantic/testdata/check/struct_var_expr_call_method.snow.want => pkg/semantic/testdata/check/struct_var_expr_call_method.snow.want +2 -2
@@ 1,7 1,7 @@
file testdata/struct_var_expr_call_method.snow [0, 1, 1]
file testdata/struct_var_expr_call_method.snow [0, 1, 1, 0]
  fn main [let: () -> void]
    block [0]
  struct S [3, 2, 0] [type: struct S]
  struct S [3, 2, 0, 0] [type: struct S]
    var:= x [var: int]
      ident int [type: int]
      call [0] [value: int]

M pkg/semantic/testdata/check/top_level_fn_init_order.snow.want => pkg/semantic/testdata/check/top_level_fn_init_order.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/top_level_fn_init_order.snow [0, 2, 0]
file testdata/top_level_fn_init_order.snow [0, 2, 0, 0]
  fn A [let: () -> void]
    block [1]
      expr

M pkg/semantic/testdata/check/top_level_init_order.snow.want => pkg/semantic/testdata/check/top_level_init_order.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/top_level_init_order.snow [2, 0, 0]
file testdata/top_level_init_order.snow [2, 0, 0, 0]
  var= A [var: int]
    ident B [let: int]
  let= B [let: int]

M pkg/semantic/testdata/check/tuple_as_struct_generic.snow.want => pkg/semantic/testdata/check/tuple_as_struct_generic.snow.want +2 -2
@@ 1,4 1,4 @@
file testdata/tuple_as_struct_generic.snow [0, 2, 1]
file testdata/tuple_as_struct_generic.snow [0, 2, 1, 0]
  fn main [let: () -> void]
    block [2]
      let:= s [let: struct S[(int, bool, string)]]


@@ 34,7 34,7 @@ file testdata/tuple_as_struct_generic.snow [0, 2, 1]
      string ["Println"] [const: string]
    let: v [let: string]
      ident string [type: string]
  struct S [1, 0, 0, $1] [type: struct S]
  struct S [1, 0, 0, 0, $1] [type: struct S]
    generic type $T [type: $T]
    let: t [let: $T]
      ident $T [type: $T]

M pkg/semantic/testdata/check/var.snow.want => pkg/semantic/testdata/check/var.snow.want +1 -1
@@ 1,3 1,3 @@
file testdata/var.snow [1, 0, 0]
file testdata/var.snow [1, 0, 0, 0]
  var: x [var: int]
    ident int [type: int]

M pkg/semantic/testdata/check/var_auto_ref.snow.want => pkg/semantic/testdata/check/var_auto_ref.snow.want +1 -1
@@ 1,3 1,3 @@
file testdata/var_auto_ref.snow [1, 0, 0]
file testdata/var_auto_ref.snow [1, 0, 0, 0]
  var= x [var: unresolved]
    ident x [var: unresolved]

M pkg/semantic/testdata/check/var_bool.snow.want => pkg/semantic/testdata/check/var_bool.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/var_bool.snow [2, 0, 0]
file testdata/var_bool.snow [2, 0, 0, 0]
  var= t [var: bool]
    ident true [let: bool]
  var= f [var: bool]

M pkg/semantic/testdata/check/var_duplicate_symbol.snow.want => pkg/semantic/testdata/check/var_duplicate_symbol.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/var_duplicate_symbol.snow [2, 0, 0]
file testdata/var_duplicate_symbol.snow [2, 0, 0, 0]
  var: x [var: int]
    ident int [type: int]
  var: x [var: string]

M pkg/semantic/testdata/check/var_tuple_type.snow.want => pkg/semantic/testdata/check/var_tuple_type.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/var_tuple_type.snow [1, 0, 0]
file testdata/var_tuple_type.snow [1, 0, 0, 0]
  var: x [var: (int, string, bool)]
    tuple type [3] [type: (int, string, bool)]
      ident int [type: int]

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

struct S {
  let s: string

  fn foo() {
    println(s)
  }
}

@extern(import: "fmt", symbol: "Println")
fn println(s: string)

fn main() {
  let iface: I = S(s: "hello!")
  iface.foo()
}

A pkg/semantic/testdata/fn_generic_interface.snow => pkg/semantic/testdata/fn_generic_interface.snow +29 -0
@@ 0,0 1,29 @@
interface I[$T] {
  fn foo(t: $T) -> $T
}

struct S {
  fn foo(i: int) -> int {}
}

struct G[$T] {
  fn foo(t: $T) -> $T {}
}

fn main() {
  var ifaceInt: I[int] = S()
  var res = ifaceInt.foo(1)
  var gInt: G[int]
  var gres = gInt.foo(1)

  ifaceInt = G[int]()
  res = ifaceInt.foo(2)

  # this should fail
  ifaceInt = G[bool]()

  # this should work
  var ifaceString: I[string]
  ifaceString = G[string]()
  ifaceString.foo("a")
}

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

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/interface_satisfied.snow => pkg/semantic/testdata/interface_satisfied.snow +70 -0
@@ 0,0 1,70 @@
interface Empty {
}

interface Foo {
  fn foo(i: int) -> int
}

struct S1 {
  fn foo(x: int) -> int {}
  fn bar(s: string) {}
}

struct S2 {
  fn bar(s: string) {}
  fn quz(b: bool) {}
}

struct S3 {
  fn foo(u: uint) -> int {}
}

struct S4 {
  ref fn foo(i: int) -> int {}
}

fn get_s4() -> S4 {
  return S4()
}

fn main() {
  var empty: Empty
  var f: Foo
  var integer: int
  var s1: S1

  empty = empty   # self assignment should work
  empty = f       # ok, everything satisfies empty
  empty = s1      # yep
  empty = integer # well no, not quite everything!

  f = S1() # all good, S1.foo exists and same types
  f = S2() # nope
  f = S3() # types don't match

  var vs4 = S4()
  let ls4 = S4()

  # this works, vs4 is a var
  f = vs4
  # not this, ls4 is immutable
  f = ls4
  # not this either, rhs is a value
  f = S4()

  var tup: (int, Foo) 
  # this is fine
  tup = (1, vs4)
  # this is not, should fail because ls4 is immutable
  tup = (1, ls4)

  var tup2: (int, Foo, (bool, Foo))
  tup2 = (1, vs4, (true, vs4)) # works, var s4 in both Foo places
  tup2 = (1, ls4, (true, get_s4())) # fails, immutable S4 and value S4

  # those all work (var S4 for Foo, and whatever for Empty)
  var tup3: (int, (Foo, (Empty)))
  tup3 = (3, (vs4, (ls4)))
  tup3 = (3, (vs4, (get_s4())))
}


A pkg/semantic/testdata/invalid_ref_fn_assign.snow => pkg/semantic/testdata/invalid_ref_fn_assign.snow +16 -0
@@ 0,0 1,16 @@
struct S {
  ref fn foo() {}
}

fn get_s() -> S {
  return S()
}

fn main() {
  var tup: (int, () -> void)
  var s1 = S()
  let s2 = S()
  tup = (1, s1.foo)
  tup = (2, s2.foo)
  tup = (3, get_s().foo)
}

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

A pkg/semantic/testdata/scopes/fn_assign_call_interface.snow.want => pkg/semantic/testdata/scopes/fn_assign_call_interface.snow.want +50 -0
@@ 0,0 1,50 @@
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
.  .  S
.  .  main
.  .  println
.  .  4 *semantic.Interface {
.  .  .  foo
.  .  .  5 *semantic.Fn {
.  .  .  }
.  .  }
.  .  6 *semantic.Struct {
.  .  .  foo
.  .  .  s
.  .  .  7 *semantic.Fn {
.  .  .  .  self
.  .  .  }
.  .  }
.  .  8 *semantic.Fn {
.  .  .  s
.  .  }
.  .  9 *semantic.Fn {
.  .  .  iface
.  .  }
.  }
}

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

A pkg/semantic/testdata/scopes/fn_generic_interface.snow.want => pkg/semantic/testdata/scopes/fn_generic_interface.snow.want +61 -0
@@ 0,0 1,61 @@
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 {
.  .  G
.  .  I
.  .  S
.  .  main
.  .  4 *semantic.Interface {
.  .  .  $T
.  .  .  foo
.  .  .  5 *semantic.Fn {
.  .  .  .  t
.  .  .  }
.  .  }
.  .  6 *semantic.Struct {
.  .  .  foo
.  .  .  7 *semantic.Fn {
.  .  .  .  i
.  .  .  .  self
.  .  .  }
.  .  }
.  .  8 *semantic.Struct {
.  .  .  $T
.  .  .  foo
.  .  .  9 *semantic.Fn {
.  .  .  .  self
.  .  .  .  t
.  .  .  }
.  .  }
.  .  10 *semantic.Fn {
.  .  .  gInt
.  .  .  gres
.  .  .  ifaceInt
.  .  .  ifaceString
.  .  .  res
.  .  }
.  }
}

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

A pkg/semantic/testdata/scopes/generic_interface.snow.want => pkg/semantic/testdata/scopes/generic_interface.snow.want +40 -0
@@ 0,0 1,40 @@
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 {
.  .  .  $T
.  .  .  $U
.  .  .  get_t
.  .  .  set_u
.  .  .  5 *semantic.Fn {
.  .  .  }
.  .  .  6 *semantic.Fn {
.  .  .  .  u
.  .  .  }
.  .  }
.  }
}

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/scopes/interface_satisfied.snow.err => pkg/semantic/testdata/scopes/interface_satisfied.snow.err +0 -0

A pkg/semantic/testdata/scopes/interface_satisfied.snow.want => pkg/semantic/testdata/scopes/interface_satisfied.snow.want +95 -0
@@ 0,0 1,95 @@
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 {
.  .  Empty
.  .  Foo
.  .  S1
.  .  S2
.  .  S3
.  .  S4
.  .  get_s4
.  .  main
.  .  4 *semantic.Interface {
.  .  }
.  .  5 *semantic.Interface {
.  .  .  foo
.  .  .  6 *semantic.Fn {
.  .  .  .  i
.  .  .  }
.  .  }
.  .  7 *semantic.Struct {
.  .  .  bar
.  .  .  foo
.  .  .  8 *semantic.Fn {
.  .  .  .  self
.  .  .  .  x
.  .  .  }
.  .  .  9 *semantic.Fn {
.  .  .  .  s
.  .  .  .  self
.  .  .  }
.  .  }
.  .  10 *semantic.Struct {
.  .  .  bar
.  .  .  quz
.  .  .  11 *semantic.Fn {
.  .  .  .  s
.  .  .  .  self
.  .  .  }
.  .  .  12 *semantic.Fn {
.  .  .  .  b
.  .  .  .  self
.  .  .  }
.  .  }
.  .  13 *semantic.Struct {
.  .  .  foo
.  .  .  14 *semantic.Fn {
.  .  .  .  self
.  .  .  .  u
.  .  .  }
.  .  }
.  .  15 *semantic.Struct {
.  .  .  foo
.  .  .  16 *semantic.Fn {
.  .  .  .  i
.  .  .  .  self
.  .  .  }
.  .  }
.  .  17 *semantic.Fn {
.  .  }
.  .  18 *semantic.Fn {
.  .  .  empty
.  .  .  f
.  .  .  integer
.  .  .  ls4
.  .  .  s1
.  .  .  tup
.  .  .  tup2
.  .  .  tup3
.  .  .  vs4
.  .  }
.  }
}

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

A pkg/semantic/testdata/scopes/invalid_ref_fn_assign.snow.want => pkg/semantic/testdata/scopes/invalid_ref_fn_assign.snow.want +44 -0
@@ 0,0 1,44 @@
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 {
.  .  S
.  .  get_s
.  .  main
.  .  4 *semantic.Struct {
.  .  .  foo
.  .  .  5 *semantic.Fn {
.  .  .  .  self
.  .  .  }
.  .  }
.  .  6 *semantic.Fn {
.  .  }
.  .  7 *semantic.Fn {
.  .  .  s1
.  .  .  s2
.  .  .  tup
.  .  }
.  }
}

A pkg/semantic/testdata/static/fn_assign_call_interface.snow.err => pkg/semantic/testdata/static/fn_assign_call_interface.snow.err +0 -0

A pkg/semantic/testdata/static/fn_assign_call_interface.snow.want => pkg/semantic/testdata/static/fn_assign_call_interface.snow.want +5 -0
@@ 0,0 1,5 @@
testdata/fn_assign_call_interface.snow:9:5: println
testdata/fn_assign_call_interface.snow:9:13: s
testdata/fn_assign_call_interface.snow:17:18: S
testdata/fn_assign_call_interface.snow:18:3: iface
testdata/fn_assign_call_interface.snow:18:9: foo

A pkg/semantic/testdata/static/fn_generic_interface.snow.err => pkg/semantic/testdata/static/fn_generic_interface.snow.err +1 -0
@@ 0,0 1,1 @@
testdata/fn_generic_interface.snow:23:14: cannot assign type struct G[bool] to variable of type interface I[int]

A pkg/semantic/testdata/static/fn_generic_interface.snow.want => pkg/semantic/testdata/static/fn_generic_interface.snow.want +15 -0
@@ 0,0 1,15 @@
testdata/fn_generic_interface.snow:14:26: S
testdata/fn_generic_interface.snow:15:13: ifaceInt
testdata/fn_generic_interface.snow:15:22: foo
testdata/fn_generic_interface.snow:17:14: gInt
testdata/fn_generic_interface.snow:17:19: foo
testdata/fn_generic_interface.snow:19:14: G
testdata/fn_generic_interface.snow:19:16: int
testdata/fn_generic_interface.snow:20:9: ifaceInt
testdata/fn_generic_interface.snow:20:18: foo
testdata/fn_generic_interface.snow:23:14: G
testdata/fn_generic_interface.snow:23:16: bool
testdata/fn_generic_interface.snow:27:17: G
testdata/fn_generic_interface.snow:27:19: string
testdata/fn_generic_interface.snow:28:3: ifaceString
testdata/fn_generic_interface.snow:28:15: foo

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

A pkg/semantic/testdata/static/interface_satisfied.snow.err => pkg/semantic/testdata/static/interface_satisfied.snow.err +7 -0
@@ 0,0 1,7 @@
testdata/interface_satisfied.snow:39:11: cannot assign type int to variable of type interface Empty
testdata/interface_satisfied.snow:42:7: cannot assign type struct S2 to variable of type interface Foo
testdata/interface_satisfied.snow:43:7: cannot assign type struct S3 to variable of type interface Foo
testdata/interface_satisfied.snow:51:7: cannot assign type struct S4 to variable of type interface Foo
testdata/interface_satisfied.snow:53:7: cannot assign type struct S4 to variable of type interface Foo
testdata/interface_satisfied.snow:59:9: cannot assign type (int, struct S4) to variable of type (int, interface Foo)
testdata/interface_satisfied.snow:63:10: cannot assign type (int, struct S4, (bool, struct S4)) to variable of type (int, interface Foo, (bool, interface Foo))

A pkg/semantic/testdata/static/interface_satisfied.snow.want => pkg/semantic/testdata/static/interface_satisfied.snow.want +25 -0
@@ 0,0 1,25 @@
testdata/interface_satisfied.snow:27:10: S4
testdata/interface_satisfied.snow:36:11: empty
testdata/interface_satisfied.snow:37:11: f
testdata/interface_satisfied.snow:38:11: s1
testdata/interface_satisfied.snow:39:11: integer
testdata/interface_satisfied.snow:41:7: S1
testdata/interface_satisfied.snow:42:7: S2
testdata/interface_satisfied.snow:43:7: S3
testdata/interface_satisfied.snow:45:13: S4
testdata/interface_satisfied.snow:46:13: S4
testdata/interface_satisfied.snow:49:7: vs4
testdata/interface_satisfied.snow:51:7: ls4
testdata/interface_satisfied.snow:53:7: S4
testdata/interface_satisfied.snow:57:13: vs4
testdata/interface_satisfied.snow:59:13: ls4
testdata/interface_satisfied.snow:62:14: vs4
testdata/interface_satisfied.snow:62:20: true
testdata/interface_satisfied.snow:62:26: vs4
testdata/interface_satisfied.snow:63:14: ls4
testdata/interface_satisfied.snow:63:20: true
testdata/interface_satisfied.snow:63:26: get_s4
testdata/interface_satisfied.snow:67:15: vs4
testdata/interface_satisfied.snow:67:21: ls4
testdata/interface_satisfied.snow:68:15: vs4
testdata/interface_satisfied.snow:68:21: get_s4

A pkg/semantic/testdata/static/invalid_ref_fn_assign.snow.err => pkg/semantic/testdata/static/invalid_ref_fn_assign.snow.err +2 -0
@@ 0,0 1,2 @@
testdata/invalid_ref_fn_assign.snow:14:16: cannot access ref fn foo; left-hand side must be var, is let
testdata/invalid_ref_fn_assign.snow:15:21: cannot access ref fn foo; left-hand side must be var, is value

A pkg/semantic/testdata/static/invalid_ref_fn_assign.snow.want => pkg/semantic/testdata/static/invalid_ref_fn_assign.snow.want +9 -0
@@ 0,0 1,9 @@
testdata/invalid_ref_fn_assign.snow:6:10: S
testdata/invalid_ref_fn_assign.snow:11:12: S
testdata/invalid_ref_fn_assign.snow:12:12: S
testdata/invalid_ref_fn_assign.snow:13:13: s1
testdata/invalid_ref_fn_assign.snow:13:16: foo
testdata/invalid_ref_fn_assign.snow:14:13: s2
testdata/invalid_ref_fn_assign.snow:14:16: foo
testdata/invalid_ref_fn_assign.snow:15:13: get_s
testdata/invalid_ref_fn_assign.snow:15:21: foo

M pkg/semantic/testdata/types/cycle.snow.want => pkg/semantic/testdata/types/cycle.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/cycle.snow [3, 0, 0]
file testdata/cycle.snow [3, 0, 0, 0]
  var= A [var: unresolved]
    ident B [var: unresolved]
  var= B [var: unresolved]

M pkg/semantic/testdata/types/empty.snow.want => pkg/semantic/testdata/types/empty.snow.want +1 -1
@@ 1,1 1,1 @@
file testdata/empty.snow [0, 0, 0]
file testdata/empty.snow [0, 0, 0, 0]

M pkg/semantic/testdata/types/fn.snow.want => pkg/semantic/testdata/types/fn.snow.want +1 -1
@@ 1,3 1,3 @@
file testdata/fn.snow [0, 1, 0]
file testdata/fn.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [0]

M pkg/semantic/testdata/types/fn_access_invalid_struct_field.snow.want => pkg/semantic/testdata/types/fn_access_invalid_struct_field.snow.want +2 -2
@@ 1,4 1,4 @@
file testdata/fn_access_invalid_struct_field.snow [0, 1, 1]
file testdata/fn_access_invalid_struct_field.snow [0, 1, 1, 0]
  fn test [let: () -> void]
    block [4]
      var: s [var: struct S]


@@ 16,6 16,6 @@ file testdata/fn_access_invalid_struct_field.snow [0, 1, 1]
        select [invalid: unresolved]
          ident s [var: struct S]
          ident z [invalid: unresolved]
  struct S [1, 0, 0] [type: struct S]
  struct S [1, 0, 0, 0] [type: struct S]
    var: x [var: int]
      ident int [type: int]

M pkg/semantic/testdata/types/fn_access_struct_type_field.snow.want => pkg/semantic/testdata/types/fn_access_struct_type_field.snow.want +2 -2
@@ 1,10 1,10 @@
file testdata/fn_access_struct_type_field.snow [0, 1, 1]
file testdata/fn_access_struct_type_field.snow [0, 1, 1, 0]
  fn test [let: () -> void]
    block [1]
      var= y [var: int]
        select [invalid: int]
          ident Point [type: struct Point]
          ident x [var: int]
  struct Point [1, 0, 0] [type: struct Point]
  struct Point [1, 0, 0, 0] [type: struct Point]
    var: x [var: int]
      ident int [type: int]

M pkg/semantic/testdata/types/fn_access_var_outside_struct.snow.want => pkg/semantic/testdata/types/fn_access_var_outside_struct.snow.want +3 -3
@@ 1,9 1,9 @@
file testdata/fn_access_var_outside_struct.snow [0, 1, 0]
file testdata/fn_access_var_outside_struct.snow [0, 1, 0, 0]
  fn main [let: () -> void]
    block [2]
      var: x [var: int]
        ident int [type: int]
      struct S [1, 1, 1] [type: struct S]
      struct S [1, 1, 1, 0] [type: struct S]
        var: y [var: string]
          ident string [type: string]
        fn get [let: () -> int]


@@ 11,7 11,7 @@ file testdata/fn_access_var_outside_struct.snow [0, 1, 0]
          block [1]
            return
              ident x [var: int]
        struct T [0, 1, 0] [type: struct T]
        struct T [0, 1, 0, 0] [type: struct T]
          fn get [let: () -> string]
            ident string [type: string]
            block [1]

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

A pkg/semantic/testdata/types/fn_assign_call_interface.snow.want => pkg/semantic/testdata/types/fn_assign_call_interface.snow.want +31 -0
@@ 0,0 1,31 @@
file testdata/fn_assign_call_interface.snow [0, 2, 1, 1]
  fn println [let: (string) -> void]
    @ [import, symbol] [2] [value: struct extern]
      ident extern [type: struct extern]
      string ["fmt"] [const: string]
      string ["Println"] [const: string]
    let: s [let: string]
      ident string [type: string]
  fn main [let: () -> void]
    block [2]
      let:= iface [let: interface I]
        ident I [type: interface I]
        call [s] [1] [value: struct S]
          ident S [type: struct S]
          string ["hello!"] [const: string]
      expr
        call [0] [value: void]
          select [let: () -> void]
            ident iface [let: interface I]
            ident foo [let: () -> void]
  struct S [1, 1, 0, 0] [type: struct S]
    let: s [let: string]
      ident string [type: string]
    fn foo [let: () -> void]
      block [1]
        expr
          call [1] [value: void]
            ident println [let: (string) -> void]
            ident s [let: string]
  interface I [1] [type: interface I]
    fn foo [let: () -> void]

M pkg/semantic/testdata/types/fn_assign_invalid.snow.want => pkg/semantic/testdata/types/fn_assign_invalid.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_assign_invalid.snow [0, 1, 0]
file testdata/fn_assign_invalid.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [2]
      var: x [var: f64]

M pkg/semantic/testdata/types/fn_assign_let.snow.want => pkg/semantic/testdata/types/fn_assign_let.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_assign_let.snow [0, 1, 0]
file testdata/fn_assign_let.snow [0, 1, 0, 0]
  fn main [let: () -> void]
    block [2]
      let= x [let: int]

M pkg/semantic/testdata/types/fn_assign_struct_fields.snow.want => pkg/semantic/testdata/types/fn_assign_struct_fields.snow.want +2 -2
@@ 1,4 1,4 @@
file testdata/fn_assign_struct_fields.snow [0, 1, 1]
file testdata/fn_assign_struct_fields.snow [0, 1, 1, 0]
  fn test [let: () -> void]
    block [8]
      var: vs [var: struct S]


@@ 35,7 35,7 @@ file testdata/fn_assign_struct_fields.snow [0, 1, 1]
          ident ls [let: struct S]
          ident z [let: () -> void]
        ident test [let: () -> void]
  struct S [2, 1, 0] [type: struct S]
  struct S [2, 1, 0, 0] [type: struct S]
    let: x [let: int]
      ident int [type: int]
    var: y [var: int]

M pkg/semantic/testdata/types/fn_assign_struct_method_to_var.snow.want => pkg/semantic/testdata/types/fn_assign_struct_method_to_var.snow.want +2 -2
@@ 1,4 1,4 @@
file testdata/fn_assign_struct_method_to_var.snow [0, 1, 1]
file testdata/fn_assign_struct_method_to_var.snow [0, 1, 1, 0]
  fn main [let: () -> void]
    block [6]
      var: s [var: struct S]


@@ 28,7 28,7 @@ file testdata/fn_assign_struct_method_to_var.snow [0, 1, 1]
        select [let: (int) -> void]
          ident s2 [let: struct S]
          ident set [let: (int) -> void]
  struct S [1, 2, 0] [type: struct S]
  struct S [1, 2, 0, 0] [type: struct S]
    var: x [var: int]
      ident int [type: int]
    fn get [let: () -> int]

M pkg/semantic/testdata/types/fn_assign_type.snow.want => pkg/semantic/testdata/types/fn_assign_type.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_assign_type.snow [0, 1, 0]
file testdata/fn_assign_type.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [1]
      assign

M pkg/semantic/testdata/types/fn_assign_unifying_type.snow.want => pkg/semantic/testdata/types/fn_assign_unifying_type.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_assign_unifying_type.snow [0, 1, 0]
file testdata/fn_assign_unifying_type.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [3]
      var: x [var: u8]

M pkg/semantic/testdata/types/fn_call_fn_value_with_labels.snow.want => pkg/semantic/testdata/types/fn_call_fn_value_with_labels.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_call_fn_value_with_labels.snow [0, 2, 0]
file testdata/fn_call_fn_value_with_labels.snow [0, 2, 0, 0]
  fn add [let: (int, int) -> int]
    let: x [let: int]
      ident int [type: int]

M pkg/semantic/testdata/types/fn_call_struct_init.snow.want => pkg/semantic/testdata/types/fn_call_struct_init.snow.want +2 -2
@@ 1,4 1,4 @@
file testdata/fn_call_struct_init.snow [0, 1, 1]
file testdata/fn_call_struct_init.snow [0, 1, 1, 0]
  fn main [let: () -> void]
    block [1]
      var= s [var: struct S]


@@ 6,7 6,7 @@ file testdata/fn_call_struct_init.snow [0, 1, 1]
          ident S [type: struct S]
          int [1] [const: int]
          string ["a"] [const: string]
  struct S [2, 0, 0] [type: struct S]
  struct S [2, 0, 0, 0] [type: struct S]
    var: x [var: int]
      ident int [type: int]
    let: y [let: string]

M pkg/semantic/testdata/types/fn_call_struct_init_no_label.snow.want => pkg/semantic/testdata/types/fn_call_struct_init_no_label.snow.want +2 -2
@@ 1,4 1,4 @@
file testdata/fn_call_struct_init_no_label.snow [0, 1, 1]
file testdata/fn_call_struct_init_no_label.snow [0, 1, 1, 0]
  fn main [let: () -> void]
    block [1]
      var= s [var: struct S]


@@ 6,7 6,7 @@ file testdata/fn_call_struct_init_no_label.snow [0, 1, 1]
          ident S [type: struct S]
          int [1] [const: int]
          string ["a"] [const: string]
  struct S [2, 0, 0] [type: struct S]
  struct S [2, 0, 0, 0] [type: struct S]
    var: x [var: int]
      ident int [type: int]
    let: y [let: string]

M pkg/semantic/testdata/types/fn_call_struct_init_only_required_no_order.snow.want => pkg/semantic/testdata/types/fn_call_struct_init_only_required_no_order.snow.want +2 -2
@@ 1,4 1,4 @@
file testdata/fn_call_struct_init_only_required_no_order.snow [0, 1, 1]
file testdata/fn_call_struct_init_only_required_no_order.snow [0, 1, 1, 0]
  fn main [let: () -> void]
    block [2]
      var= s [var: struct S]


@@ 10,7 10,7 @@ file testdata/fn_call_struct_init_only_required_no_order.snow [0, 1, 1]
        call [b] [1] [value: struct S]
          ident S [type: struct S]
          string ["b"] [const: string]
  struct S [3, 0, 0] [type: struct S]
  struct S [3, 0, 0, 0] [type: struct S]
    var: a [var: int]
      ident int [type: int]
    let: b [let: string]

M pkg/semantic/testdata/types/fn_call_struct_method.snow.want => pkg/semantic/testdata/types/fn_call_struct_method.snow.want +2 -2
@@ 1,4 1,4 @@
file testdata/fn_call_struct_method.snow [0, 1, 1]
file testdata/fn_call_struct_method.snow [0, 1, 1, 0]
  fn test [let: () -> void]
    block [2]
      var: p [var: struct Point]


@@ 9,7 9,7 @@ file testdata/fn_call_struct_method.snow [0, 1, 1]
            ident p [var: struct Point]
            ident add [let: (int) -> void]
          int [1] [const: int]
  struct Point [1, 1, 0] [type: struct Point]
  struct Point [1, 1, 0, 0] [type: struct Point]
    var: x [var: int]
      ident int [type: int]
    fn add [let: (int) -> void]

M pkg/semantic/testdata/types/fn_call_unifying_type.snow.want => pkg/semantic/testdata/types/fn_call_unifying_type.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_call_unifying_type.snow [0, 2, 0]
file testdata/fn_call_unifying_type.snow [0, 2, 0, 0]
  fn add [let: (int, int) -> int]
    let: x [let: int]
      ident int [type: int]

M pkg/semantic/testdata/types/fn_call_with_invalid_labels.snow.want => pkg/semantic/testdata/types/fn_call_with_invalid_labels.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_call_with_invalid_labels.snow [0, 2, 0]
file testdata/fn_call_with_invalid_labels.snow [0, 2, 0, 0]
  fn add [let: (int, int) -> int]
    let: x [let: int]
      ident int [type: int]

M pkg/semantic/testdata/types/fn_call_with_labels.snow.want => pkg/semantic/testdata/types/fn_call_with_labels.snow.want +2 -2
@@ 1,4 1,4 @@
file testdata/fn_call_with_labels.snow [0, 2, 1]
file testdata/fn_call_with_labels.snow [0, 2, 1, 0]
  fn add [let: (int, int) -> int]
    let: x [let: int]
      ident int [type: int]


@@ 45,7 45,7 @@ file testdata/fn_call_with_labels.snow [0, 2, 1]
                ident s [var: struct S]
              ident do [let: (int) -> void]
          int [6] [const: int]
  struct S [0, 1, 0] [type: struct S]
  struct S [0, 1, 0, 0] [type: struct S]
    fn do [let: (int) -> void]
      let: z [let: int]
        ident int [type: int]

M pkg/semantic/testdata/types/fn_call_wrong_arity.snow.want => pkg/semantic/testdata/types/fn_call_wrong_arity.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_call_wrong_arity.snow [0, 2, 0]
file testdata/fn_call_wrong_arity.snow [0, 2, 0, 0]
  fn add [let: (int, int) -> int]
    let: x [let: int]
      ident int [type: int]

M pkg/semantic/testdata/types/fn_compare.snow.want => pkg/semantic/testdata/types/fn_compare.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_compare.snow [0, 1, 0]
file testdata/fn_compare.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [2]
      var= x [var: int]

M pkg/semantic/testdata/types/fn_complex_selectors.snow.want => pkg/semantic/testdata/types/fn_complex_selectors.snow.want +3 -3
@@ 1,4 1,4 @@
file testdata/fn_complex_selectors.snow [0, 2, 1]
file testdata/fn_complex_selectors.snow [0, 2, 1, 0]
  fn create [let: () -> struct S]
    ident S [type: struct S]
    block [2]


@@ 36,12 36,12 @@ file testdata/fn_complex_selectors.snow [0, 2, 1]
                  ident s2 [var: struct T]
                ident do [let: () -> (int, () -> int)]
            ident 1 [value: () -> int]
  struct S [2, 0, 1] [type: struct S]
  struct S [2, 0, 1, 0] [type: struct S]
    var: s1 [var: int]
      ident int [type: int]
    var: s2 [var: struct T]
      ident T [type: struct T]
    struct T [1, 1, 0] [type: struct T]
    struct T [1, 1, 0, 0] [type: struct T]
      var: t1 [var: string]
        ident string [type: string]
      fn do [let: () -> (int, () -> int)]

M pkg/semantic/testdata/types/fn_duplicate_param_name.snow.want => pkg/semantic/testdata/types/fn_duplicate_param_name.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_duplicate_param_name.snow [0, 1, 0]
file testdata/fn_duplicate_param_name.snow [0, 1, 0, 0]
  fn dup [let: (int, string) -> void]
    let: x [let: int]
      ident int [type: int]

M pkg/semantic/testdata/types/fn_explicit_void.snow.want => pkg/semantic/testdata/types/fn_explicit_void.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_explicit_void.snow [0, 3, 0]
file testdata/fn_explicit_void.snow [0, 3, 0, 0]
  fn do_nothing [let: () -> void]
    ident void [type: void]
    block [1]

M pkg/semantic/testdata/types/fn_extern_pkg_before_conflict_name.snow.want => pkg/semantic/testdata/types/fn_extern_pkg_before_conflict_name.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_extern_pkg_before_conflict_name.snow [0, 1, 0]
file testdata/fn_extern_pkg_before_conflict_name.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [4]
      fn print [let: (int) -> void]

M pkg/semantic/testdata/types/fn_extern_pkg_conflict_name.snow.want => pkg/semantic/testdata/types/fn_extern_pkg_conflict_name.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_extern_pkg_conflict_name.snow [0, 1, 0]
file testdata/fn_extern_pkg_conflict_name.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    block [4]
      var: fmt [var: int]

M pkg/semantic/testdata/types/fn_extern_ref_method.snow.want => pkg/semantic/testdata/types/fn_extern_ref_method.snow.want +2 -2
@@ 1,7 1,7 @@
file testdata/fn_extern_ref_method.snow [0, 1, 0]
file testdata/fn_extern_ref_method.snow [0, 1, 0, 0]
  fn main [let: () -> void]
    block [1]
      struct S [0, 1, 0] [type: struct S]
      struct S [0, 1, 0, 0] [type: struct S]
        ref fn f [let: () -> void]
          @ [import, symbol] [2] [value: struct extern]
            ident extern [type: struct extern]

M pkg/semantic/testdata/types/fn_extern_with_body.snow.want => pkg/semantic/testdata/types/fn_extern_with_body.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_extern_with_body.snow [0, 1, 0]
file testdata/fn_extern_with_body.snow [0, 1, 0, 0]
  fn test [let: () -> void]
    @ [import, symbol] [2] [value: struct extern]
      ident extern [type: struct extern]

M pkg/semantic/testdata/types/fn_fn_arg.snow.want => pkg/semantic/testdata/types/fn_fn_arg.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_fn_arg.snow [0, 3, 0]
file testdata/fn_fn_arg.snow [0, 3, 0, 0]
  fn do [let: (int, (int) -> int) -> int]
    let: x [let: int]
      ident int [type: int]

M pkg/semantic/testdata/types/fn_generic_decl_after_inst.snow.want => pkg/semantic/testdata/types/fn_generic_decl_after_inst.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_generic_decl_after_inst.snow [0, 2, 0]
file testdata/fn_generic_decl_after_inst.snow [0, 2, 0, 0]
  fn main [let: () -> void]
    block [1]
      let= a [let: int]

M pkg/semantic/testdata/types/fn_generic_fn_uses_generic_fn.snow.want => pkg/semantic/testdata/types/fn_generic_fn_uses_generic_fn.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_generic_fn_uses_generic_fn.snow [0, 3, 0]
file testdata/fn_generic_fn_uses_generic_fn.snow [0, 3, 0, 0]
  fn A [$1] [let: ($T) -> $T]
    generic type $T [type: $T]
    let: v [let: $T]

M pkg/semantic/testdata/types/fn_generic_identity.snow.want => pkg/semantic/testdata/types/fn_generic_identity.snow.want +1 -1
@@ 1,4 1,4 @@
file testdata/fn_generic_identity.snow [0, 5, 0]
file testdata/fn_generic_identity.snow [0, 5, 0, 0]
  fn id [$1] [let: ($T) -> $T]
    generic type $T [type: $T]
    let: v [let: $T]

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

A pkg/semantic/testdata/types/fn_generic_interface.snow.want => pkg/semantic/testdata/types/fn_generic_interface.snow.want +79 -0
@@ 0,0 1,79 @@
file testdata/fn_generic_interface.snow [0, 1, 2, 1]
  fn main [let: () -> void]
    block [10]
      var:= ifaceInt [var: interface I[int]]