Skip to content

Using @TypeOf for peer type resolution can trigger false dependency cycles #12000

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
topolarity opened this issue Jul 5, 2022 · 6 comments
Closed
Labels
bug Observed behavior contradicts documented or intended behavior stage1 The process of building from source via WebAssembly and the C backend.
Milestone

Comments

@topolarity
Copy link
Contributor

Zig Version

0.10.0-dev.2840+32fb86821

Steps to Reproduce

Using @TypeOf() for peer type resolution requires using @as(T, undefined) or similar.

The problem is that this will trigger resolution of T:

const T = struct {
    // Should be ?*const T, instead "error: struct 'T' depends on itself"
    next: @TypeOf(null, @as(*const T, undefined)),
};

test {
    _ = T;
}

Expected Behavior

This should resolve to a type:

const T = struct {
    next: ?*const T,
};

Actual Behavior

./example.zig:8:11: error: struct 'T' depends on itself
const T = struct {
          ^
@topolarity topolarity added the bug Observed behavior contradicts documented or intended behavior label Jul 5, 2022
@topolarity
Copy link
Contributor Author

I wanted to mention this comes from a real world use case (despite the exotic type situation): I'm currently struggling with this in a parser combinator library I'm writing.

Recursive parse trees lead to recursive types (#6211 is another issue I've had to work around), and I use peer resolution in some cases to combine multiple function results for different alternatives in the grammar.

@nektro
Copy link
Contributor

nektro commented Jul 5, 2022

dependency is true. @as(*const T, undefined) requires knowing size of T, meaning all fields have to be resolved. this is in a field type expression however.

@topolarity
Copy link
Contributor Author

It's a pointer, so the size of T doesn't need to be known afaict. For reference, this does work:

const T = struct {
    next: ?*const T,
};

@topolarity
Copy link
Contributor Author

topolarity commented Jul 5, 2022

Tried to workaround this by re-implementing peer type resolution (poorly) in userspace.

This seems possible, but it has to be manually inlined to avoid dependency cycles caused by constructing new types in a function call:

fn Ident(comptime U: type) type {
    return U;
}

fn Optional(comptime U: type) type {
    return ?U;
}

fn PeerResolve(comptime T: type, comptime U: type) type {
    if (T == @TypeOf(null) and U != void) {
        return ?U;
    } else if (T != void and U == @TypeOf(null)) {
        return ?T;
    } else unreachable;
}

const Foo = struct {
    const MaybePtrFoo1 = @TypeOf(null, @as(*const Foo, undefined));
    const MaybePtrFoo2 = PeerResolve(@TypeOf(null), *const Foo);

    // next1: MaybePtrFoo1, // error: struct 'Foo' depends on itself
    // next2: MaybePtrFoo2, // error: struct 'Foo' depends on itself
    // next3: Optional(*const Foo), // error: struct 'Foo' depends on itself
    next4: ?*const Foo,
    next5: Ident(*const Foo),
    next6: *const Ident(Foo),
};

test {
    _ = Foo;
}

@Vexu
Copy link
Member

Vexu commented Jul 5, 2022

It's a pointer, so the size of T doesn't need to be known afaict.

Not true in stage1 #6706. The example is special cased.

@Vexu Vexu added the stage1 The process of building from source via WebAssembly and the C backend. label Jul 5, 2022
@Vexu Vexu added this to the 0.12.0 milestone Jul 5, 2022
@topolarity
Copy link
Contributor Author

Ah, that explains it - Thanks for the info @Vexu.

Glad to see this is already resolved in stage2 🙂

wooster0 added a commit to wooster0/zig that referenced this issue Dec 15, 2022
wooster0 added a commit to wooster0/zig that referenced this issue Dec 15, 2022
wooster0 added a commit to wooster0/zig that referenced this issue Dec 15, 2022
wooster0 added a commit to wooster0/zig that referenced this issue Dec 15, 2022
wooster0 added a commit to wooster0/zig that referenced this issue Dec 16, 2022
wooster0 added a commit to wooster0/zig that referenced this issue Dec 17, 2022
wooster0 added a commit to wooster0/zig that referenced this issue Dec 18, 2022
wooster0 added a commit to wooster0/zig that referenced this issue Dec 18, 2022
wooster0 added a commit to wooster0/zig that referenced this issue Dec 21, 2022
@andrewrk andrewrk modified the milestones: 0.12.0, 0.11.0 Dec 27, 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