Introduce typed semantic analysis pipeline

This commit is contained in:
pavel 2026-08-27 19:28:24 +02:00
commit f4cd4f4458
30 changed files with 2079 additions and 2381 deletions

View file

@ -1096,7 +1096,7 @@ fun main() {
}
}
func TestGenerateGoChannelsAndSelect(t *testing.T) {
func TestGenerateGoChannelSendAndRead(t *testing.T) {
src := `
package demo
@ -1105,13 +1105,8 @@ fun writer(ch: Channel<Int>) {
}
fun main() {
val ch = Channel<Int>()
runBlocking {
launch { writer(ch) }
select {
ch -> println(it)
}
}
val ch = Channel<Int>(1)
writer(ch)
val v = ch.read()
println(v)
}
@ -1131,12 +1126,8 @@ fun main() {
for _, want := range []string{
`func writer(ch chan int)`,
`ch <- 7`,
`ch := make(chan int)`,
`gotlinScope.Launch`,
`ch := make(chan int, 1)`,
`writer(ch)`,
`select {`,
`case it := <-ch:`,
`fmt.Println(it)`,
`v := <-ch`,
`fmt.Println(v)`,
} {
@ -1146,138 +1137,6 @@ fun main() {
}
}
func TestGenerateGoSelectAfterAndEvery(t *testing.T) {
src := `
package demo
fun main() {
select {
after(1000) -> println(it)
every(250) -> println("tick")
}
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`"time"`,
`func gotlinEveryMs(ms int) <-chan time.Time {`,
`case it := <-time.After(time.Duration(1000) * time.Millisecond):`,
`fmt.Println(it)`,
`case <-gotlinEveryMs(250):`,
`fmt.Println("tick")`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoEveryRejectsNonPositiveMilliseconds(t *testing.T) {
cases := []string{
`every(0)`,
`every(-1)`,
}
for _, timerCall := range cases {
src := `
package demo
fun main() {
select {
` + timerCall + ` -> println("x")
}
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
_, err = GenerateGo(prog)
if err == nil {
t.Fatalf("expected go generation error for %s", timerCall)
}
if !strings.Contains(err.Error(), "every(ms) requires ms > 0") {
t.Fatalf("unexpected error for %s: %v", timerCall, err)
}
}
}
func TestGenerateGoAfterEveryArityValidation(t *testing.T) {
cases := []struct {
call string
want string
}{
{`after()`, "after(ms) expects exactly one Int argument"},
{`after(1, 2)`, "after(ms) expects exactly one Int argument"},
{`every()`, "every(ms) expects exactly one Int argument"},
{`every(1, 2)`, "every(ms) expects exactly one Int argument"},
}
for _, tc := range cases {
src := `
package demo
fun main() {
select {
` + tc.call + ` -> println("x")
}
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
_, err = GenerateGo(prog)
if err == nil {
t.Fatalf("expected go generation error for %s", tc.call)
}
if !strings.Contains(err.Error(), tc.want) {
t.Fatalf("unexpected error for %s: %v", tc.call, err)
}
}
}
func TestGenerateGoAfterEveryIntValidation(t *testing.T) {
cases := []struct {
call string
want string
}{
{`after("1s")`, "after(ms) expects an Int argument"},
{`every(true)`, "every(ms) expects an Int argument"},
}
for _, tc := range cases {
src := `
package demo
fun main() {
select {
` + tc.call + ` -> println("x")
}
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
_, err = GenerateGo(prog)
if err == nil {
t.Fatalf("expected go generation error for %s", tc.call)
}
if !strings.Contains(err.Error(), tc.want) {
t.Fatalf("unexpected error for %s: %v", tc.call, err)
}
}
}
func TestGenerateGoNoTimeImportWhenUnused(t *testing.T) {
src := `
package demo
@ -1300,36 +1159,6 @@ fun main() {
}
}
func TestGenerateGoNoTickerShorthandRewrite(t *testing.T) {
src := `
package demo
import time
fun main() {
val tick = time.NewTicker(time.Second)
select {
tick -> println("x")
}
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
if strings.Contains(code, "<-tick.C") {
t.Fatalf("ticker shorthand rewrite should be removed:\n%s", code)
}
if !strings.Contains(code, "case <-tick:") {
t.Fatalf("expected raw source receive in generated code:\n%s", code)
}
}
func TestGenerateGoExplicitErrorsForBunStyleCalls(t *testing.T) {
src := `
package demo