Introduction

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

This is the unfair Rust quiz, a collection of very hard, gay, sometimes even unfair questions about Rust.

The canonical URL of this quiz is https://this.quiz.is.fckn.gay

You can find the repo at https://github.com/BoxyUwU/rust-quiz

Unsafe 1 @WaffleLapkin @BoxyUwU @m-ou-se @Victoronz

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

Note: the question is whether the code, as executed, is UB or whether it is sound. When the snippet has UB, explain exactly where it is UB and why.

#![allow(deref_nullptr)]

fn main() {
    // 1. UB?
    unsafe {
        _ = *std::ptr::null::<u32>();
    }
}
#![allow(deref_nullptr, unused_parens)]

fn main() {
    // 2. UB?
    unsafe {
        _ = (*std::ptr::null::<u32>());
    }
}
#![allow(deref_nullptr, unused_parens)]

fn main() {
    // 3. UB?
    unsafe {
        _ = (*std::ptr::null::<u32>(),);
    }
}
#![allow(deref_nullptr, unused_braces)]

fn main() {
    // 4. UB?
    unsafe {
        _ = { *std::ptr::null::<u32>() };
    }
}
#![allow(deref_nullptr)]

fn main() {
    // 5. UB?
    _ = unsafe { *std::ptr::null::<u32>() };
}
Solution

Examples 1 and 2 are fine, while 3, 4 and 5 are UB:

error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
 --> examples/unsafe_1_3.rs:6:14
  |
6 |         _ = (*std::ptr::null::<u32>(),);
  |              ^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
  |
  = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
  = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
  = note: BACKTRACE:
  = note: inside `main` at examples/unsafe_1_3.rs:6:14: 6:38

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to 1 previous error

error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
 --> examples/unsafe_1_4.rs:6:15
  |
6 |         _ = { *std::ptr::null::<u32>() };
  |               ^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
  |
  = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
  = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
  = note: BACKTRACE:
  = note: inside `main` at examples/unsafe_1_4.rs:6:15: 6:39

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to 1 previous error

error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
 --> examples/unsafe_1_5.rs:5:18
  |
5 |     _ = unsafe { *std::ptr::null::<u32>() };
  |                  ^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
  |
  = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
  = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
  = note: BACKTRACE:
  = note: inside `main` at examples/unsafe_1_5.rs:5:18: 5:42

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to 1 previous error

Loading a value from a null pointer is undefined behavior in Rust. However, dereferencing a pointer does not always cause a load, it only creates a place that can then be implicitly coerced to a value.

In examples 1 and 2 the dereference produces a place which is immediately discarded by the assignment to _ (note that parenthesis do not affect anything other than precedence of operators).

In example 3 the place created by the dereference is coerced to a value because (...,) creates a single element tuple (note the ,!).

In examples 4 and 5 the place created by the dereference is coerced to a value, because it is returned from a block (note that normal and unsafe blocks behave the same) which causes UB.

To learn more about differences between places and values read an article by Ralf Jung, "What is a place expression?".

Unsafe 2 @WaffleLapkin @BoxyUwU

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

Note: the question is whether the code, as executed, is UB or whether it is sound. When the snippet has UB, explain exactly where it is UB and why.

use std::mem::MaybeUninit;

fn main() {
    // Safety: all bitpatterns are valid for u8
    let random_number: u8 = unsafe { MaybeUninit::uninit().assume_init() };

    let very_random_number = if random_number <= 100 {
        unsafe {
            // Safety: all bitpatterns are valid for u32
            let rng_array: [u32; 100] = MaybeUninit::uninit().assume_init();
            // Safety: The `random_number` is in bounds
            *rng_array.get_unchecked(random_number as usize)
        }
    } else {
        // chosen by a fair dice roll
        4
    };

    dbg!(very_random_number);
}
Solution
warning: the type `u8` does not permit being left uninitialized
 --> examples/unsafe_2.rs:5:38
  |
5 |     let random_number: u8 = unsafe { MaybeUninit::uninit().assume_init() };
  |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |                                      |
  |                                      this code causes undefined behavior when executed
  |                                      help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
  |
  = note: integers must be initialized
  = note: `#[warn(invalid_value)]` on by default

warning: the type `[u32; 100]` does not permit being left uninitialized
  --> examples/unsafe_2.rs:10:41
   |
10 |             let rng_array: [u32; 100] = MaybeUninit::uninit().assume_init();
   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |                                         |
   |                                         this code causes undefined behavior when executed
   |                                         help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
   |
   = note: integers must be initialized

error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
 --> examples/unsafe_2.rs:5:38
  |
5 |     let random_number: u8 = unsafe { MaybeUninit::uninit().assume_init() };
  |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
  |
  = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
  = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
  = note: BACKTRACE:
  = note: inside `main` at examples/unsafe_2.rs:5:38: 5:73

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to 1 previous error; 2 warnings emitted

Even though all initialized bitpatterns are valid for integer types, creating an integer value from uninitialized memory is still undefined behavior. More details can be found in the MaybeUninit documentation.

Careful readers may also have noticed that there is an index out of bounds error from checking random_number <= 100 instead of random_number < 100. While this is logically incorrect, it does not result in any UB as the previous line when creating random_number is UB and thus all future lines are not executed.

Unsafe 3 @orlp @Noratrieb

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

Note: the question is whether the code, as executed, is UB or whether it is sound. When the snippet has UB, explain exactly where it is UB and why.

fn main() {
    let mut v = vec![0_u8; 10];

    // SAFETY: The vec has 10 elements, so 1 and 2 are in bounds.
    //         The two elements are distinct, so we are not overlapping.
    unsafe {
        let r1: *mut u8 = v.as_mut_ptr().add(1);
        let r2: *mut u8 = v.as_mut_ptr().add(2);
        *r1 = 10;
        *r2 = 10;
    }
}
fn main() {
    let mut v = vec![0_u8; 10];

    // SAFETY: The vec has 10 elements, so 1 and 2 are in bounds.
    //         The two elements are distinct, so we are not overlapping.
    unsafe {
        let r1: *mut u8 = v.get_unchecked_mut(1);
        let r2: *mut u8 = v.get_unchecked_mut(2);
        *r1 = 10;
        *r2 = 10;
    }
}
Solution

Example 1 is sound, example 2 is UB.

error: Undefined Behavior: attempting a write access using <2620> at alloc1189[0x1], but that tag does not exist in the borrow stack for this location
 --> examples/unsafe_3_2.rs:9:9
  |
9 |         *r1 = 10;
  |         ^^^^^^^^
  |         |
  |         attempting a write access using <2620> at alloc1189[0x1], but that tag does not exist in the borrow stack for this location
  |         this error occurs as part of an access at alloc1189[0x1..0x2]
  |
  = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
  = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
help: <2620> was created by a SharedReadWrite retag at offsets [0x1..0x2]
 --> examples/unsafe_3_2.rs:7:27
  |
7 |         let r1: *mut u8 = v.get_unchecked_mut(1);
  |                           ^^^^^^^^^^^^^^^^^^^^^^
help: <2620> was later invalidated at offsets [0x0..0xa] by a Unique retag
 --> examples/unsafe_3_2.rs:8:27
  |
8 |         let r2: *mut u8 = v.get_unchecked_mut(2);
  |                           ^^^^^^^^^^^^^^^^^^^^^^
  = note: BACKTRACE (of the first span):
  = note: inside `main` at examples/unsafe_3_2.rs:9:9: 9:17

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to 1 previous error

v.as_mut_ptr() refers to Vec::as_mut_ptr(v), which only creates a &mut reference to the vec itself.

v.get_unchecked_mut() comes from an implicit dereference to a slice, referring to <[T]>::get_unchecked_mut(Vec::deref(v)), creating a &mut to all slice elements. When doing the deref for creating r2, this full &mut invalidates r1.

Misc 1 @WaffleLapkin @BoxyUwU

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

pub unsafe const fn my_zeroed<T>() -> T {
    assert!(std::mem::size_of::<T>() <= 256);
    std::mem::transmute_copy(&[0u8; 256])
}

fn main() {
    unsafe {
        my_zeroed::<[*mut u32; 64]>();
    }
}
Solution
error: expected one of `extern` or `fn`, found keyword `const`
 --> examples/misc_1.rs:1:12
  |
1 | pub unsafe const fn my_zeroed<T>() -> T {
  |     -------^^^^^
  |     |      |
  |     |      expected one of `extern` or `fn`
  |     help: `const` must come before `unsafe`: `const unsafe`
  |
  = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`

error: could not compile `code` (example "misc_1") due to 1 previous error

As the error says, there is a given order function qualifiers must go in.

Misc 2 @WaffleLapkin @BoxyUwU

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

struct Data {
    name: String,
    bones: Vec<String>,
}

impl std::fmt::Debug for Data {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", &self.name)?;
        for bone in &self.bones {
            write!(f, " {}", bone)?;
        }
        writeln!(f, "")
    }
}

fn main() {
    let data = Data {
        name: "Boxy".into(),
        bones: vec!["fakebone1".into(), "fakebone2".into()],
    };
    dbg!(data)
}
Solution
error[E0308]: mismatched types
  --> examples/misc_2.rs:21:5
   |
16 | fn main() {
   |          - expected `()` because of default return type
...
21 |     dbg!(data)
   |     ^^^^^^^^^^ expected `()`, found `Data`
   |
   = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0308`.
error: could not compile `code` (example "misc_2") due to 1 previous error

There is a lot of fluff, the mistake is on the second to last line. dbg! returns its argument after printing to the stderr, which means that you need to use ; after it in cases like this.

Misc 3 @WaffleLapkin @BoxyUwU

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

struct Foo {
    func: fn(),
}

fn print_heheh() {
    println!("ferrisUwu")
}

fn bar(foo: Foo) {
    foo.func();
}

fn main() {
    bar(Foo { func: print_heheh });
}
Solution
error[E0599]: no method named `func` found for struct `Foo` in the current scope
  --> examples/misc_3.rs:10:9
   |
1  | struct Foo {
   | ---------- method `func` not found for this struct
...
10 |     foo.func();
   |         ^^^^ field, not a method
   |
help: to call the function stored in `func`, surround the field access with parentheses
   |
10 |     (foo.func)();
   |     +        +

For more information about this error, try `rustc --explain E0599`.
error: could not compile `code` (example "misc_3") due to 1 previous error

There is a syntactic difference between a method call and a normal call. expr.identifier() is always a method call and Foo does not have a method called func. To call the function stored in a field you need to add parenthesis:

fn bar(foo: Foo) {
    (foo.func)();
}

Note that the same problem does not apply to tuples and tuple structs, because you can't name a method with an integer identifier. i.e. the following would compile:

struct Foo(fn());

fn print_heheh() {
    println!("ferrisUwu")
}

fn main() {
    let foo = Foo(print_heheh);
    foo.0();
}

Misc 4 @BoxyUwU

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

fn main() {
    let mut map = HashMap::new();
    map.insert(1, 2);
    assert_eq!(map.get_mut(&1), Some(&mut 2));
}
Solution
error[E0433]: failed to resolve: use of undeclared type `HashMap`
 --> examples/misc_4.rs:2:19
  |
2 |     let mut map = HashMap::new();
  |                   ^^^^^^^ use of undeclared type `HashMap`
  |
help: consider importing this struct
  |
1 + use std::collections::HashMap;
  |

For more information about this error, try `rustc --explain E0433`.
error: could not compile `code` (example "misc_4") due to 1 previous error

This is a trick question (as they all are in this quiz though), HashMap is not included in the prelude and so must be imported explicitly.

Misc 5 @WaffleLapkin @BoxyUwU

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

trait Super {
    fn assoc() -> Self;
}

trait Sub: Super {}

fn f<T: Sub>() -> T {
    Sub::assoc()
}

fn main() {}
Solution
error[E0782]: trait objects must include the `dyn` keyword
 --> examples/misc_5.rs:8:5
  |
8 |     Sub::assoc()
  |     ^^^
  |
help: add `dyn` keyword before this trait
  |
8 |     <dyn Sub>::assoc()
  |     ++++    +

error[E0038]: the trait `Sub` cannot be made into an object
 --> examples/misc_5.rs:8:5
  |
8 |     Sub::assoc()
  |     ^^^ `Sub` cannot be made into an object
  |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
 --> examples/misc_5.rs:2:8
  |
2 |     fn assoc() -> Self;
  |        ^^^^^ ...because associated function `assoc` has no `self` parameter
...
5 | trait Sub: Super {}
  |       --- this trait cannot be made into an object...
help: consider turning `assoc` into a method by giving it a `&self` argument
  |
2 |     fn assoc(&self) -> Self;
  |              +++++
help: alternatively, consider constraining `assoc` so it does not apply to trait objects
  |
2 |     fn assoc() -> Self where Self: Sized;
  |                        +++++++++++++++++

error[E0308]: mismatched types
 --> examples/misc_5.rs:8:5
  |
7 | fn f<T: Sub>() -> T {
  |      -            -
  |      |            |
  |      |            expected `T` because of return type
  |      |            help: consider using an impl return type: `impl Sub`
  |      expected this type parameter
8 |     Sub::assoc()
  |     ^^^^^^^^^^^^ expected type parameter `T`, found `dyn Sub`
  |
  = note: expected type parameter `T`
               found trait object `dyn Sub`
  = help: type parameters must be constrained to match other types
  = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
  = note: the caller chooses a type for `T` which can be different from `dyn Sub`

error[E0038]: the trait `Sub` cannot be made into an object
 --> examples/misc_5.rs:8:5
  |
8 |     Sub::assoc()
  |     ^^^^^^^^^^^^ `Sub` cannot be made into an object
  |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
 --> examples/misc_5.rs:2:8
  |
2 |     fn assoc() -> Self;
  |        ^^^^^ ...because associated function `assoc` has no `self` parameter
...
5 | trait Sub: Super {}
  |       --- this trait cannot be made into an object...
help: consider turning `assoc` into a method by giving it a `&self` argument
  |
2 |     fn assoc(&self) -> Self;
  |              +++++
help: alternatively, consider constraining `assoc` so it does not apply to trait objects
  |
2 |     fn assoc() -> Self where Self: Sized;
  |                        +++++++++++++++++

error[E0277]: the size for values of type `dyn Sub` cannot be known at compilation time
 --> examples/misc_5.rs:8:5
  |
8 |     Sub::assoc()
  |     ^^^^^^^^^^^^ doesn't have a size known at compile-time
  |
  = help: the trait `Sized` is not implemented for `dyn Sub`
  = note: the return type of a function must have a statically known size

Some errors have detailed explanations: E0038, E0277, E0308, E0782.
For more information about an error, try `rustc --explain E0038`.
error: could not compile `code` (example "misc_5") due to 5 previous errors

The diagnostic is very confusing, which is clearly a bug in the compiler.

The issue here is that you can't refer to items from super traits through sub traits. Even though Sub has a super trait Super, you can't use Sub::assoc(). You can use Super::assoc() though, i.e. this compiles just fine:

trait Super {
    fn assoc() -> Self;
}

trait Sub: Super {}

fn f<T: Sub>() -> T {
    Super::assoc()
}

Trait::assoc is a shorter version of <_ as Trait>::assoc (aka fully qualified path).

Misc 6 @orlp @Noratrieb

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

What does this program print?

#![allow(unreachable_code)]

struct PrintOnDrop(&'static str);
impl Drop for PrintOnDrop {
    fn drop(&mut self) {
        eprint!("{}", self.0);
    }
}

fn main() {
    owo();
    uwu();
}

fn owo() {
    (
        (PrintOnDrop("1"), PrintOnDrop("2"), PrintOnDrop("3")),
        return,
    );
}

fn uwu() {
    (PrintOnDrop("1"), PrintOnDrop("2"), PrintOnDrop("3"), return);
}
Solution
123321

Every expression in the outermost tuple is evaluated from left to right. return is the last expression, at which point the function returns and all tuple elements are dropped. When an expression during tuple construction causes drops to be invoked, all elements are dropped from last to first. This is a general rule for local variables or temporaries in Rust and also applies to local variables.

But in owo, the first element is a fully constructed tuple, which is dropped the same way all structures are - from first to last.

Misc 8 @adotinthevoid

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

struct bar {}
fn bar() {}

struct foo();
fn foo() {}
Solution
error[E0428]: the name `foo` is defined multiple times
 --> examples/misc_8.rs:8:1
  |
7 | struct foo();
  | ------------- previous definition of the value `foo` here
8 | fn foo() {}
  | ^^^^^^^^ `foo` redefined here
  |
  = note: `foo` must be defined only once in the value namespace of this module

For more information about this error, try `rustc --explain E0428`.
error: could not compile `code` (example "misc_8") due to 1 previous error

There are 3 kinds of structs in Rust:

  1. Plain structs (eg struct Foo { bar: i32 })
  2. Tuple structs (eg struct Bar(i32);)
  3. Unit structs (eg struct Baz;)

All 3 kinds can have a struct with no fields.

Types and values live in separate namespaces, as it is usually 1 possible to syntactically determine whether an identifier the compiler needs to resolve will be an value or type .

1

except when it isn't :)

This means that struct bar {} only gets inserted into the type namespace, and fn bar only gets inserted to the value namespace (as functions in Rust are first class values [^not]). Therefore both of these declarations can co-exist.

However for struct foo, because it's a tuple struct, it also needs to insert the constructor into the value namespace. (This isn't quite the same as inserting a function, as it's also valid in pattern matching, but it's close). This then clashes with fn foo, which also lives in the value namespace, causing the compiler error.

[^not] except when they're not :)

Misc 9 @adotinthevoid @jdonszelmann @Victoronz @GoldsteinE @WaffleLapkin

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

struct Unit;
struct Tuple();
struct Struct {}

fn main() {
    Unit;
    Tuple;
    Struct;

    Unit();
    Tuple();
    Struct();

    Unit {};
    Tuple {};
    Struct {};

    Unit = Unit;
    Tuple = Tuple();
    Struct = Struct {};

    Unit { .. } = Unit { ..Unit };
    Tuple { .. } = Tuple { ..Tuple() };
    Struct { .. } = Struct { ..Struct {} };
}
Solution
error[E0423]: expected value, found struct `Struct`
 --> examples/misc_9.rs:8:5
  |
3 | struct Struct {}
  | ---------------- `Struct` defined here
...
8 |     Struct;
  |     ^^^^^^ help: use struct literal syntax instead: `Struct {}`

error[E0423]: expected value, found struct `Struct`
  --> examples/misc_9.rs:20:5
   |
3  | struct Struct {}
   | ---------------- `Struct` defined here
...
20 |     Struct = Struct {};
   |     ^^^^^^ help: use struct literal syntax instead: `Struct {}`

error[E0618]: expected function, found struct `Unit`
  --> examples/misc_9.rs:10:5
   |
1  | struct Unit;
   | ----------- struct `Unit` defined here
...
10 |     Unit();
   |     ^^^^--
   |     |
   |     call expression requires function
   |
help: `Unit` is a unit struct, and does not take parentheses to be constructed
   |
10 -     Unit();
10 +     Unit;
   |

error[E0423]: expected function, tuple struct or tuple variant, found struct `Struct`
  --> examples/misc_9.rs:12:5
   |
3  | struct Struct {}
   | ---------------- `Struct` defined here
...
12 |     Struct();
   |     ^^^^^^^^ help: use struct literal syntax instead: `Struct {}`

error[E0070]: invalid left-hand side of assignment
  --> examples/misc_9.rs:19:11
   |
19 |     Tuple = Tuple();
   |     ----- ^
   |     |
   |     cannot assign to this expression

Some errors have detailed explanations: E0070, E0423, E0618.
For more information about an error, try `rustc --explain E0070`.
error: could not compile `code` (example "misc_9") due to 5 previous errors

Unit; on it's own is fine, because Unit is declared as a unit struct, so Unit is a constant of type Unit.

Tuple; on it's own is fine, because Tuple as a value is the constructor for Tuple, with type fn() -> Tuple.

Struct; is a compiler error, because Struct only exists as a type, and never a value.

Only Tuple structs can be initialized with parentheses, because it's actually calling a constructor function.

No matter what kind a struct is, it can always be initialized with braces (even if not declared with them). Therefore all 3 statements are OK.

You cannot generally use a struct name as the left hand side of an assignment. However, with the Unit = Unit works because this is a destructuring assignment where Unit on the left is a constant pattern.

Destructuring assignment on a unit structs works as any other struct, and struct update syntax as well, even when there are no fields. Therefore, the last three statements work.

Trait Solver 1 @BoxyUwU @WaffleLapkin

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

trait Trait {}

impl Trait for for<'a> fn(&'a u32) {}

fn f()
where
    for<'a> fn(&'a u32): Trait,
{
}

fn main() {
    f();
}
Solution
error: implementation of `Trait` is not general enough
  --> examples/trait_solver_1.rs:12:5
   |
12 |     f();
   |     ^^^ implementation of `Trait` is not general enough
   |
   = note: `for<'a> fn(&'a u32)` must implement `Trait`, for any lifetime `'0`...
   = note: ...but `Trait` is actually implemented for the type `for<'a> fn(&'a u32)`

error: could not compile `code` (example "trait_solver_1") due to 1 previous error

The trait implementation is for a higher ranked function pointer (for<'a> fn). But the where clause is different, there the for<'a> is parsed as part of the bound, so the bound is on a not higher-ranked function pointer.

impl:

type: for<'a> fn(&'a u32)
trait: Trait

bound:

type: fn(&'a u32)
trait: Trait

Only higher-ranked function pointers implement the trait, so it fails to compile.

Trait Solver 2 @BoxyUwU @WaffleLapkin

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

struct A;
struct B;
struct C;

trait Trait<'a, T> {
    type Assoc;
}

trait Bound {}

impl Bound for B {}
impl Bound for C {}

impl<'a> Trait<'a, B> for A {
    type Assoc = B;
}

impl<'a> Trait<'a, C> for A {
    type Assoc = C;
}

fn f<T>(_: T)
where
    for<'a> A: Trait<'a, T>,
    for<'a> <A as Trait<'a, T>>::Assoc: Bound,
{
}

fn main() {
    f(B);
}
Solution
error[E0277]: the trait bound `for<'a> <A as Trait<'a, _>>::Assoc: Bound` is not satisfied
  --> examples/trait_solver_2.rs:30:7
   |
30 |     f(B);
   |     - ^ the trait `for<'a> Bound` is not implemented for `<A as Trait<'a, _>>::Assoc`
   |     |
   |     required by a bound introduced by this call
   |
   = help: the following other types implement trait `Bound`:
             B
             C
note: this is a known limitation of the trait solver that will be lifted in the future
  --> examples/trait_solver_2.rs:30:7
   |
30 |     f(B);
   |     --^-
   |     | |
   |     | the trait solver is unable to infer the generic types that should be inferred from this argument
   |     add turbofish arguments to this call to specify the types manually, even if it's redundant
note: required by a bound in `f`
  --> examples/trait_solver_2.rs:25:41
   |
22 | fn f<T>(_: T)
   |    - required by a bound in this function
...
25 |     for<'a> <A as Trait<'a, T>>::Assoc: Bound,
   |                                         ^^^^^ required by this bound in `f`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `code` (example "trait_solver_2") due to 1 previous error

Trait Solver 3 @BoxyUwU @WaffleLapkin

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

trait TraitA {}
trait TraitB<T: Sized> {}

impl TraitA for &dyn TraitB<[u8]> {}

trait MyDefault {
    fn default() -> Self;
}

impl<T: TraitA> MyDefault for T {
    fn default() -> T {
        todo!("not important for the example")
    }
}

fn main() {
    <&dyn TraitB<[u8]> as MyDefault>::default();
}
Solution
thread 'main' panicked at examples/trait_solver_3.rs:12:9:
not yet implemented: not important for the example
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Yeah. This actually runs.

(:

The compiler does not check "Well Formedness" of traits in trait objects, so dyn Trait<[u8]> does not produce an error, even though [u8] is not Sized.

This is might be unsound, but no one come up with an example of causing UB in safe code with this. At the very least, this is unexpected.

Trait Solver 4 @BoxyUwU @WaffleLapkin

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

trait A<'a> {
   type Assoc;
}

trait B {}

fn f(_: impl for<'a> A<'a, Assoc = impl B + 'a>) {}

impl<'a> A<'a> for () {
   type Assoc = &'a u8;
}

impl B for &u8 {}

fn main() {
   f(());
}
Solution
error: `impl Trait` can only mention lifetimes from an fn or impl
 --> examples/trait_solver_4.rs:7:45
  |
7 | fn f(_: impl for<'a> A<'a, Assoc = impl B + 'a>) {}
  |                  -- lifetime declared here  ^^

error[E0308]: mismatched types
  --> examples/trait_solver_4.rs:16:5
   |
16 |     f(());
   |     ^^^^^ one type is more general than the other
   |
   = note: expected reference `&'a _`
              found reference `&_`
note: the lifetime requirement is introduced here
  --> examples/trait_solver_4.rs:7:28
   |
7  | fn f(_: impl for<'a> A<'a, Assoc = impl B + 'a>) {}
   |                            ^^^^^^^^^^^^^^^^^^^

For more information about this error, try `rustc --explain E0308`.
error: could not compile `code` (example "trait_solver_4") due to 2 previous errors

The impls are turned into generic parameters on the function (O for the outer impl A, I for the inner impl B).

fn f<O, I>(_: O)
where
    O: for<'a> A<'a, Assoc = I>,
    I: B + 'a,
{}

When looked at like this, it can be seen that the 'a in I: B + 'a doesn't actually exist. It is supposed to come from the O: for<'a> bound, but that's a separate bound. So the I bound cannot name 'a, which is why this does not compile.

This is why nested argument-position-impl-trait can sometimes inhibit confusing behavior.

To make this example compile, you can use newly-stabilized associated type bounds instead of an impl trait. As the Assoc: B + 'a is part of the bound on the generic parameter, it can name the higher-ranked 'a.

fn f(_: impl for<'a> A<'a, Assoc: B + 'a>) {}

Trait Solver 5 @BoxyUwU @WaffleLapkin

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

trait Super {}
trait Sub<T>: Super {}

trait Overlap<T> {}
impl<T, U: Sub<T>> Overlap<T> for U {}
impl<T> Overlap<T> for () {}

fn main() {}
Solution
error[E0119]: conflicting implementations of trait `Overlap<_>` for type `()`
 --> examples/trait_solver_5.rs:6:1
  |
5 | impl<T, U: Sub<T>> Overlap<T> for U {}
  | ----------------------------------- first implementation here
6 | impl<T> Overlap<T> for () {}
  | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()`
  |
  = note: downstream crates may implement trait `Sub<_>` for type `()`

For more information about this error, try `rustc --explain E0119`.
error: could not compile `code` (example "trait_solver_5") due to 1 previous error

Trait Solver 6 @WaffleLapkin @BoxyUwU

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

fn func(a: &u32) {
    dbg!(a);
}

fn accepts_func(b: fn(&u32), c: &u32) {
    b(c);
}

fn main() {
    accepts_func(func as fn(_), &23);
}
Solution
error[E0308]: mismatched types
  --> examples/trait_solver_6.rs:10:18
   |
10 |     accepts_func(func as fn(_), &23);
   |     ------------ ^^^^^^^^^^^^^ one type is more general than the other
   |     |
   |     arguments to this function are incorrect
   |
   = note: expected fn pointer `for<'a> fn(&'a u32)`
              found fn pointer `fn(_)`
note: function defined here
  --> examples/trait_solver_6.rs:5:4
   |
5  | fn accepts_func(b: fn(&u32), c: &u32) {
   |    ^^^^^^^^^^^^ -----------

For more information about this error, try `rustc --explain E0308`.
error: could not compile `code` (example "trait_solver_6") due to 1 previous error

Let's first explicitly annotate all elided lifetimes:

fn func<'a>(a: &'a u32) {
    dbg!(a);
}

fn accepts_func<'a>(b: for<'b> fn(&'b u32), c: &'a u32) {
    b(c);
}

fn main() {
    accepts_func(func as fn(_), &23);
}

func is a higher-ranked function of type for<'a> fn(&'a u32). This means it can accept any lifetime. accepts_func's first parameter b is also a higher ranked function of the same type, so it needs a function that can accept any lifetime.

But in main, we cast the higher-ranked function type to fn(_). fn(_) is inferred to not be a higher-ranked function pointer type (inferring a specific lifetime for the argument), so it is no longer valid to pass to accepts_func.

If we instead specify it as as fn(&_) it gets inferred as a higher-ranked function pointer type again and the program compiles. Specifying an inferred type as &_ is sometimes done in real programs for closure arguments to make sure the closure type is inferred to be higher-ranked.

Type System 7 @Noratrieb

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

trait Cat {}

// meow!
impl<T> Cat for T {}

fn main() {
    let r = &0;
    require_box(Box::new(r));

    let local = 0;
    let r = &local;
    require_box(Box::new(r));
}

// Cats love boxes.
fn require_box(_a: Box<dyn Cat>) {}
Solution
error[E0597]: `local` does not live long enough
  --> examples/trait_solver_7.rs:11:13
   |
10 |     let local = 0;
   |         ----- binding `local` declared here
11 |     let r = &local;
   |             ^^^^^^ borrowed value does not live long enough
12 |     require_box(Box::new(r));
   |                 ----------- cast requires that `local` is borrowed for `'static`
13 | }
   | - `local` dropped here while still borrowed
   |
   = note: due to object lifetime defaults, `Box<dyn Cat>` actually means `Box<(dyn Cat + 'static)>`

For more information about this error, try `rustc --explain E0597`.
error: could not compile `code` (example "trait_solver_7") due to 1 previous error

Box<dyn Cat> means Box<dyn Cat + 'static>, and the local variable is not 'static. &0 does produce a &'static i32 though, because it is implicitly static-promoted.

Borrow Checker 1 @WaffleLapkin @BoxyUwU

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

fn func(a: &'static u32) {
    dbg!(a);
}

fn accepts_func(f: fn(&u32), data: &u32) {
    f(data);
}

fn main() {
    //  &'static u32 can be shortened to any
    // lifetime borrow so func should be fine
    accepts_func(func, &274);
}
Solution
error[E0308]: mismatched types
  --> examples/borrowck_1.rs:12:18
   |
12 |     accepts_func(func, &274);
   |     ------------ ^^^^ one type is more general than the other
   |     |
   |     arguments to this function are incorrect
   |
   = note: expected fn pointer `for<'a> fn(&'a _)`
                 found fn item `fn(&'static _) {func}`
note: function defined here
  --> examples/borrowck_1.rs:5:4
   |
5  | fn accepts_func(f: fn(&u32), data: &u32) {
   |    ^^^^^^^^^^^^ -----------

For more information about this error, try `rustc --explain E0308`.
error: could not compile `code` (example "borrowck_1") due to 1 previous error

Elided lifetimes in function pointers use "for all", so fn(&u32) in accepts_func is the same as for<'a> fn(&'a u32). In other words accepts_func requires a function that can be called with a reference with any lifetime.

Notably func can't be called with any lifetime — it can only be called with 'static, causing the error.

Note that normally it's okay to shorten lifetimes, i.e. coerce &'big _ to &'small _. However, in function pointers it's different, you can coerce fn(&'small _) to fn(&'big _) but not the other way around. This is because when you call fn(&'big _) the argument can be coerced to &'small _. This is also commonly known as functions being contravariant in respect to their arguments. You can learn more about variance in the Subtyping and Variance chapter of the nomicon.

Borrow Checker 2 @WaffleLapkin @BoxyUwU

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

fn main() {
    consume_fn(identity);
}

fn identity(x: &u32) -> &u32 {
    x
}

fn consume_fn<T>(_: impl FnOnce(&u32) -> T) {}
Solution
error[E0308]: mismatched types
 --> examples/borrowck_2.rs:2:5
  |
2 |     consume_fn(identity);
  |     ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
  |
  = note: expected reference `&_`
             found reference `&_`
note: the lifetime requirement is introduced here
 --> examples/borrowck_2.rs:9:42
  |
9 | fn consume_fn<T>(_: impl FnOnce(&u32) -> T) {}
  |                                          ^

For more information about this error, try `rustc --explain E0308`.
error: could not compile `code` (example "borrowck_2") due to 1 previous error

identity returns a reference with the same lifetime as the argument, i.e. it's for<'a> fn(&'a u32) -> &'a u32. consume_fn accepts some function with a signature of for<'a> fn(&'a u32) -> T where T is some type.

Notably, T is defined outside of the binder (aka "for all" qualifier, for<'a>), so it can't name 'a, causing the error.

Borrow Checker 3 @BoxyUwU

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

fn foo(a: &mut u32) -> u32 {
    let mut b = || &mut *a;

    *b() = 12;
    *b() = 73;
    *a
}

fn main() {
    foo(&mut 292);
}
Solution
error: captured variable cannot escape `FnMut` closure body
 --> examples/borrowck_3.rs:2:20
  |
1 | fn foo(a: &mut u32) -> u32 {
  |        - variable defined here
2 |     let mut b = || &mut *a;
  |                  - ^^^^^^-
  |                  | |     |
  |                  | |     variable captured here
  |                  | returns a reference to a captured variable which escapes the closure body
  |                  inferred to be a `FnMut` closure
  |
  = note: `FnMut` closures only have access to their captured variables while they are executing...
  = note: ...therefore, they cannot allow references to captured variables to escape

error: could not compile `code` (example "borrowck_3") due to 1 previous error

The closure assigned to b can only return a reference with one specific lifetime (because it has no lifetimes in arguments). So both calls to b return a unique (mutable) reference with the same lifetime, which is an error, because all unique references must be disjoint.

If you inline calls to b it would work though:

fn foo(a: &mut u32) -> u32 {
    *(&mut *a) = 12;
    *(&mut *a) = 73;
    *a
}

This is fine because reborrows return different lifetimes, allowing them to be disjoint.

Borrow Checker 4 @BoxyUwU @WaffleLapkin

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

#[derive(Debug)]
struct Foo<'a>(&'a mut u32);

fn main() {
    let mut data = 10;
    let mut foo = Foo(&mut data);
    mutate(&mut foo);
    dbg!(foo);
}

fn mutate<'a>(f: &'a mut Foo<'a>) {
    *f.0 += 1;
}
Solution
error[E0505]: cannot move out of `foo` because it is borrowed
 --> examples/borrowck_4.rs:8:5
  |
6 |     let mut foo = Foo(&mut data);
  |         ------- binding `foo` declared here
7 |     mutate(&mut foo);
  |            -------- borrow of `foo` occurs here
8 |     dbg!(foo);
  |     ^^^^^^^^^
  |     |
  |     move out of `foo` occurs here
  |     borrow later used here
  |
  = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider cloning the value if the performance cost is acceptable
  |
7 |     mutate(&mut foo).clone();
  |                     ++++++++

For more information about this error, try `rustc --explain E0505`.
error: could not compile `code` (example "borrowck_4") due to 1 previous error

mutate forces the lifetime of the reference to be the same as the lifetime of the foo itself, so you effectively can't use it ever again — any reference will overlap with the one passed to mutate.

To fix this you need to detach the lifetime of the reference from Foo's lifetime:

fn mutate<'a, 'b>(f: &'a mut Foo<'b>) { ... }

Alternatively you can elide both lifetimes:

fn mutate(f: &mut Foo<'_>) { ... }

Borrow Checker 5 @WaffleLapkin @BoxyUwU

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

use std::collections::HashMap;

fn get_or_insert_1234(map: &mut HashMap<u32, u64>) -> &mut u64 {
    if let Some(v) = map.get_mut(&0) {
        return v;
    }

    map.insert(0, 1234);
    map.get_mut(&0).unwrap()
}

fn main() {}
Solution
error[E0499]: cannot borrow `*map` as mutable more than once at a time
 --> examples/borrowck_5.rs:8:5
  |
3 | fn get_or_insert_1234(map: &mut HashMap<u32, u64>) -> &mut u64 {
  |                            - let's call the lifetime of this reference `'1`
4 |     if let Some(v) = map.get_mut(&0) {
  |                      --- first mutable borrow occurs here
5 |         return v;
  |                - returning this value requires that `*map` is borrowed for `'1`
...
8 |     map.insert(0, 1234);
  |     ^^^ second mutable borrow occurs here

error[E0499]: cannot borrow `*map` as mutable more than once at a time
 --> examples/borrowck_5.rs:9:5
  |
3 | fn get_or_insert_1234(map: &mut HashMap<u32, u64>) -> &mut u64 {
  |                            - let's call the lifetime of this reference `'1`
4 |     if let Some(v) = map.get_mut(&0) {
  |                      --- first mutable borrow occurs here
5 |         return v;
  |                - returning this value requires that `*map` is borrowed for `'1`
...
9 |     map.get_mut(&0).unwrap()
  |     ^^^ second mutable borrow occurs here

For more information about this error, try `rustc --explain E0499`.
error: could not compile `code` (example "borrowck_5") due to 2 previous errors

This error is the limitation of the current borrow checker. Because v is returned from the function, the lifetime of the reference returned from the first get_mut is inferred to be "until the end of the function". The current borrow checker does not understand that the None variant does not contain the lifetime, so after the if the reference does not need to be kept alive (there is no reference).

This is a very famous example which is fixed by the next implementation of the borrow checker, polonius.

Borrowck 6 @adotinthevoid @Noratrieb

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

type R1<'a> = &'a mut i32;
struct R2<'a>(&'a mut i32);

fn r1_once(_: R1){}
fn r2_once(_: R2){}

pub fn r1_twice(x: R1) {
    r1_once(x);
    r1_once(x);
}

pub fn r2_twice(x: R2) {
    r2_once(x);
    r2_once(x);
}

fn main() {
    r1_twice(&mut 0);
    r2_twice(R2(&mut 0));
}
Solution
error[E0382]: use of moved value: `x`
  --> examples/borrowck_6.rs:14:13
   |
12 | pub fn r2_twice(x: R2) {
   |                 - move occurs because `x` has type `R2<'_>`, which does not implement the `Copy` trait
13 |     r2_once(x);
   |             - value moved here
14 |     r2_once(x);
   |             ^ value used here after move
   |
note: consider changing this parameter type in function `r2_once` to borrow instead if owning the value isn't necessary
  --> examples/borrowck_6.rs:5:15
   |
5  | fn r2_once(_: R2){}
   |    -------    ^^ this parameter takes ownership of the value
   |    |
   |    in this function

For more information about this error, try `rustc --explain E0382`.
error: could not compile `code` (example "borrowck_6") due to 1 previous error

r2_twice does not compile because R2 does not implement Copy, and is moved twice. This is basic Rust, but r1_twice does compile even though &mut i32 does not implement Copy! That's because for R1, the reference is not moved into r1_once, it is instead reborrowed. Reborrows are a special operation on references that the borrow checker understands and behave like &mut *x. So there is just a new reference passed to r1_once, with the original one preserved.