Skip to content

Commit

Permalink
Extend E0308 description with dynamic dispatch example
Browse files Browse the repository at this point in the history
  • Loading branch information
Andre Bogus committed Mar 19, 2020
1 parent 57e1da5 commit bf29323
Show file tree
Hide file tree
Showing 3 changed files with 423 additions and 0 deletions.
47 changes: 47 additions & 0 deletions src/librustc_error_codes/error_codes/E0308.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,50 @@ variable. It can occur for several cases, the most common of which is a
mismatch in the expected type that the compiler inferred for a variable's
initializing expression, and the actual type explicitly assigned to the
variable.

One possible scenario is that we have a trait and want to use multiple
implementors conditionally via dynamic dispatch. E. g.

```compile_fail,E0308
use std::{io, fs, env};
let arg = env::args().nth(1);
let mut input = if arg == "-" {
std::io::stdin()
} else {
fs::File::open(arg)?
// expected struct `std::io::Stdin`, found struct `std::fs::File
};
// - if and else have incompatible types
Ok::<(), io::Error>(())
```

In many cases, the trait methods use self by (mutable) reference. Thus we can
create a `dyn` reference, but we need two variables for the actual objects,
because as shown above, one variable can only hold one type of object. We must
still declare the variables outside of the `if` to make sure they live long
enough.

Note that this relies on the fact that while one needs to initialize a value to
use it, Rust is clever enough to allow unused values to stay uninitialized:

```no_run
use std::{io, fs, env};
let arg = env::args().nth(1).unwrap_or("-".into());
// We only declare, not initialize the values.
let (mut stdin, mut file);
// We need to ascribe the type here to select dynamic dispatch.
let input: &mut dyn io::Read = if arg == "-" {
stdin = std::io::stdin();
&mut stdin
} else {
file = fs::File::open(arg)?;
&mut file
};
Ok::<(), io::Error>(())
```
188 changes: 188 additions & 0 deletions src/test/ui/json-bom-plus-crlf-multifile.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,53 @@ variable. It can occur for several cases, the most common of which is a
mismatch in the expected type that the compiler inferred for a variable's
initializing expression, and the actual type explicitly assigned to the
variable.

One possible scenario is that we have a trait and want to use multiple
implementors conditionally via dynamic dispatch. E. g.

```compile_fail,E0308
use std::{io, fs, env};

let arg = env::args().nth(1);

let mut input = if arg == \"-\" {
std::io::stdin()
} else {
fs::File::open(arg)?
// expected struct `std::io::Stdin`, found struct `std::fs::File
};
// - if and else have incompatible types

Ok::<(), io::Error>(())
```

In many cases, the trait methods use self by (mutable) reference. Thus we can
create a `dyn` reference, but we need two variables for the actual objects,
because as shown above, one variable can only hold one type of object. We must
still declare the variables outside of the `if` to make sure they live long
enough.

Note that this relies on the fact that while one needs to initialize a value to
use it, Rust is clever enough to allow unused values to stay uninitialized:

```no_run
use std::{io, fs, env};

let arg = env::args().nth(1).unwrap_or(\"-\".into());

// We only declare, not initialize the values.
let (mut stdin, mut file);

// We need to ascribe the type here to select dynamic dispatch.
let input: &mut dyn io::Read = if arg == \"-\" {
stdin = std::io::stdin();
&mut stdin
} else {
file = fs::File::open(arg)?;
&mut file
};
Ok::<(), io::Error>(())
```
"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":612,"byte_end":618,"line_start":17,"line_end":17,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:17:22: error[E0308]: mismatched types
"}
{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
Expand All @@ -38,6 +85,53 @@ variable. It can occur for several cases, the most common of which is a
mismatch in the expected type that the compiler inferred for a variable's
initializing expression, and the actual type explicitly assigned to the
variable.

One possible scenario is that we have a trait and want to use multiple
implementors conditionally via dynamic dispatch. E. g.

```compile_fail,E0308
use std::{io, fs, env};

let arg = env::args().nth(1);

let mut input = if arg == \"-\" {
std::io::stdin()
} else {
fs::File::open(arg)?
// expected struct `std::io::Stdin`, found struct `std::fs::File
};
// - if and else have incompatible types

Ok::<(), io::Error>(())
```

In many cases, the trait methods use self by (mutable) reference. Thus we can
create a `dyn` reference, but we need two variables for the actual objects,
because as shown above, one variable can only hold one type of object. We must
still declare the variables outside of the `if` to make sure they live long
enough.

Note that this relies on the fact that while one needs to initialize a value to
use it, Rust is clever enough to allow unused values to stay uninitialized:

```no_run
use std::{io, fs, env};

let arg = env::args().nth(1).unwrap_or(\"-\".into());

// We only declare, not initialize the values.
let (mut stdin, mut file);

// We need to ascribe the type here to select dynamic dispatch.
let input: &mut dyn io::Read = if arg == \"-\" {
stdin = std::io::stdin();
&mut stdin
} else {
file = fs::File::open(arg)?;
&mut file
};
Ok::<(), io::Error>(())
```
"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":672,"byte_end":678,"line_start":19,"line_end":19,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:19:22: error[E0308]: mismatched types
"}
{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
Expand All @@ -59,6 +153,53 @@ variable. It can occur for several cases, the most common of which is a
mismatch in the expected type that the compiler inferred for a variable's
initializing expression, and the actual type explicitly assigned to the
variable.

One possible scenario is that we have a trait and want to use multiple
implementors conditionally via dynamic dispatch. E. g.

```compile_fail,E0308
use std::{io, fs, env};

let arg = env::args().nth(1);

let mut input = if arg == \"-\" {
std::io::stdin()
} else {
fs::File::open(arg)?
// expected struct `std::io::Stdin`, found struct `std::fs::File
};
// - if and else have incompatible types

Ok::<(), io::Error>(())
```

In many cases, the trait methods use self by (mutable) reference. Thus we can
create a `dyn` reference, but we need two variables for the actual objects,
because as shown above, one variable can only hold one type of object. We must
still declare the variables outside of the `if` to make sure they live long
enough.

Note that this relies on the fact that while one needs to initialize a value to
use it, Rust is clever enough to allow unused values to stay uninitialized:

```no_run
use std::{io, fs, env};

let arg = env::args().nth(1).unwrap_or(\"-\".into());

// We only declare, not initialize the values.
let (mut stdin, mut file);

// We need to ascribe the type here to select dynamic dispatch.
let input: &mut dyn io::Read = if arg == \"-\" {
stdin = std::io::stdin();
&mut stdin
} else {
file = fs::File::open(arg)?;
&mut file
};
Ok::<(), io::Error>(())
```
"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":735,"byte_end":741,"line_start":22,"line_end":22,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:23:1: error[E0308]: mismatched types
"}
{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
Expand All @@ -80,6 +221,53 @@ variable. It can occur for several cases, the most common of which is a
mismatch in the expected type that the compiler inferred for a variable's
initializing expression, and the actual type explicitly assigned to the
variable.

One possible scenario is that we have a trait and want to use multiple
implementors conditionally via dynamic dispatch. E. g.

```compile_fail,E0308
use std::{io, fs, env};

let arg = env::args().nth(1);

let mut input = if arg == \"-\" {
std::io::stdin()
} else {
fs::File::open(arg)?
// expected struct `std::io::Stdin`, found struct `std::fs::File
};
// - if and else have incompatible types

Ok::<(), io::Error>(())
```

In many cases, the trait methods use self by (mutable) reference. Thus we can
create a `dyn` reference, but we need two variables for the actual objects,
because as shown above, one variable can only hold one type of object. We must
still declare the variables outside of the `if` to make sure they live long
enough.

Note that this relies on the fact that while one needs to initialize a value to
use it, Rust is clever enough to allow unused values to stay uninitialized:

```no_run
use std::{io, fs, env};

let arg = env::args().nth(1).unwrap_or(\"-\".into());

// We only declare, not initialize the values.
let (mut stdin, mut file);

// We need to ascribe the type here to select dynamic dispatch.
let input: &mut dyn io::Read = if arg == \"-\" {
stdin = std::io::stdin();
&mut stdin
} else {
file = fs::File::open(arg)?;
&mut file
};
Ok::<(), io::Error>(())
```
"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":801,"byte_end":809,"line_start":25,"line_end":26,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `std::string::String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":792,"byte_end":798,"line_start":25,"line_end":25,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:25:22: error[E0308]: mismatched types
"}
{"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors
Expand Down
Loading

0 comments on commit bf29323

Please sign in to comment.