rust-lang / rust-lang/rfcs

Make `<T as Trait>::U == V` always succeed if `<T as Trait>::U` is `!`

Open
#1,825 18 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

T-lang
Dominant language
Markdown
Stars
6.6k
Forks
1.7k
Avg merge
16h 14m
Merged PRs (30d)
1

Description

Using #![feature(never_type)] from RFC 1216, I'd like to write a Future instance for !, so that the following compiles:

#![feature(never_type)]

use futures::future::Future;
use std::io::Error;

fn main() {
    // the type of `panic!()` doesn't matter as the function call is unreachable
    i_take_a_future(panic!());
}

fn i_take_a_future<F>(f: F)
    where F: Future<Item = u8, Error = Error>
{
    // do whatever with the future
}

As described in RFC 1216, any trait whose only associated items are methods has a trivial instance for !: just fill in every method body with match self {}. Future, however, has two associated types, Item and Error. Definitions reproduced from futures-rs:

trait Future {
    type Item;
    type Error;
    
    fn poll(&mut self) -> Poll<Self::Item, Self::Error>;
}

type Poll<T, E> = Result<Async<T>, E>;

enum Async<T> {
    Ready(T),
    NotReady,
}

A Future instance for ! can be written as follows:


impl Future for ! {
    type Item = !;
    type Error = !;
    
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match self {}
    }
}

This works in nightly Rust, but the instance isn't very useful, as it can only be used where Item and Error are expected to be !. Trying the initial example produces a type match error:

error[E0271]: type mismatch resolving `<! as Future>::Item == u8`
  --> <anon>
   |
   |     i_take_a_future(panic!());
   |     ^^^^^^^^^^^^^^^ expected !, found u8
   |
   = note: expected type `!`
   = note:    found type `u8`
   = note: required by `i_take_a_future`

error[E0271]: type mismatch resolving `<! as Future>::Error == std::io::Error`
  --> <anon>
   |
   |     i_take_a_future(panic!());
   |     ^^^^^^^^^^^^^^^ expected !, found struct `std::io::Error`
   |
   = note: expected type `!`
   = note:    found type `std::io::Error`
   = note: required by `i_take_a_future`

As far as I can tell, it would be safe for any <T as Trait>::U == V to match successfully if <T as Trait>::U is !, in the same way that expressions of type ! can implicitly cast cast to any type, because a value of type ! can never actually be produced.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading RFC 1216 and the never_type behavior described in this issue, then examine how associated-type equality constraints are handled for !. Use the Future example as the motivating case. Done means determining and specifying whether <T as Trait>::U == V may match when the associated type is !, with the safety and type-checking implications addressed.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.