~mna/snow

81715ef36651ed601b4fe898bb5ad9f9ea21cf90 — Martin Angers 1 year, 10 months ago 5ebfddd wip-post-ast
pkg/{codegen,semantic}: OMG all codegen tests pass, all is good
45 files changed, 188 insertions(+), 220 deletions(-)

M cmd/snowc/main.go
M pkg/codegen/mangle.go
M pkg/codegen/testdata/fn_nested_struct_method.snow.want
M pkg/codegen/testdata/fn_struct_method.snow.want
A pkg/codegen/visit_scopes.go
M pkg/semantic/scope.go
M pkg/semantic/testdata/check/fn_access_var_outside_struct.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_call_struct_method.snow.want
M pkg/semantic/testdata/check/fn_call_with_labels.snow.want
M pkg/semantic/testdata/check/fn_complex_selectors.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_method_explicit_self.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_ref_on_fn_nested_in_method.snow.want
M pkg/semantic/testdata/check/fn_return_struct.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_self_shadow.snow.want
M pkg/semantic/testdata/check/fn_struct_self_uses.snow.want
M pkg/semantic/testdata/check/struct_var_expr_call_method.snow.want
M pkg/semantic/testdata/types/fn_access_var_outside_struct.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_call_struct_method.snow.want
M pkg/semantic/testdata/types/fn_call_with_labels.snow.want
M pkg/semantic/testdata/types/fn_complex_selectors.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_method_explicit_self.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_ref_on_fn_nested_in_method.snow.want
M pkg/semantic/testdata/types/fn_return_struct.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_self_shadow.snow.want
M pkg/semantic/testdata/types/fn_struct_self_uses.snow.want
M pkg/semantic/testdata/types/struct_var_expr_call_method.snow.want
M pkg/semantic/translate_pass.go
M cmd/snowc/main.go => cmd/snowc/main.go +2 -2
@@ 210,7 210,7 @@ func (c *cmd) Typecheck(stdio *mainer.Stdio, args []string) error {
}

func (c *cmd) Codegen(stdio *mainer.Stdio, args []string) error {
	files, err := codegen.GenerateFiles(c.GenDir, args...)
	files, err := codegen.Exec(c.GenDir, args...)
	for _, file := range files {
		fmt.Fprintf(stdio.Stdout, "> %s\n", file)
	}


@@ 247,7 247,7 @@ func (c *cmd) splitDashDash(args []string) (parts [2][]string) {
}

func (c *cmd) build(stdio *mainer.Stdio, paths []string, goflags []string) error {
	files, err := codegen.GenerateFiles(c.GenDir, paths...)
	files, err := codegen.Exec(c.GenDir, paths...)
	if err != nil {
		var el scanner.ErrorList
		if errors.As(err, &el) {

M pkg/codegen/mangle.go => pkg/codegen/mangle.go +44 -42
@@ 33,57 33,59 @@ func mangle(unit *semantic.Unit) *nameResolver {
		ruses[decl] = true
	}

	// TODO: I believe it should be based by walking the scopes instead! Would
	// work for all declarations (all registered in scopes), and even for Self
	// (which has no AST/ASG node).

	names := make(map[semantic.Decl]string)
	semantic.Inspect(unit, func(n semantic.Node) bool {
		// first, process the generic cases for all decls
		if decl, ok := n.(semantic.Decl); ok {
			// Universe types are handled by the translator.goTypeExprFor method.
	InspectScope(unit.Scope(), func(s *semantic.Scope) bool {
		if s == nil {
			return false
		}

			// if this is the main function, mangle it as "main" and that's it.
		for _, decl := range s.Symbols {
			// first, process the generic cases for all decls
			if decl == unit.Main {
				names[decl] = basicIdentsToGo[decl.Ident()]
				return true
			}
		}

		switch n := n.(type) {
		case *semantic.Fn:
			var b fmtBuilder
			if n.Scope().IsTopLevel() || n.MethodOf != nil {
				b.withExport(false)
				continue
			}
			names[n] = b.get(n.Ident())

		case *semantic.Var:
			// if this is a variable (not a struct field nor a function parameter)
			// and its value is unused, mangle as "_".
			if !ruses[n] && n.ParamOf == nil && n.PropOf == nil {
				// TODO: unless public/exported
				names[n] = "_"
				break
			if decl.Scope().IsUniverse() {
				if _, ok := decl.Type().(*semantic.BasicType); ok {
					names[decl] = basicIdentsToGo[decl.Ident()]
					continue
				}
			}

			var b fmtBuilder
			if n.Scope().IsTopLevel() || n.PropOf != nil {
				b.withExport(false)
			}
			names[n] = b.get(n.Ident())
			switch decl := decl.(type) {
			case *semantic.Fn:
				var b fmtBuilder
				if decl.Scope().IsTopLevel() || decl.MethodOf != nil {
					b.withExport(false)
				}
				names[decl] = b.get(decl.Ident())

			case *semantic.Var:
				// if this is a variable (not a struct field nor a function parameter)
				// and its value is unused, mangle as "_".
				if !ruses[decl] && decl.ParamOf == nil && decl.PropOf == nil {
					// TODO: unless public/exported
					names[decl] = "_"
					break
				}

		case *semantic.Struct:
			var b fmtBuilder
			b.withExport(false)
			if !n.Scope().IsTopLevel() {
				b.withScope(n.Scope())
			}
			names[n] = b.get(n.Ident())

		case *semantic.Ident:
			// if the referenced declaration is in the Universe and the type is
			// BasicType, mangle as its corresponding Go basic type or identifier.
			if ref := n.Ref; ref != nil && ref.Scope().IsUniverse() {
				if _, ok := ref.Type().(*semantic.BasicType); ok {
					names[ref] = basicIdentsToGo[ref.Ident()]
				var b fmtBuilder
				if decl.Scope().IsTopLevel() || decl.PropOf != nil {
					b.withExport(false)
				}
				names[decl] = b.get(decl.Ident())

			case *semantic.Struct:
				var b fmtBuilder
				b.withExport(false)
				if !decl.Scope().IsTopLevel() {
					b.withScope(decl.Scope())
				}
				names[decl] = b.get(decl.Ident())
			}
		}
		return true

M pkg/codegen/testdata/fn_nested_struct_method.snow.want => pkg/codegen/testdata/fn_nested_struct_method.snow.want +33 -19
@@ 2,39 2,53 @@ package main

import "fmt"

type _ɤU_0_0ɤS struct {
	_ɤx string
type _ا4اS struct {
	_اx string
}

func _ا4اSاnew(
	s _ا4اS,
) _ا4اS {
	var r _ا4اS
	return r
}

func (
	self *_ɤU_0_0ɤS,
) _ɤinit() {
	self._ɤx = "hello"
	self *_ا4اS,
) _اinit() {
	self._اx = "hello"
}

type _ɤU_0_0_0ɤT struct {
	_ɤy string
type _ا5اT struct {
	_اy string
}

func _ا5اTاnew(
	s _ا5اT,
) _ا5اT {
	var r _ا5اT
	return r
}

func (
	self *_ɤU_0_0_0ɤT,
) _ɤappend(
	self *_ا5اT,
) _اappend(
	s string,
) {
	self._ɤy = self._ɤy + s
	self._اy = self._اy + s
}

func main() {
	var s _ɤU_0_0ɤS
	var t _ɤU_0_0_0ɤT
	s._ɤinit()
	t._ɤappend(s._ɤx)
	t._ɤappend(", world")
	_ɤprintln(t._ɤy)
	var s _ا4اS
	var t _ا5اT
	s._اinit()
	t._اappend(s._اx)
	t._اappend(", world")
	_اprintln(t._اy)
}

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

M pkg/codegen/testdata/fn_struct_method.snow.want => pkg/codegen/testdata/fn_struct_method.snow.want +0 -2
@@ 22,14 22,12 @@ func _ا5اSاnew(
func (
	self *_ا5اS,
) _اinc() {
	var _ _ا5اS
	self._اx = self._اx + 1
}

func (
	self *_ا5اS,
) _اrefinc() {
	var self _ا5اS
	self._اx = self._اx + 1
}


A pkg/codegen/visit_scopes.go => pkg/codegen/visit_scopes.go +34 -0
@@ 0,0 1,34 @@
package codegen

import "git.sr.ht/~mna/snow/pkg/semantic"

type ScopeVisitor interface {
	VisitScope(s *semantic.Scope) (w ScopeVisitor)
}

func WalkScope(v ScopeVisitor, s *semantic.Scope) {
	if v = v.VisitScope(s); v == nil {
		return
	}
	for _, child := range s.Children {
		WalkScope(v, child)
	}
	v.VisitScope(nil)
}

type inspector func(s *semantic.Scope) bool

func (f inspector) VisitScope(s *semantic.Scope) ScopeVisitor {
	if f(s) {
		return f
	}
	return nil
}

// InspectScope traverses the scopes in breadth-first order: It starts by calling
// f(s); s must not be nil. If f returns true, Inspect invokes f
// recursively for each of the non-nil children of s, followed by a
// call of f(nil).
func InspectScope(s *semantic.Scope, f func(*semantic.Scope) bool) {
	WalkScope(inspector(f), s)
}

M pkg/semantic/scope.go => pkg/semantic/scope.go +0 -3
@@ 147,9 147,6 @@ func (s *Scope) Register(ident string, decl Decl) bool {
	if _, ok := s.Symbols[ident]; ok {
		return false
	}
	if s.Symbols == nil {
		s.Symbols = make(map[string]Decl)
	}
	s.Symbols[ident] = decl
	return true
}

M pkg/semantic/testdata/check/fn_access_var_outside_struct.snow.want => pkg/semantic/testdata/check/fn_access_var_outside_struct.snow.want +2 -6
@@ 8,16 8,12 @@ file testdata/fn_access_var_outside_struct.snow [0, 1, 0]
          ident string [type: string]
        fn get [let: () -> int]
          ident int [type: int]
          block [2]
            let: self [let: struct S]
              ident S [type: struct S]
          block [1]
            return
              ident x [var: int]
        struct T [0, 1, 0] [type: struct T]
          fn get [let: () -> string]
            ident string [type: string]
            block [2]
              let: self [let: struct T]
                ident T [type: struct T]
            block [1]
              return
                ident y [var: string]

M pkg/semantic/testdata/check/fn_assign_struct_fields.snow.want => pkg/semantic/testdata/check/fn_assign_struct_fields.snow.want +1 -3
@@ 41,6 41,4 @@ file testdata/fn_assign_struct_fields.snow [0, 1, 1]
    var: y [var: int]
      ident int [type: int]
    fn z [let: () -> void]
      block [1]
        let: self [let: struct S]
          ident S [type: struct S]
      block [0]

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 -6
@@ 33,17 33,13 @@ file testdata/fn_assign_struct_method_to_var.snow [0, 1, 1]
      ident int [type: int]
    fn get [let: () -> int]
      ident int [type: int]
      block [2]
        let: self [let: struct S]
          ident S [type: struct S]
      block [1]
        return
          ident x [var: int]
    ref fn set [let: (int) -> void]
      let: v [let: int]
        ident int [type: int]
      block [2]
        var: self [var: struct S]
          ident S [type: struct S]
      block [1]
        assign
          ident x [var: int]
          ident v [let: int]

M pkg/semantic/testdata/check/fn_call_struct_method.snow.want => pkg/semantic/testdata/check/fn_call_struct_method.snow.want +1 -3
@@ 15,9 15,7 @@ file testdata/fn_call_struct_method.snow [0, 1, 1]
    fn add [let: (int) -> void]
      let: y [let: int]
        ident int [type: int]
      block [2]
        let: self [let: struct Point]
          ident Point [type: struct Point]
      block [1]
        assign
          ident x [var: int]
          binary [+] [value: int]

M pkg/semantic/testdata/check/fn_call_with_labels.snow.want => pkg/semantic/testdata/check/fn_call_with_labels.snow.want +1 -3
@@ 49,6 49,4 @@ file testdata/fn_call_with_labels.snow [0, 2, 1]
    fn do [let: (int) -> void]
      let: z [let: int]
        ident int [type: int]
      block [1]
        let: self [let: struct S]
          ident S [type: struct S]
      block [0]

M pkg/semantic/testdata/check/fn_complex_selectors.snow.want => pkg/semantic/testdata/check/fn_complex_selectors.snow.want +1 -3
@@ 49,9 49,7 @@ file testdata/fn_complex_selectors.snow [0, 2, 1]
          ident int [type: int]
          sig [0->1] [type: () -> int]
            ident int [type: int]
        block [3]
          let: self [let: struct T]
            ident T [type: struct T]
        block [2]
          fn func [let: () -> int]
            ident int [type: int]
            block [1]

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

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 +1 -3
@@ 7,9 7,7 @@ file testdata/fn_invalid_ref_call_via_value.snow [0, 1, 0]
        ref fn set [let: (int) -> void]
          let: v [let: int]
            ident int [type: int]
          block [2]
            var: self [var: struct S]
              ident S [type: struct S]
          block [1]
            assign
              ident x [var: int]
              ident v [let: int]

M pkg/semantic/testdata/check/fn_method_explicit_self.snow.want => pkg/semantic/testdata/check/fn_method_explicit_self.snow.want +1 -3
@@ 13,9 13,7 @@ file testdata/fn_method_explicit_self.snow [0, 1, 1]
      ident int [type: int]
    fn getX [let: () -> int]
      ident int [type: int]
      block [2]
        let: self [let: struct S]
          ident S [type: struct S]
      block [1]
        return
          select [let: int]
            ident self [let: struct S]

M pkg/semantic/testdata/check/fn_nested_struct_method.snow.want => pkg/semantic/testdata/check/fn_nested_struct_method.snow.want +2 -6
@@ 5,9 5,7 @@ file testdata/fn_nested_struct_method.snow [0, 1, 0]
        var: x [var: string]
          ident string [type: string]
        ref fn init [let: () -> void]
          block [2]
            var: self [var: struct S]
              ident S [type: struct S]
          block [1]
            assign
              ident x [var: string]
              string ["hello"] [const: string]


@@ 17,9 15,7 @@ file testdata/fn_nested_struct_method.snow [0, 1, 0]
          ref fn append [let: (string) -> void]
            let: s [let: string]
              ident string [type: string]
            block [2]
              var: self [var: struct T]
                ident T [type: struct T]
            block [1]
              assign
                ident y [var: string]
                binary [+] [value: string]

M pkg/semantic/testdata/check/fn_nested_struct_self.snow.want => pkg/semantic/testdata/check/fn_nested_struct_self.snow.want +1 -3
@@ 7,9 7,7 @@ file testdata/fn_nested_struct_self.snow [0, 0, 1]
        ident int [type: int]
      fn negate [let: () -> int]
        ident int [type: int]
        block [2]
          let: self [let: struct T]
            ident T [type: struct T]
        block [1]
          return
            unary [-] [value: int]
              select [let: 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 +1 -3
@@ 3,8 3,6 @@ file testdata/fn_ref_on_fn_nested_in_method.snow [0, 0, 1]
    var: x [var: int]
      ident int [type: int]
    ref fn rf [let: () -> void]
      block [2]
        var: self [var: struct S]
          ident S [type: struct S]
      block [1]
        ref fn non_method [let: () -> void]
          block [0]

M pkg/semantic/testdata/check/fn_return_struct.snow.want => pkg/semantic/testdata/check/fn_return_struct.snow.want +1 -3
@@ 48,6 48,4 @@ file testdata/fn_return_struct.snow [0, 2, 1]
    var: y [var: int]
      ident int [type: int]
    fn z [let: () -> void]
      block [1]
        let: self [let: struct S]
          ident S [type: struct S]
      block [0]

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

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 +1 -3
@@ 6,8 6,6 @@ file testdata/fn_struct_method_access_top_level.snow [1, 1, 1]
  struct S [0, 1, 0] [type: struct S]
    fn get [let: () -> int]
      ident int [type: int]
      block [2]
        let: self [let: struct S]
          ident S [type: struct S]
      block [1]
        return
          ident x [var: int]

M pkg/semantic/testdata/check/fn_struct_order_independent.snow.want => pkg/semantic/testdata/check/fn_struct_order_independent.snow.want +1 -3
@@ 6,9 6,7 @@ file testdata/fn_struct_order_independent.snow [0, 0, 1]
      ident int [type: int]
    fn test [let: () -> int]
      ident int [type: int]
      block [2]
        let: self [let: struct S]
          ident S [type: struct S]
      block [1]
        return
          binary [+] [value: int]
            ident x [var: int]

M pkg/semantic/testdata/check/fn_struct_self_shadow.snow.want => pkg/semantic/testdata/check/fn_struct_self_shadow.snow.want +1 -3
@@ 4,9 4,7 @@ file testdata/fn_struct_self_shadow.snow [0, 0, 1]
      ident int [type: int]
    fn get [let: () -> int]
      ident int [type: int]
      block [2]
        let: self [let: struct S]
          ident S [type: struct S]
      block [1]
        return
          select [let: int]
            ident self [let: struct S]

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

M pkg/semantic/testdata/check/struct_var_expr_call_method.snow.want => pkg/semantic/testdata/check/struct_var_expr_call_method.snow.want +2 -6
@@ 12,9 12,7 @@ file testdata/struct_var_expr_call_method.snow [0, 1, 1]
      ident y [let: int]
    fn f [let: () -> int]
      ident int [type: int]
      block [3]
        let: self [let: struct S]
          ident S [type: struct S]
      block [2]
        assign
          ident x [var: int]
          binary [+] [value: int]


@@ 24,9 22,7 @@ file testdata/struct_var_expr_call_method.snow [0, 1, 1]
          ident x [var: int]
    ref fn f2 [let: () -> int]
      ident int [type: int]
      block [5]
        var: self [var: struct S]
          ident S [type: struct S]
      block [4]
        assign
          ident x [var: int]
          binary [+] [value: int]

M pkg/semantic/testdata/types/fn_access_var_outside_struct.snow.want => pkg/semantic/testdata/types/fn_access_var_outside_struct.snow.want +2 -6
@@ 8,16 8,12 @@ file testdata/fn_access_var_outside_struct.snow [0, 1, 0]
          ident string [type: string]
        fn get [let: () -> int]
          ident int [type: int]
          block [2]
            let: self [let: struct S]
              ident S [type: struct S]
          block [1]
            return
              ident x [var: int]
        struct T [0, 1, 0] [type: struct T]
          fn get [let: () -> string]
            ident string [type: string]
            block [2]
              let: self [let: struct T]
                ident T [type: struct T]
            block [1]
              return
                ident y [var: string]

M pkg/semantic/testdata/types/fn_assign_struct_fields.snow.want => pkg/semantic/testdata/types/fn_assign_struct_fields.snow.want +1 -3
@@ 41,6 41,4 @@ file testdata/fn_assign_struct_fields.snow [0, 1, 1]
    var: y [var: int]
      ident int [type: int]
    fn z [let: () -> void]
      block [1]
        let: self [let: struct S]
          ident S [type: struct S]
      block [0]

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 -6
@@ 33,17 33,13 @@ file testdata/fn_assign_struct_method_to_var.snow [0, 1, 1]
      ident int [type: int]
    fn get [let: () -> int]
      ident int [type: int]
      block [2]
        let: self [let: struct S]
          ident S [type: struct S]
      block [1]
        return
          ident x [var: int]
    ref fn set [let: (int) -> void]
      let: v [let: int]
        ident int [type: int]
      block [2]
        var: self [var: struct S]
          ident S [type: struct S]
      block [1]
        assign
          ident x [var: int]
          ident v [let: int]

M pkg/semantic/testdata/types/fn_call_struct_method.snow.want => pkg/semantic/testdata/types/fn_call_struct_method.snow.want +1 -3
@@ 15,9 15,7 @@ file testdata/fn_call_struct_method.snow [0, 1, 1]
    fn add [let: (int) -> void]
      let: y [let: int]
        ident int [type: int]
      block [2]
        let: self [let: struct Point]
          ident Point [type: struct Point]
      block [1]
        assign
          ident x [var: int]
          binary [+] [value: int]

M pkg/semantic/testdata/types/fn_call_with_labels.snow.want => pkg/semantic/testdata/types/fn_call_with_labels.snow.want +1 -3
@@ 49,6 49,4 @@ file testdata/fn_call_with_labels.snow [0, 2, 1]
    fn do [let: (int) -> void]
      let: z [let: int]
        ident int [type: int]
      block [1]
        let: self [let: struct S]
          ident S [type: struct S]
      block [0]

M pkg/semantic/testdata/types/fn_complex_selectors.snow.want => pkg/semantic/testdata/types/fn_complex_selectors.snow.want +1 -3
@@ 49,9 49,7 @@ file testdata/fn_complex_selectors.snow [0, 2, 1]
          ident int [type: int]
          sig [0->1] [type: () -> int]
            ident int [type: int]
        block [3]
          let: self [let: struct T]
            ident T [type: struct T]
        block [2]
          fn func [let: () -> int]
            ident int [type: int]
            block [1]

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

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

M pkg/semantic/testdata/types/fn_method_explicit_self.snow.want => pkg/semantic/testdata/types/fn_method_explicit_self.snow.want +1 -3
@@ 13,9 13,7 @@ file testdata/fn_method_explicit_self.snow [0, 1, 1]
      ident int [type: int]
    fn getX [let: () -> int]
      ident int [type: int]
      block [2]
        let: self [let: struct S]
          ident S [type: struct S]
      block [1]
        return
          select [let: int]
            ident self [let: struct S]

M pkg/semantic/testdata/types/fn_nested_struct_method.snow.want => pkg/semantic/testdata/types/fn_nested_struct_method.snow.want +2 -6
@@ 5,9 5,7 @@ file testdata/fn_nested_struct_method.snow [0, 1, 0]
        var: x [var: string]
          ident string [type: string]
        ref fn init [let: () -> void]
          block [2]
            var: self [var: struct S]
              ident S [type: struct S]
          block [1]
            assign
              ident x [var: string]
              string ["hello"] [const: string]


@@ 17,9 15,7 @@ file testdata/fn_nested_struct_method.snow [0, 1, 0]
          ref fn append [let: (string) -> void]
            let: s [let: string]
              ident string [type: string]
            block [2]
              var: self [var: struct T]
                ident T [type: struct T]
            block [1]
              assign
                ident y [var: string]
                binary [+] [value: string]

M pkg/semantic/testdata/types/fn_nested_struct_self.snow.want => pkg/semantic/testdata/types/fn_nested_struct_self.snow.want +1 -3
@@ 7,9 7,7 @@ file testdata/fn_nested_struct_self.snow [0, 0, 1]
        ident int [type: int]
      fn negate [let: () -> int]
        ident int [type: int]
        block [2]
          let: self [let: struct T]
            ident T [type: struct T]
        block [1]
          return
            unary [-] [value: int]
              select [let: int]

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

M pkg/semantic/testdata/types/fn_return_struct.snow.want => pkg/semantic/testdata/types/fn_return_struct.snow.want +1 -3
@@ 48,6 48,4 @@ file testdata/fn_return_struct.snow [0, 2, 1]
    var: y [var: int]
      ident int [type: int]
    fn z [let: () -> void]
      block [1]
        let: self [let: struct S]
          ident S [type: struct S]
      block [0]

M pkg/semantic/testdata/types/fn_struct_main_method.snow.want => pkg/semantic/testdata/types/fn_struct_main_method.snow.want +1 -3
@@ 5,6 5,4 @@ file testdata/fn_struct_main_method.snow [0, 1, 1]
    fn main [let: (int) -> void]
      let: x [let: int]
        ident int [type: int]
      block [1]
        let: self [let: struct S]
          ident S [type: struct S]
      block [0]

M pkg/semantic/testdata/types/fn_struct_method_access_top_level.snow.want => pkg/semantic/testdata/types/fn_struct_method_access_top_level.snow.want +1 -3
@@ 6,8 6,6 @@ file testdata/fn_struct_method_access_top_level.snow [1, 1, 1]
  struct S [0, 1, 0] [type: struct S]
    fn get [let: () -> int]
      ident int [type: int]
      block [2]
        let: self [let: struct S]
          ident S [type: struct S]
      block [1]
        return
          ident x [var: int]

M pkg/semantic/testdata/types/fn_struct_order_independent.snow.want => pkg/semantic/testdata/types/fn_struct_order_independent.snow.want +1 -3
@@ 6,9 6,7 @@ file testdata/fn_struct_order_independent.snow [0, 0, 1]
      ident int [type: int]
    fn test [let: () -> int]
      ident int [type: int]
      block [2]
        let: self [let: struct S]
          ident S [type: struct S]
      block [1]
        return
          binary [+] [value: int]
            ident x [var: int]

M pkg/semantic/testdata/types/fn_struct_self_shadow.snow.want => pkg/semantic/testdata/types/fn_struct_self_shadow.snow.want +1 -3
@@ 4,9 4,7 @@ file testdata/fn_struct_self_shadow.snow [0, 0, 1]
      ident int [type: int]
    fn get [let: () -> int]
      ident int [type: int]
      block [2]
        let: self [let: struct S]
          ident S [type: struct S]
      block [1]
        return
          select [let: int]
            ident self [let: struct S]

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

M pkg/semantic/testdata/types/struct_var_expr_call_method.snow.want => pkg/semantic/testdata/types/struct_var_expr_call_method.snow.want +2 -6
@@ 12,9 12,7 @@ file testdata/struct_var_expr_call_method.snow [0, 1, 1]
      ident y [let: int]
    fn f [let: () -> int]
      ident int [type: int]
      block [3]
        let: self [let: struct S]
          ident S [type: struct S]
      block [2]
        assign
          ident x [var: int]
          binary [+] [value: int]


@@ 24,9 22,7 @@ file testdata/struct_var_expr_call_method.snow [0, 1, 1]
          ident x [var: int]
    ref fn f2 [let: () -> int]
      ident int [type: int]
      block [5]
        var: self [var: struct S]
          ident S [type: struct S]
      block [4]
        assign
          ident x [var: int]
          binary [+] [value: int]

M pkg/semantic/translate_pass.go => pkg/semantic/translate_pass.go +29 -14
@@ 106,11 106,12 @@ func (t *translateVisitor) Visit(n ast.Node) ast.Visitor {
		}

		// parameters and body (possibly missing for external functions) are in a new scope
		tt := t.clone(t.scope.New(&fn))
		bodyScope := t.scope.New(&fn)
		tt := t.clone(bodyScope)
		tt.preventBlockScope = true
		if str, ok := fn.scope.Owner.(*Struct); ok {
			fn.MethodOf = str
			generateSelfVar(&fn, n.Body)
			generateSelfVar(&fn, n.Body, bodyScope)
		}
		for i, param := range n.Signature.Params {
			ast.Walk(tt, param)


@@ 498,23 499,37 @@ func (t *translateVisitor) buildVarOrExpr(kw token.Token, ident *ast.Ident, typ 
	return v.TypeExpr
}

func generateSelfVar(fn *Fn, body *ast.Block) {
func generateSelfVar(fn *Fn, body *ast.Block, bodyScope *Scope) {
	// nothing to do if there is no body
	if body == nil {
		return
	}

	// make "self" a var if the function is a ref
	kw := token.Let
	/*
		// TODO: remove if that works...
			// make "self" a var if the function is a ref
			kw := token.Let
			if fn.IsRef {
				kw = token.Var
			}
			self := &ast.VarDecl{
				Kw:    kw,
				KwPos: body.Pos(),
				Name:  &ast.Ident{Name: SelfVarName, IdentPos: body.Pos()},
				Colon: body.Pos(),
				Type:  &ast.Ident{Name: fn.MethodOf.Ident(), IdentPos: body.Pos()},
			}
			body.Stmts = append([]ast.Stmt{self}, body.Stmts...)
	*/
	// just register the "self" var in the scope
	var self Var
	self.Ctx = Immutable
	if fn.IsRef {
		kw = token.Var
	}
	self := &ast.VarDecl{
		Kw:    kw,
		KwPos: body.Pos(),
		Name:  &ast.Ident{Name: SelfVarName, IdentPos: body.Pos()},
		Colon: body.Pos(),
		Type:  &ast.Ident{Name: fn.MethodOf.Ident(), IdentPos: body.Pos()},
		self.Ctx = Mutable
	}
	body.Stmts = append([]ast.Stmt{self}, body.Stmts...)
	self.pos = body.Pos()
	self.scope = bodyScope
	self.ident = SelfVarName
	self.typ = &StructType{Decl: fn.MethodOf}
	bodyScope.Register(SelfVarName, &self)
}