Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 27 additions & 5 deletions compiler/lowering.go
Original file line number Diff line number Diff line change
Expand Up @@ -9275,10 +9275,11 @@ const taglessSwitchValue = "(true as boolean)"
func (o *LoweringOwner) lowerSwitchStmt(ctx lowerFileContext, stmt *ast.SwitchStmt) ([]loweredStmt, []Diagnostic) {
var diagnostics []Diagnostic
var init []loweredStmt
var prelude []loweredStmt
if stmt.Init != nil {
lowered, initDiagnostics := o.lowerStmt(ctx, stmt.Init)
var initDiagnostics []Diagnostic
ctx, prelude, init, initDiagnostics = o.lowerSwitchInit(ctx, stmt.Init)
diagnostics = append(diagnostics, initDiagnostics...)
init = append(init, lowered...)
}

value := taglessSwitchValue
Expand Down Expand Up @@ -9361,7 +9362,25 @@ func (o *LoweringOwner) lowerSwitchStmt(ctx lowerFileContext, stmt *ast.SwitchSt
return []loweredStmt{lowered}, diagnostics
}
init = append(init, lowered)
return []loweredStmt{{children: init}}, diagnostics
return append(prelude, loweredStmt{children: init}), diagnostics
}

// lowerSwitchInit lowers the init statement of a switch or type switch, as
// lowerStmt does for an if init. A short declaration that redeclares a name
// its initializer reads, as in switch pos, err := f(pos), saves the outer
// value in prelude, to emit before the block of the switch. It returns the
// context for the rest of the switch, in which the new names are visible.
func (o *LoweringOwner) lowerSwitchInit(
ctx lowerFileContext,
init ast.Stmt,
) (lowerFileContext, []loweredStmt, []loweredStmt, []Diagnostic) {
initCtx := ctx
var prelude []loweredStmt
if stmtCtx, nextCtx, aliasPrelude, ok := o.lowerShortDeclStatementContext(ctx, init); ok {
initCtx, ctx, prelude = stmtCtx, nextCtx, aliasPrelude
}
lowered, diagnostics := o.lowerStmt(initCtx, init)
return ctx, prelude, lowered, diagnostics
}

// splitSwitchFallthrough returns the statements of a case body without its
Expand Down Expand Up @@ -9429,8 +9448,11 @@ func constantComparableType(ctx lowerFileContext, expr ast.Expr) string {
func (o *LoweringOwner) lowerTypeSwitchStmt(ctx lowerFileContext, stmt *ast.TypeSwitchStmt) ([]loweredStmt, []Diagnostic) {
var lowered []loweredStmt
var diagnostics []Diagnostic
var prelude []loweredStmt
if stmt.Init != nil {
init, initDiagnostics := o.lowerStmt(ctx, stmt.Init)
var init []loweredStmt
var initDiagnostics []Diagnostic
ctx, prelude, init, initDiagnostics = o.lowerSwitchInit(ctx, stmt.Init)
diagnostics = append(diagnostics, initDiagnostics...)
lowered = append(lowered, init...)
}
Expand Down Expand Up @@ -9500,7 +9522,7 @@ func (o *LoweringOwner) lowerTypeSwitchStmt(ctx lowerFileContext, stmt *ast.Type
switchIR.site = o.lowerTypeSwitchSite(ctx, switchIR)
}
lowered = append(lowered, loweredStmt{typeSwitch: switchIR})
return lowered, diagnostics
return append(prelude, lowered...), diagnostics
}

// lowerTypeSwitchSite returns the hoisted runtime site of a type switch whose
Expand Down
6 changes: 6 additions & 0 deletions tests/tests/shadow_define_init/expected.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
switchInit: 2
ifInit: 2
block: 2
single: 4
forInit: 3
typeSwitchInit: 5
Empty file.
69 changes: 69 additions & 0 deletions tests/tests/shadow_define_init/shadow_define_init.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package main

func next(n int) (int, error) {
return n + 1, nil
}

// switchInit redeclares pos in a switch init from the outer pos.
func switchInit(pos int) int {
switch pos, err := next(pos); err {
case nil:
return pos
}
return -1
}

// ifInit redeclares pos in an if init from the outer pos.
func ifInit(pos int) int {
if pos, err := next(pos); err == nil {
return pos
}
return -1
}

// block redeclares pos in a nested block from the outer pos.
func block(pos int) int {
{
pos, err := next(pos)
if err == nil {
return pos
}
}
return -1
}

// single redeclares pos with a single value in a switch init.
func single(pos int) int {
switch pos := pos * 2; pos {
case 4:
return pos
}
return -1
}

// forInit redeclares i in a for init from the outer i.
func forInit(i int) int {
sum := 0
for i := i; i < 3; i++ {
sum += i
}
return sum
}

// typeSwitchInit redeclares v in a type switch init from the outer v.
func typeSwitchInit(v any) int {
switch v, ok := v.(int); any(ok).(type) {
case bool:
return v
}
return -1
}

func main() {
println("switchInit:", switchInit(1))
println("ifInit:", ifInit(1))
println("block:", block(1))
println("single:", single(2))
println("forInit:", forInit(1))
println("typeSwitchInit:", typeSwitchInit(5))
}
114 changes: 114 additions & 0 deletions tests/tests/shadow_define_init/shadow_define_init.gs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Generated file based on shadow_define_init.go
// Updated when compliance tests are re-run, DO NOT EDIT!

import * as $ from "@goscript/builtin/index.js"

export function next(n: number): [number, $.GoError] {
return [n + 1, null]
}

export function switchInit(pos: number): number {
let __goscriptShadow0 = pos
{
let __goscriptTuple0: any = next(__goscriptShadow0)
let __goscriptShadow1: number = __goscriptTuple0[0]
let err: $.GoError = __goscriptTuple0[1]
let __goscriptSwitch0 = err
switch ((true as boolean)) {
case __goscriptSwitch0 == null:
{
return __goscriptShadow1
break
}
}
}
return -1
}

export function ifInit(pos: number): number {
let __goscriptShadow2 = pos
{
let __goscriptTuple1: any = next(__goscriptShadow2)
let __goscriptShadow3: number = __goscriptTuple1[0]
let err: $.GoError = __goscriptTuple1[1]
if (err == null) {
return __goscriptShadow3
}
}
return -1
}

export function block(pos: number): number {
{
let __goscriptShadow4 = pos
let __goscriptTuple2: any = next(__goscriptShadow4)
let __goscriptShadow5: number = __goscriptTuple2[0]
let err: $.GoError = __goscriptTuple2[1]
if (err == null) {
return __goscriptShadow5
}
}
return -1
}

export function single(pos: number): number {
let __goscriptShadow6 = pos
{
let __goscriptShadow7 = __goscriptShadow6 * 2
switch (__goscriptShadow7) {
case 4:
{
return __goscriptShadow7
break
}
}
}
return -1
}

export function forInit(i: number): number {
let sum = 0
{
let __goscriptShadow8 = i
for (let __goscriptShadow9 = __goscriptShadow8; __goscriptShadow9 < 3; __goscriptShadow9++) {
sum += __goscriptShadow9
}
}
return sum
}

export function typeSwitchInit(v: any): number {
let __goscriptShadow10 = v
let __goscriptTuple3: any = $.typeAssertTuple<number>(__goscriptShadow10, /* @__PURE__ */ $.basicType("int"))
let __goscriptShadow11: number = __goscriptTuple3[0]
let ok: boolean = __goscriptTuple3[1]
{
const __goscriptTypeSwitchValue = ok
switch ($.typeSwitchCase(__goscriptTypeSwitchValue, __goscriptStatic0())) {
case 0:
{
return __goscriptShadow11
}
break
}
}
return -1
}

export async function main(): globalThis.Promise<void> {
await $.println("switchInit:", switchInit(1))
await $.println("ifInit:", ifInit(1))
await $.println("block:", block(1))
await $.println("single:", single(2))
await $.println("forInit:", forInit(1))
await $.println("typeSwitchInit:", typeSwitchInit($.basicInterfaceValue(5, "int")))
}

var __goscriptStatic0$value: any
function __goscriptStatic0(): any {
return __goscriptStatic0$value ??= ($.typeSwitchSite([/* @__PURE__ */ $.basicType("bool")]))
}

if ($.isMainScript(import.meta)) {
await main()
}
25 changes: 25 additions & 0 deletions tests/tests/shadow_define_init/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"compilerOptions": {
"paths": {
"*": [
"./*"
],
"@go/github.com/s4wave/goscript/*": [
"../../../*"
],
"@goscript/*": [
"../../../tests/tests/shadow_define_init/run/output/@goscript/*",
"../../../gs/*",
"../../../tests/deps/*"
],
"@goscript/github.com/s4wave/goscript/tests/tests/shadow_define_init/*": [
"./*"
]
}
},
"extends": "../../../tests/tsconfig.base.json",
"include": [
"index.ts",
"shadow_define_init.gs.ts"
]
}
Loading