Discovered in #49039 the recent stabilization of ! unfortunately has some hazards related to coercion on the libs side of things. We discussed this at the work week and decided that we can't land PRs like #49039 which would also mean that the libs team wouldn't be able to actually recommend using ! as an error type (bummer!)
This is intended to be a tracking issue for sorting this out. I'm tagging it as a regression to mainly keep track of it, but it's not strictly speaking a regression.
cc @rust-lang/libs
cc @rust-lang/lang
@nikomatsakis, @dtolnay and I discussed this at the Rust all hands, and our preliminary opinion was that we should roll back the stabilization of ! and TryFrom until we get this sorted out. This is a super unfortunate result, but I think it's better than introducing ! and telling no one to use it as an error type.
As far as the error itself, this is happening because inference works backwards from the return type to assume that x in this expression must be of type Error:
use std::error::Error;
fn foo(x: !) -> Box<Error> {
Box::new(x)
}
Error is !Sized, however, and so is not a valid argument to Box::new.
We discussed the possibility of disabling inference where it would produce unsized argument types, but this would interact poorly with future changes to remove the Sized bound on Box::new when unsized rvalues land. @nikomatsakis suggested we might be able to come up with something tailored to the specific case of Box::new and uninhabited types, but I'm not sure what he had in mind.
Is it possible to make the ! to anything coercion have "less priority" than the type implementing a trait to trait object unsizing coercion?
I really hope we can find a solution similar to this, in time for 1.26
I talked to @nikomatsakis as well and looking at the example again it's plausible we could try unsizing coercion before the ! -> _, however, Box::new can't take an unsized type anyway.
I opened https://github.com/rust-lang/rust/issues/49691 to track specifically the rollback part.
I'm removing the regression tag since this is not a regression, and we have #49691 to track that part. This issue should be added to the various spreadsheets tracking Rust 2018 progress though.
Starting at https://github.com/rust-lang/rust/issues/35121#issuecomment-375867616 is some discussion of T: From<!> too, including how we can hack it before a real specialization solution is ready. I really think we should block stabilization on that bound too; ! as an error type is much less ergonomic without it.
Is keeping things as-is and introducing the coercion properly later on gonna cause some sort of pain or backcompat issues?
Removing from milestone now that ! is destabilized
I am wondering if there is an explanation somewhere as to why functions that take ! values as input are even type checked and compiled? It seems like we could make the compiler aware that such a function can never be invoked and have it just skip them?
Similarly for any branches that involve creation or matching of never values, I suppose...
At the codegen (LLVM backend) level, the "presence" of an uninhabited value makes the code unreachable and I assume that no code is generated. But in my opinion it鈥檚 much less obvious that we should skip type-checking.
@droundy: you might like to gather a look at https://github.com/rust-lang/rust/pull/47291, which does some of the things you're talking about.
Has there been any progress on this issue in the last months?
Does this mean ! can be stabilized now?
Confirmed that the code below now compiles on master. (With a unreachable expression warning, but without error[E0277]: the size for values of type `dyn std::error::Error` cannot be known at compilation time like before.)
#![feature(never_type)]
pub fn foo(x: !) -> Box<std::error::Error> {
Box::new(x)
}
Most helpful comment
Does this mean
!can be stabilized now?