• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

forst-lang / forst / 28339482643

28 Jun 2026 11:21PM UTC coverage: 75.708% (+0.3%) from 75.457%
28339482643

push

github

web-flow
feat(compiler): improve constraints, guards, and codegen (#116)

Co-authored-by: Cursor <cursoragent@cursor.com>

263 of 417 new or added lines in 27 files covered. (63.07%)

6 existing lines in 4 files now uncovered.

25089 of 33139 relevant lines covered (75.71%)

124.27 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.93
/forst/internal/typechecker/infer_function_node.go
1
package typechecker
2

3
import (
4
        "forst/internal/ast"
5

6
        logrus "github.com/sirupsen/logrus"
7
)
8

9
func (tc *TypeChecker) inferFunctionNode(functionNode ast.FunctionNode) ([]ast.TypeNode, error) {
964✔
10
        prevFn := tc.currentFunction
964✔
11
        tc.currentFunction = &functionNode
964✔
12
        prevErrBranchDepth := tc.resultErrIfBranchDepth
964✔
13
        tc.resultErrIfBranchDepth = 0
964✔
14
        defer func() {
1,928✔
15
                tc.currentFunction = prevFn
964✔
16
                tc.resultErrIfBranchDepth = prevErrBranchDepth
964✔
17
        }()
964✔
18

19
        tc.log.WithFields(logrus.Fields{
964✔
20
                "function": "inferNodeType",
964✔
21
                "fn":       functionNode.Ident.ID,
964✔
22
                "phase":    "ENTER",
964✔
23
        }).Debug("Function node type inference")
964✔
24

964✔
25
        if err := tc.RestoreScope(functionNode); err != nil {
964✔
26
                return nil, err
×
27
        }
×
28
        tc.log.WithFields(logrus.Fields{
964✔
29
                "function": "inferNodeType",
964✔
30
                "fn":       functionNode.Ident.ID,
964✔
31
        }).Debug("Restored function scope")
964✔
32

964✔
33
        for _, param := range functionNode.Params {
1,121✔
34
                switch typedParam := param.(type) {
157✔
35
                case ast.SimpleParamNode:
156✔
36
                        tc.scopeStack.currentScope().RegisterSymbol(
156✔
37
                                typedParam.Ident.ID,
156✔
38
                                []ast.TypeNode{typedParam.Type},
156✔
39
                                SymbolVariable)
156✔
40
                case ast.DestructuredParamNode:
1✔
41
                        tc.registerDestructuredParamSymbols(typedParam.Fields, typedParam.Type, SymbolVariable)
1✔
42
                }
43
        }
44
        tc.DebugPrintCurrentScope()
964✔
45

964✔
46
        params := make([]ast.Node, len(functionNode.Params))
964✔
47
        for index, param := range functionNode.Params {
1,121✔
48
                params[index] = param
157✔
49
        }
157✔
50

51
        paramTypes, err := tc.inferNodeTypes(params, functionNode)
964✔
52
        if err != nil {
964✔
53
                return nil, err
×
54
        }
×
55

56
        for index, inferredParamTypes := range paramTypes {
1,121✔
57
                param := functionNode.Params[index]
157✔
58
                tc.log.WithFields(logrus.Fields{
157✔
59
                        "paramTypes": inferredParamTypes,
157✔
60
                        "param":      param.GetIdent(),
157✔
61
                        "function":   "inferNodeType",
157✔
62
                }).Trace("Storing param variable type")
157✔
63

157✔
64
                switch p := param.(type) {
157✔
65
                case ast.SimpleParamNode:
156✔
66
                        tc.scopeStack.currentScope().RegisterSymbol(
156✔
67
                                p.Ident.ID,
156✔
68
                                inferredParamTypes,
156✔
69
                                SymbolVariable)
156✔
70
                        if len(inferredParamTypes) > 0 {
312✔
71
                                tc.VariableTypes[p.Ident.ID] = append([]ast.TypeNode(nil), inferredParamTypes...)
156✔
72
                        }
156✔
73
                case ast.DestructuredParamNode:
1✔
74
                        if shapeFields, ok := tc.ShapeFieldsFromParamType(p.Type); ok {
2✔
75
                                for _, fieldName := range p.Fields {
3✔
76
                                        sf, ok := shapeFields[fieldName]
2✔
77
                                        if !ok {
2✔
NEW
78
                                                continue
×
79
                                        }
80
                                        if tn, ok := ShapeFieldTypeNode(sf); ok {
4✔
81
                                                fieldTypes := []ast.TypeNode{tn}
2✔
82
                                                tc.scopeStack.currentScope().RegisterSymbol(
2✔
83
                                                        ast.Identifier(fieldName),
2✔
84
                                                        fieldTypes,
2✔
85
                                                        SymbolVariable)
2✔
86
                                                tc.VariableTypes[ast.Identifier(fieldName)] = append([]ast.TypeNode(nil), fieldTypes...)
2✔
87
                                        }
2✔
88
                                }
89
                        }
90
                }
91
        }
92

93
        if signature, ok := tc.Functions[functionNode.Ident.ID]; ok {
1,899✔
94
                for index := range signature.Parameters {
1,070✔
95
                        if index < len(paramTypes) && len(paramTypes[index]) >= 1 {
270✔
96
                                signature.Parameters[index].Type = paramTypes[index][0]
135✔
97
                        }
135✔
98
                }
99
        }
100

101
        for _, bodyNode := range functionNode.Body {
2,695✔
102
                if _, err := tc.inferNodeType(bodyNode); err != nil {
1,768✔
103
                        return nil, err
37✔
104
                }
37✔
105
        }
106

107
        inferredType, err := tc.inferFunctionReturnType(functionNode)
927✔
108
        if err != nil {
927✔
109
                return nil, err
×
110
        }
×
111
        tc.storeInferredFunctionReturnType(&functionNode, inferredType)
927✔
112
        if err := tc.validateInferredReceiverMethodReturn(functionNode, inferredType); err != nil {
928✔
113
                return nil, err
1✔
114
        }
1✔
115
        tc.popScope()
926✔
116

926✔
117
        tc.log.WithFields(logrus.Fields{
926✔
118
                "function": "inferNodeType",
926✔
119
                "fn":       functionNode.Ident.ID,
926✔
120
                "phase":    "EXIT",
926✔
121
        }).Debug("Function node type inference")
926✔
122

926✔
123
        return inferredType, nil
926✔
124
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc