diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 949f4457aa32..c7a20f243b0c 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -55,10 +55,9 @@ fn foo(x: Empty) { // empty } } - ``` -but this won't: +However, this won't: ``` fn foo(x: Option) { @@ -71,7 +70,18 @@ fn foo(x: Option) { E0003: r##" Not-a-Number (NaN) values cannot be compared for equality and hence can never -match the input to a match expression. To match against NaN values, you should +match the input to a match expression. So, the following will not compile: + +``` +const NAN: f32 = 0.0 / 0.0; + +match number { + NAN => { /* ... */ }, + // ... +} +``` + +To match against NaN values, you should instead use the `is_nan()` method in a guard, like so: ``` @@ -429,22 +439,20 @@ match 5u32 { "##, E0038: r####" +Trait objects like `Box` can only be constructed when certain +requirements are satisfied by the trait in question. -Trait objects like `Box`, can only be constructed when certain -requirements are obeyed by the trait in question. - -Trait objects are a form of dynamic dispatch and use dynamically sized types. -So, for a given trait `Trait`, when `Trait` is treated as a type, as in -`Box`, the inner type is "unsized". In such cases the boxed pointer is a -"fat pointer" and contains an extra pointer to a method table for dynamic -dispatch. This design mandates some restrictions on the types of traits that are -allowed to be used in trait objects, which are collectively termed as "object -safety" rules. +Trait objects are a form of dynamic dispatch and use a dynamically sized type +for the inner type. So, for a given trait `Trait`, when `Trait` is treated as a +type, as in `Box`, the inner type is "unsized". In such cases the boxed +pointer is a "fat pointer" that contains an extra pointer to a table of methods +(among other things) for dynamic dispatch. This design mandates some +restrictions on the types of traits that are allowed to be used in trait +objects, which are collectively termed as "object safety" rules. Attempting to create a trait object for a non object-safe trait will trigger this error. - There are various rules: ### The trait cannot require `Self: Sized` @@ -463,7 +471,7 @@ trait Foo where Self: Sized { we cannot create an object of type `Box` or `&Foo` since in this case `Self` would not be `Sized`. -Generally `Self : Sized` is used to indicate that the trait should not be used +Generally, `Self : Sized` is used to indicate that the trait should not be used as a trait object. If the trait comes from your own crate, consider removing this restriction. @@ -475,6 +483,7 @@ This happens when a trait has a method like the following: trait Trait { fn foo(&self) -> Self; } + impl Trait for String { fn foo(&self) -> Self { "hi".to_owned() @@ -488,8 +497,11 @@ impl Trait for u8 { } ``` -In such a case, the compiler cannot predict the return type of `foo()` in a case -like the following: +(Note that `&self` and `&mut self` are okay, it's additional `Self` types which +cause this problem) + +In such a case, the compiler cannot predict the return type of `foo()` in a +situation like the following: ``` fn call_foo(x: Box) { @@ -498,8 +510,10 @@ fn call_foo(x: Box) { } ``` -If the offending method isn't actually being called on the trait object, you can -add a `where Self: Sized` bound on the method: +If only some methods aren't object-safe, you can add a `where Self: Sized` bound +on them to mark them as explicitly unavailable to trait objects. The +functionality will still be available to all other implementers, including +`Box` which is itself sized (assuming you `impl Trait for Box`) ``` trait Trait { @@ -508,10 +522,10 @@ trait Trait { } ``` -Now, `foo()` can no longer be called on the trait object, but you will be -allowed to call other trait methods and construct the trait objects. With such a -bound, one can still call `foo()` on types implementing that trait that aren't -behind trait objects. +Now, `foo()` can no longer be called on a trait object, but you will now be +allowed to make a trait object, and that will be able to call any object-safe +methods". With such a bound, one can still call `foo()` on types implementing +that trait that aren't behind trait objects. ### Method has generic type parameters @@ -535,10 +549,10 @@ impl Trait for u8 { // ... ``` -at compile time a table of all implementations of `Trait`, containing pointers -to the implementation of `foo()` would be generated. +at compile time each implementation of `Trait` will produce a table containing +the various methods (and other items) related to the implementation. -This works fine, but when we the method gains generic parameters, we can have a +This works fine, but when the method gains generic parameters, we can have a problem. Usually, generic parameters get _monomorphized_. For example, if I have @@ -555,12 +569,14 @@ implementation on-demand. If you call `foo()` with a `bool` parameter, the compiler will only generate code for `foo::()`. When we have additional type parameters, the number of monomorphized implementations the compiler generates does not grow drastically, since the compiler will only generate an -implementation if the function is called with hard substitutions. +implementation if the function is called with unparametrized substitutions +(i.e., substitutions where none of the substituted types are themselves +parametrized). However, with trait objects we have to make a table containing _every object that implements the trait_. Now, if it has type parameters, we need to add -implementations for every type that implements the trait, bloating the table -quickly. +implementations for every type that implements the trait, and there could +theoretically be an infinite number of types. For example, with @@ -675,13 +691,46 @@ safe, so they are forbidden when specifying supertraits. There's no easy fix for this, generally code will need to be refactored so that you no longer need to derive from `Super`. - "####, E0079: r##" Enum variants which contain no data can be given a custom integer representation. This error indicates that the value provided is not an integer literal and is therefore invalid. + +For example, in the following code, + +``` +enum Foo { + Q = "32" +} +``` + +we try to set the representation to a string. + +There's no general fix for this; if you can work with an integer +then just set it to one: + +``` +enum Foo { + Q = 32 +} +``` + +however if you actually wanted a mapping between variants +and non-integer objects, it may be preferable to use a method with +a match instead: + +``` +enum Foo { Q } +impl Foo { + fn get_str(&self) -> &'static str { + match *self { + Foo::Q => "32", + } + } +} +``` "##, E0080: r##" @@ -704,8 +753,7 @@ https://doc.rust-lang.org/reference.html#ffi-attributes "##, E0109: r##" -You tried to give a type parameter to a type which doesn't need it. Erroneous -code example: +You tried to give a type parameter to a type which doesn't need it; for example: ``` type X = u32; // error: type parameters are not allowed on this type @@ -713,24 +761,25 @@ type X = u32; // error: type parameters are not allowed on this type Please check that you used the correct type and recheck its definition. Perhaps it doesn't need the type parameter. + Example: ``` -type X = u32; // ok! +type X = u32; // this compiles ``` "##, E0110: r##" -You tried to give a lifetime parameter to a type which doesn't need it. -Erroneous code example: +You tried to give a lifetime parameter to a type which doesn't need it; for +example: ``` type X = u32<'static>; // error: lifetime parameters are not allowed on // this type ``` -Please check that you used the correct type and recheck its definition, -perhaps it doesn't need the lifetime parameter. Example: +Please check that the correct type was used and recheck its definition; perhaps +it doesn't need the lifetime parameter. Example: ``` type X = u32; // ok!