Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions compiler/rustc_driver_impl/src/session_diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ pub(crate) struct RlinkCorruptFile<'a> {

#[derive(Diagnostic)]
#[diag("the compiler unexpectedly panicked. This is a bug")]
#[note("we would appreciate a bug report with a minimal reproduction at the URL below")]

@workingjubilee workingjubilee Jul 15, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not require a minimal reproduction. We need any reproducer. And the link itself contains explanation of what we are hoping for in an ideal bug report.

@workingjubilee workingjubilee Jul 15, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "URL below" is on a line that says:

note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md

So this is not really new information?

View changes since the review

#[note("set `RUST_BACKTRACE=1` environment variable to display a backtrace")]
#[note("try running `cargo clean` and rebuilding; transient failures do sometimes occur")]

@workingjubilee workingjubilee Jul 15, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want to know when incremental errors are repeatedly recurring, and this feels like it tacitly encourages people to not report them. We could say something but I'm not sure it is this sort of "don't worry about it" thing?

pub(crate) struct Ice;

#[derive(Diagnostic)]
Expand Down
50 changes: 50 additions & 0 deletions compiler/rustc_error_codes/src/error_codes/E0035.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
The type parameter list on a method call was provided, but the method in
question doesn't accept type parameters directly at the call site.

Note: E0035 was previously used for "argument count mismatch" but has since been
merged into E0087/E0089. The most common way to encounter a related message
today is when using turbofish syntax on a **trait method** that does not accept
type parameters at the call site.

## Turbofish on trait methods

A common mistake is trying to specify the output type of a trait method like
`into()` using turbofish syntax:

```rust,ignore
let x: u32 = y.into::<u32>(); // This does not work
```

Trait methods do not accept turbofish syntax because the type is resolved by
the trait bound, not by the call site. Attempting this produces an error
because `Into::into` takes no type parameters.

The correct approach is to annotate the **variable binding** with the expected
type, which lets the compiler infer the correct trait implementation:

```
let y: i32 = 42;
let x: u32 = y.into(); // ok: compiler infers `Into<u32>` from the type of `x`
```

Alternatively, use the fully-qualified syntax which does allow you to name the
trait explicitly:

```
let y: i32 = 42;
let x = Into::<u32>::into(y); // ok: fully-qualified call names the trait
```

When the type must be specified at the call site for another method, use a
type annotation on the variable instead of turbofish:

```
// Instead of: let x = some_value.method::<Type>()
// Write: let x: Type = some_value.method()
let x: Vec<char> = "hello".chars().rev().collect(); // ok
```

See also [E0283] for the "type annotations required" error that often precedes
the turbofish attempt.

[E0283]: https://doc.rust-lang.org/error_codes/E0283.html
41 changes: 41 additions & 0 deletions compiler/rustc_error_codes/src/error_codes/E0038.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ Rust, trait object types were written as plain `Trait` (just the name of the
trait, written in type positions) but this was a bit too confusing, so we now
write `dyn Trait`.

**What is a trait object?** A trait object (`dyn Trait`) is a way to store or
pass values of *different* concrete types behind a single pointer, as long as
all those types implement `Trait`. For example, `Box<dyn Animal>` can hold a
`Dog` or a `Cat` — the compiler does not know which at compile time, so it uses
dynamic dispatch (a vtable pointer at runtime) to call the right method.

Some traits are not allowed to be used as trait object types. The traits that
are allowed to be used as trait object types are called "dyn-compatible"[^1]
traits. Attempting to use a trait object type for a trait that is not
Expand Down Expand Up @@ -31,6 +37,41 @@ aspects.

[^1]: Formerly known as "object-safe".

## Common mistake: using a trait as a direct parameter type

A frequent trigger of E0038 is writing a trait name where a concrete type or
generic is expected:

```compile_fail,E0038
use std::thread;

fn named_thread(name: Into<String>, f: impl FnOnce()) {
// ^^^^^^^^^^^^ `Into<String>` is not a concrete type;
// this becomes `dyn Into<String>` which
// is not dyn-compatible because `Into`
// has a method that returns `Self`
}
```

The fix is to use a **generic type parameter** or **`impl Trait`** syntax:

```
use std::thread;

// Option 1: generic type parameter
fn named_thread_generic<S: Into<String>>(name: S, f: impl FnOnce()) {
// ...
}

// Option 2: impl Trait (equivalent, more concise)
fn named_thread(name: impl Into<String>, f: impl FnOnce()) {
// ...
}
```

Both forms tell the compiler "accept any concrete type that implements
`Into<String>`", without creating a trait object.

### The trait requires `Self: Sized`

Traits that are declared as `Trait: Sized` or which otherwise inherit a
Expand Down
80 changes: 67 additions & 13 deletions compiler/rustc_error_codes/src/error_codes/E0117.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,48 @@ trait defined in another crate) where
- all of the parameters being passed to the trait (if there are any) are also
foreign.

To avoid this kind of error, ensure that at least one local type is referenced
by the `impl`:
## Understanding "local" vs "foreign" types

- A **local type** is any type defined in the **current** crate.
- A **foreign type** is any type defined in **another** crate (including `std`,
`core`, and any dependency).

The orphan rule requires that **at least one** type mentioned in the `impl` is
local. This prevents two crates from each providing conflicting implementations
for the same trait+type combination, which would cause ambiguity.

### The three cases that trigger E0117

**Case 1: Foreign trait + foreign type**

```compile_fail,E0117
// `Display` is foreign (from `std`), `Vec<i32>` is foreign (from `std`)
use std::fmt;
impl fmt::Display for Vec<i32> {} // error: both trait and type are foreign
```
pub struct Foo; // you define your type in your crate

impl Drop for Foo { // and you can implement the trait on it!
// code of trait implementation here
# fn drop(&mut self) { }
}
**Case 2: Foreign trait + all-foreign type parameters**

impl From<Foo> for i32 { // or you use a type from your crate as
// a type parameter
fn from(i: Foo) -> i32 {
0
}
```compile_fail,E0117
// `From` is foreign, and both `String` and `Vec<u8>` are foreign
impl From<Vec<u8>> for String {} // error: no local type involved
```

**Case 3: Foreign trait on a foreign generic type, even with a local parameter**

```compile_fail,E0117
// `Iterator` is foreign, `Vec<MyLocal>` uses Vec (foreign) as the outer type.
// A local type as a *type parameter* of a foreign generic type is not enough.
struct MyLocal;
impl Iterator for Vec<MyLocal> { // error: the "implementing type" Vec<_> is foreign
type Item = MyLocal;
fn next(&mut self) -> Option<MyLocal> { None }
}
```

Alternatively, define a trait locally and implement that instead:
## How to fix E0117

**Fix 1:** Define the trait locally and implement that instead:

```
trait Bar {
Expand All @@ -45,6 +67,38 @@ impl Bar for u32 {
}
```

**Fix 2:** Wrap the foreign type in a local newtype and implement the trait on
the wrapper:

```
use std::fmt;

// Wrap the foreign type in a local struct
struct MyVec(Vec<i32>);

impl fmt::Display for MyVec {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.0)
}
}
```

**Fix 3:** Use a local type as the `Self` type with a foreign trait:

```
pub struct Foo; // local type

impl Drop for Foo { // ok: Foo is local
fn drop(&mut self) { }
}

impl From<Foo> for i32 { // ok: Foo is local (as a type parameter)
fn from(i: Foo) -> i32 {
0
}
}
```

For information on the design of the orphan rules, see [RFC 1023].

[RFC 1023]: https://github.com/rust-lang/rfcs/blob/master/text/1023-rebalancing-coherence.md
97 changes: 97 additions & 0 deletions compiler/rustc_error_codes/src/error_codes/E0277.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,100 @@ fn main() {

Rust only looks at the signature of the called function, as such it must
already specify all requirements that will be used for every type parameter.

## E0277 with the `?` operator — missing `From` implementation

A common and confusing case of E0277 occurs when using the `?` operator for
error propagation. When `?` is used inside a function, it **implicitly converts**
the error type using the `From` trait. If the conversion is not implemented, you
will see an error like:

```
the trait `From<Error1>` is not implemented for `Error2`
```

The connection to `?` is not always obvious. Here is an example:

```compile_fail,E0277
use std::num::ParseIntError;
use std::fmt;

#[derive(Debug)]
struct MyError(String);

impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "my error: {}", self.0)
}
}

// This function returns `MyError`, but `?` tries to convert `ParseIntError`
// into `MyError` using `From<ParseIntError>` — which isn't implemented.
fn parse_number(s: &str) -> Result<i32, MyError> {
let n = s.parse::<i32>()?; // error: `From<ParseIntError>` not implemented for `MyError`
Ok(n)
}
```

The `?` operator expands roughly to:

```rust,ignore
let n = match s.parse::<i32>() {
Ok(val) => val,
Err(e) => return Err(MyError::from(e)), // requires From<ParseIntError> for MyError
};
```

**Fix option 1:** Implement `From<ParseIntError>` for `MyError`:

```
use std::num::ParseIntError;
use std::fmt;

#[derive(Debug)]
struct MyError(String);

impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "my error: {}", self.0)
}
}

impl From<ParseIntError> for MyError {
fn from(e: ParseIntError) -> MyError {
MyError(e.to_string())
}
}

fn parse_number(s: &str) -> Result<i32, MyError> {
let n = s.parse::<i32>()?; // ok: From<ParseIntError> is now implemented
Ok(n)
}
```

**Fix option 2:** Convert the error explicitly without `?`:

```
use std::num::ParseIntError;

#[derive(Debug)]
struct MyError(String);

fn parse_number(s: &str) -> Result<i32, MyError> {
let n = s.parse::<i32>().map_err(|e| MyError(e.to_string()))?;
Ok(n)
}
```

**Fix option 3:** Use a boxed error type that accepts any error implementing
`std::error::Error`:

```
fn parse_number(s: &str) -> Result<i32, Box<dyn std::error::Error>> {
let n = s.parse::<i32>()?; // ok: Box<dyn Error> implements From<E> for any E: Error
Ok(n)
}
```

When you see E0277 involving `From`, look for `?` operators in the function
body — the `?` is almost certainly the source of the implicit conversion attempt.
41 changes: 41 additions & 0 deletions compiler/rustc_error_codes/src/error_codes/E0283.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,44 @@ impl Into<u32> for Foo {
let foo = Foo;
let bar: u32 = Into::<u32>::into(foo) * 1u32;
```

## Annotating `into()` — turbofish does not work on trait methods

A common follow-up mistake when seeing E0283 on `into()` is to try to use
turbofish syntax to specify the type:

```rust,ignore
let x: u32 = y.into::<u32>(); // error[E0035]: does not take type parameters
```

This does **not** work. `Into` is a trait, and trait methods do not accept
turbofish syntax directly. The type must be inferred from the surrounding
context rather than specified at the call site.

The correct ways to annotate an `into()` call are:

**Option 1:** Annotate the binding with its expected type:

```
let y: i32 = 42;
let x: u32 = y.into(); // compiler infers `Into<u32>` from the annotation on `x`
```

**Option 2:** Use a type-ascription-style cast with `as` for primitive types:

```
let y: i32 = 42;
let x = y as u32;
```

**Option 3:** Use the fully-qualified syntax to name the trait explicitly:

```
let y: i32 = 42;
let x = Into::<u32>::into(y);
```

See also [E0035] for the error produced when turbofish is mistakenly used on a
trait method.

[E0035]: https://doc.rust-lang.org/error_codes/E0035.html
Loading
Loading