Skip to content

When returning an unsized place from a closure, should suggest returning a reference to it instead #152064

@ais523

Description

@ais523

Code

fn main() {
    let o = Some("Hello, world!");
    for s in o.map(|s| s[3..8]) {}
}

Current output

error[E0277]: the size for values of type `str` cannot be known at compilation time
    --> src/main.rs:3:16
     |
   3 |     for s in o.map(|s| s[3..8]) {}
     |                ^^^ doesn't have a size known at compile-time
     |
     = help: the trait `Sized` is not implemented for `str`
note: required by an implicit `Sized` bound in `Option::<T>::map`
    --> /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:1160:22
     |
1160 |     pub const fn map<U, F>(self, f: F) -> Option<U>
     |                      ^ required by the implicit `Sized` requirement on this type parameter in `Option::<T>::map`

error[E0277]: the size for values of type `str` cannot be known at compilation time
 --> src/main.rs:3:24
  |
3 |     for s in o.map(|s| s[3..8]) {}
  |                        ^^^^^^^ doesn't have a size known at compile-time
  |
  = help: the trait `Sized` is not implemented for `str`
  = note: the return type of a function must have a statically known size

error[E0277]: the size for values of type `str` cannot be known at compilation time
   --> src/main.rs:3:14
    |
  3 |     for s in o.map(|s| s[3..8]) {}
    |              ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `str`
note: required by an implicit `Sized` bound in `Option`
   --> /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:600:17
    |
600 | pub enum Option<T> {
    |                 ^ required by the implicit `Sized` requirement on this type parameter in `Option`

error[E0277]: `Option<str>` is not an iterator
    --> src/main.rs:3:14
     |
   3 |     for s in o.map(|s| s[3..8]) {}
     |              ^^^^^^^^^^^^^^^^^^ `Option<str>` is not an iterator
     |
     = help: the trait `IntoIterator` is not implemented for `Option<str>`
help: the following other types implement trait `IntoIterator`
    --> /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:2304:1
     |
2304 | impl<T> const IntoIterator for Option<T> {
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Option<T>`
...
2328 | impl<'a, T> IntoIterator for &'a Option<T> {
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&Option<T>`
...
2338 | impl<'a, T> IntoIterator for &'a mut Option<T> {
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&mut Option<T>`

Desired output

error[E0277]: the size for values of type `str` cannot be known at compilation time
 --> src/main.rs:3:24
  |
3 |     for s in o.map(|s| s[3..8]) {}
  |                        ^^^^^^^ doesn't have a size known at compile-time
  |
  = help: the trait `Sized` is not implemented for `str`
  = note: the return type of a function must have a statically known size
help: consider borrowing the return value
  |
3 |     for s in o.map(|s| &s[3..8]) {}
  |                        +

Rationale and extra context

This error happens when the code attempts to return a place containing an unsized type from a closure (rather than a reference to that place). There are two things wrong with the resulting error messages.

One is that they assume throughout the rest of the compile that the return type (in this case, str) is correct (despite being impossible), which leads to a lot of secondary error messages about unsized types being used in a place where they can't be used: out of the four error messages here, only the second one (the one that lists the root cause, trying to return an unsized type) is actually useful. This can make it hard for a new user to figure out specifically where the problem is, as the other error messages are talking about side effects that the mistake has on the rest of the code rather than the mistake itself.

The other is that there is a likely fix (returning a reference to a place rather than trying to return the place itself) which should be suggested: in most cases, users who are trying to return a str or a slice from a function probably wanted to return a reference to it instead.

There may be cases where &mut is a better suggestion than &, but figuring that out would likely require a second type-check against a hypothetical type, so it may be better to just suggest & unconditionally and let the compiler suggest &mut on the next attempt.

The check should be specific to trying to return an unsized place that isn't a temporary – otherwise the user's mistake is likely to be different (and the suggestion of adding & wouldn't work anyway). It's also specific to closures with no explicitly stated return type (because when there is explicitly stated return type, either with a closure or a function, the error messages are fine already).

The code in this report is an MCVE reduced from an actual program created by a newcomer to Rust.

Other cases

// Effectively the same thing also happens with slices:
fn main() {
    let o = Some(b"Hello, world!");
    for s in o.map(|s| s[3..8]) {}
}

Rust Version

Tested on the Rust playground
Nightly version: 1.95.0-nightly (2026-02-02 f60a0f1bcc5a2a6dd8eb)

Anything else?

@rustbot label +D-lack-of-suggestion +D-confusing +D-newcomer-roadblock +A-closures +A-DSTs +S-has-mcve

Metadata

Metadata

Assignees

Labels

A-DSTsArea: Dynamically-sized types (DSTs)A-closuresArea: Closures (`|…| { … }`)A-diagnosticsArea: Messages for errors, warnings, and lintsD-confusingDiagnostics: Confusing error or lint that should be reworked.D-lack-of-suggestionDiagnostics: Adding a (structured) suggestion would increase the quality of the diagnostic.D-newcomer-roadblockDiagnostics: Confusing error or lint; hard to understand for new users.S-has-mcveStatus: A Minimal Complete and Verifiable Example has been found for this issueT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions