Skip to content

Tagged union sometimes returns without the data. #2896

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ntgraff opened this issue Jul 14, 2019 · 2 comments
Closed

Tagged union sometimes returns without the data. #2896

ntgraff opened this issue Jul 14, 2019 · 2 comments
Labels
bug Observed behavior contradicts documented or intended behavior stage1 The process of building from source via WebAssembly and the C backend.
Milestone

Comments

@ntgraff
Copy link

ntgraff commented Jul 14, 2019

When this code returns, unless the function runs first and returns null, it will return State{ .Playing = }. If the function is run and returns null and is then run to return PlayingState.init(...) it will return State{ .Playing = PlayingState{ <data> }}.

With the relevant code cut out:

// in main game loop, game_state is State { .MainMenu = MainMenuState }
for (pressed_keys.toSlice()) |key| if (game_state.handleKey(&ctx, key)) |state| {
    std.debug.warn("switching to a new state!\n");
    game_state = state;
};
pressed_keys.shrink(0);

// in State
fn handleKey(state: *State, ctx: *Context, key: Key) ?State {
    switch (state.*) {
        .Playing => |*s| ...,
        .MainMenu => |*s| switch (key) {
            .Space => return PlayingState.init(c_allocator, ctx),
            .Escape => {
                c.glfwSetWindowShouldClose(ctx.window, c.GL_TRUE);
                return null;
            },
            else => return null,
        },
    }
}

A few examples of what happens, $ is terminal output, <> and () are what is going on:

<space is pressed>
$ switching to a new state!
(no state switch happens)
<space is pressed>
$ switching to a new state!
(no state switch happens)
<up is pressed>
<space is pressed>
(state switch happens successfully)
<up is pressed>
<space is pressed>
$ switching to a new state!
(state switches successfully)

I believe that the compiler should not allow the return to just be PlayingState.init(...), because it is not correct. The current way it does it does not work as expected.

@mikdusan
Copy link
Member

mikdusan commented Jul 15, 2019

here's a reduction that I think is pretty close to the issue.

  • when using initDirect() compiler is uncertain about the type of container being initialized
  • when using initCall() compiler does not error and generates llvm-ir to call a function with result-location type mismatch (llvm-ir appended below); looks related to broken module with error union and union(enum) #2881

reduction.zig: use one of { initDirect() or initCall() }

export fn foo() void {
    var state = initDirect();
    //var state = initCall();
}

// error: no member named 'value' in union 'State
fn initDirect() State {
    return One{ .value = 255 };
}

// llvm-ir error: Call parameter type does not match function signature!
fn initCall() State {
    return One.init();
}

const State = union(enum) {
    one: One,
};

const One = struct {
    value: u8,

    fn init() One {
        return One{ .value = 255 };
    }
};

llvm-ir when using initCall() -- One.init() is called with %State* result-location

; Function Attrs: nobuiltin nounwind sspstrong
define internal fastcc void @initCall(%State* nonnull sret) unnamed_addr #2 !dbg !50 {
Entry:
  call fastcc void @One.init(%State* sret %0), !dbg !54
  ret void, !dbg !56
}

; Function Attrs: nobuiltin nounwind sspstrong
define internal fastcc void @One.init(%One* nonnull sret) unnamed_addr #2 !dbg !57 {
Entry:
  %1 = getelementptr inbounds %One, %One* %0, i32 0, i32 0, !dbg !61
  store i8 -1, i8* %1, align 1, !dbg !63
  ret void, !dbg !64
}

@andrewrk andrewrk added this to the 0.5.0 milestone Jul 16, 2019
@andrewrk andrewrk added the bug Observed behavior contradicts documented or intended behavior label Jul 16, 2019
@andrewrk andrewrk modified the milestones: 0.5.0, 0.6.0 Sep 29, 2019
@andrewrk andrewrk added the stage1 The process of building from source via WebAssembly and the C backend. label Feb 10, 2020
@andrewrk andrewrk modified the milestones: 0.6.0, 0.7.0 Apr 3, 2020
@andrewrk andrewrk modified the milestones: 0.7.0, 0.8.0 Aug 13, 2020
@andrewrk andrewrk modified the milestones: 0.8.0, 0.9.0 Nov 6, 2020
@andrewrk andrewrk modified the milestones: 0.9.0, 0.10.0 May 19, 2021
@Vexu
Copy link
Member

Vexu commented Dec 28, 2022

This is a combination of #2802 and missing casts fixed in #3727

@Vexu Vexu closed this as completed Dec 28, 2022
@andrewrk andrewrk modified the milestones: 0.12.0, 0.11.0 Dec 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Observed behavior contradicts documented or intended behavior stage1 The process of building from source via WebAssembly and the C backend.
Projects
None yet
Development

No branches or pull requests

4 participants