Skip to content
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

type S = Option<Box<S>>; should compile #63097

Closed
lihz6 opened this issue Jul 29, 2019 · 3 comments
Closed

type S = Option<Box<S>>; should compile #63097

lihz6 opened this issue Jul 29, 2019 · 3 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@lihz6
Copy link

lihz6 commented Jul 29, 2019

It seems a compiler bug to me. I tried this code:

type S = Option<Box<S>>;

I expected it could compile, but instead:

lihz:linkedlist lihzhang$ cargo build
   Compiling linkedlist v0.1.0 (/Users/lihzhang/Documents/com.github/linkedlist)
error[E0391]: cycle detected when processing `S`
 --> src/lib.rs:1:21
  |
1 | type S = Option<Box<S>>;
  |                     ^
  |
  = note: ...which again requires processing `S`, completing the cycle
note: cycle used when collecting item types in top-level module
 --> src/lib.rs:1:1
  |
1 | type S = Option<Box<S>>;
  | ^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0391`.
error: Could not compile `linkedlist`.

To learn more, run the command again with --verbose.

However, the equivalent code as following compiles fine:

enum S {
    T(Option<Box<S>>),
}
@hellow554
Copy link
Contributor

hellow554 commented Jul 29, 2019

Why do you think it should be possible? What is the difference to type S = S? This is a cycle, do you agree? So, type S = Option<S> is a cycle as well? And the same goes for type S = Option<Box<S>>. All of these three examples are cycles.

Why does enum S { T(Box<S>) } work? Because it is an indirection. Box isn't the same size as S, but it is "a pointer" to S. If you go to the playground and try it yourself, the compiler will tell you what's wrong.

error[E0072]: recursive type `S` has infinite size
 --> src/lib.rs:1:1
  |
1 | enum S {
  | ^^^^^^ recursive type has infinite size
2 |     T(S)
  |       - recursive without indirection
  |
  = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `S` representable

@Centril Centril added A-diagnostics Area: Messages for errors, warnings, and lints A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jul 29, 2019
@Centril
Copy link
Contributor

Centril commented Jul 29, 2019

This is working as intended; the issue is not indirection however but rather that type aliases are aliases and so when the compiler is working out what S is it has to compute the type expression Option<Box<S>> which requires working out what S is so you have to compute Option<Box<S>>, and so we have a cycle.

This is different from enums and structs in that these introduce essentially a fixpoint:

struct S = μ S. Option<Box<S>>;

which works fine because S in Option<Box<S>> refers to the bound variable S and so we have no cycles.

See https://en.wikipedia.org/wiki/Recursive_data_type for more information.


We should perhaps recognize this case and say something about type aliases not behaving like data types suggesting an enum or struct instead. cc @oli-obk @estebank

@jonas-schievink jonas-schievink added the C-enhancement Category: An issue proposing an enhancement or a PR with one. label Jul 29, 2019
@estebank
Copy link
Contributor

Current output:

error[[E0391]](https://doc.rust-lang.org/stable/error_codes/E0391.html): cycle detected when expanding type alias `S`
 --> src/lib.rs:1:21
  |
1 | type S = Option<Box<S>>;
  |                     ^
  |
  = note: ...which immediately requires expanding type alias `S` again
  = note: type aliases cannot be recursive
  = help: consider using a struct, enum, or union instead to break the cycle
  = help: see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information
note: cycle used when collecting item types in top-level module
 --> src/lib.rs:1:1
  |
1 | type S = Option<Box<S>>;
  | ^^^^^^^^^^^^^^^^^^^^^^^^

bors added a commit to rust-lang-ci/rust that referenced this issue Sep 1, 2023
…bank,compiler-errors

Permit recursive weak type aliases

I saw rust-lang#63097 and thought "we can do ~~better~~ funnier". So here it is. It's not useful, but it's certainly something. This may actually become feasible with lazy norm (so in 5 years (constant, not reducing over time)).

r? `@estebank`

cc `@GuillaumeGomez`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

5 participants