Add expression functions with context boundaries
This commit is contained in:
parent
5085ae51aa
commit
773c34f3f4
18 changed files with 391 additions and 52 deletions
86
internal/lang/expression_function_test.go
Normal file
86
internal/lang/expression_function_test.go
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
package lang
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestExpressionBodiedFunctionInfersReturnType(t *testing.T) {
|
||||
program, err := Parse(`package demo
|
||||
fun twice(value: Int) = value * 2
|
||||
fun text() = "value"`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
output, err := GenerateGo(program)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, expected := range []string{"func twice(value int) int", "return value * 2", "func text() string", `return "value"`} {
|
||||
if !strings.Contains(string(output), expected) {
|
||||
t.Fatalf("missing %q:\n%s", expected, output)
|
||||
}
|
||||
}
|
||||
if got := ResolvedType(program.Functions[0].ExpressionBody).String(); got != "Int" {
|
||||
t.Fatalf("return type = %s", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpressionBodyInferenceReachesFixedPoint(t *testing.T) {
|
||||
program, err := Parse(`package demo
|
||||
fun first() = second()
|
||||
fun second() = third()
|
||||
fun third() = 42`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
semantic, err := Analyze(program)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, name := range []string{"first", "second", "third"} {
|
||||
symbol, _ := semantic.Global.Lookup(name)
|
||||
if got := symbol.Type.(FunctionType).Result.String(); got != "Int" {
|
||||
t.Fatalf("%s result = %s", name, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithContextExpressionBodyEstablishesBoundary(t *testing.T) {
|
||||
program, err := Parse(`package demo
|
||||
import http net.http
|
||||
import exec os.exec
|
||||
fun work() { exec.commandContext("date") }
|
||||
fun handle(request: *http.Request) = withContext(request.context()) {
|
||||
work()
|
||||
}`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
semantic, err := Analyze(program)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !semantic.FunctionEffects["work"].Has(CoroutineEffect) {
|
||||
t.Fatal("work should require ambient context")
|
||||
}
|
||||
if semantic.FunctionEffects["handle"].Has(CoroutineEffect) {
|
||||
t.Fatal("withContext should be an effect boundary")
|
||||
}
|
||||
output, err := GenerateGo(program)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
code := string(output)
|
||||
for _, expected := range []string{
|
||||
"func work(gotlinScope *GotlinCoroutineScope)",
|
||||
`exec.CommandContext(gotlinScope.Context(), "date")`,
|
||||
"func handle(request *http.Request)",
|
||||
"gotlinRunWithContext(request.Context()",
|
||||
"work(gotlinScope)",
|
||||
} {
|
||||
if !strings.Contains(code, expected) {
|
||||
t.Fatalf("missing %q:\n%s", expected, code)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue