Skip to content

Return-position impl Trait is not satisfied by divergent/never type #113875

Open
@wchargin

Description

@wchargin

I tried this code:

pub fn foo() -> impl Iterator<Item = u32> {
    loop {}
    // or panic!(), etc.
}

// Equivalent code modulo cut elimination
pub fn bar() -> impl Iterator<Item = u32> {
    bar_helper()
}
fn bar_helper() -> std::iter::Empty<u32> {
    loop {}
}

I expected to see this happen:

Module should compile without error. If foo or bar are invoked, they
should diverge. In particular, foo and bar should be equivalent in
terms of both static and dynamic semantics.

In general, fn foo() -> T { loop {} } should compile for any type T,
because loop {} should be at type ! and ! should be a subtype of
every type. This seems to be the case for all proper types that I've
tried, including uninhabited ones like std::convert::Infallible, but
not when T is actually a return-position impl Trait.

Instead, this happened:

error[E0277]: `()` is not an iterator
 --> src/lib.rs:1:17
  |
1 | pub fn foo() -> impl Iterator<Item = u32> {
  |                 ^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator
  |
  = help: the trait `Iterator` is not implemented for `()`

This is surprising, because I'm not sure where the unit type is coming
from. If I replace impl Iterator<Item = u32> with impl Default, or
another trait that () does implement, then it compiles without error.
But if I use impl Trait for a trait that () does not implement, then
it raises this compile-time error.

The fact that bar compiles makes it feel especially weird that foo
does not compile, because they should be equivalent. Yes, there's more
type information (I've used std::iter::Empty<u32> as a specific type
implementing Iterator<Item = u32>), but I don't see why that should
matter. The error given by rustc wasn't a "ambiguous type; specify type
annotations" kind of error.

Playground with these examples and a few more:
https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=e8061b7ffb50afef8b230892d458d26b

Meta

rustc --version --verbose:

rustc 1.70.0 (90c541806 2023-05-31)
binary: rustc
commit-hash: 90c541806f23a127002de5b4038be731ba1458ca
commit-date: 2023-05-31
host: x86_64-unknown-linux-gnu
release: 1.70.0
LLVM version: 16.0.2

Also exists in nightly 2023-07-18.

Metadata

Metadata

Assignees

Labels

A-diagnosticsArea: Messages for errors, warnings, and lintsA-docsArea: Documentation for any part of the project, including the compiler, standard library, and toolsA-trait-systemArea: Trait systemF-never_type`#![feature(never_type)]`T-langRelevant to the language team, which will review and decide on the PR/issue.T-typesRelevant to the types 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