Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Diagnostic for Infallible #402

Merged
merged 2 commits into from
Sep 25, 2024
Merged

Implement Diagnostic for Infallible #402

merged 2 commits into from
Sep 25, 2024

Conversation

caass
Copy link
Contributor

@caass caass commented Aug 17, 2024

I've been working with some code that looks like this:

trait DiagnosticTryFrom<Input>: Sized {
  type Error: Diagnostic;

  fn try_from_diagnostic(input: Input) -> Result<Self, Self::Error>;
}

And so logically it makes sense to create a blanket implementation on top of TryInto:

impl <I, O> DiagnosticTryFrom<I> for O where O: TryFrom<I>, O::Error: Diagnostic {
  type Error = O::Error;

  fn try_from_diagnostic(input: I) -> Result<Self, Self::Error> {
    O::try_from(input)
  }
}

Which works very well for my own TryFrom implementations -- but not so well when there's a From implementation available. Every From implementation gets a blanket implementation of TryFrom with an error type of Infallible, so I'm not able to implement Diagnostic for that error type due to the orphan rule.

This PR implements Diagnostic for Infallible, so any API relying on TryFrom<T, Error: Diagnostic> can also use From<T> implementations.

@Porges
Copy link
Contributor

Porges commented Aug 18, 2024

FWIW the unsafe is not really needed here, using an empty match match *self {} should (all of the time? most of the time?) result in the same output.

Comparing using the "Show Assembly" feature in Rust Playground:

unreachableunsafe unreachablematch
use std::convert::Infallible;

trait Diagnostic {
    fn get_a_thing(&self) -> Option<String>;
}

impl Diagnostic for Infallible {
    fn get_a_thing(&self) -> Option<String> {
        unreachable!()
    }
}

#[inline(never)]
pub fn do_the_thing(x: Infallible) -> Option<String> {
    x.get_a_thing()
}
use std::convert::Infallible;

trait Diagnostic {
    fn get_a_thing(&self) -> Option<String>;
}

impl Diagnostic for Infallible {
    fn get_a_thing(&self) -> Option<String> {
        unsafe { std::hint::unreachable_unchecked() }
    }
}

#[inline(never)]
pub fn do_the_thing(x: Infallible) -> Option<String> {
    x.get_a_thing()
}
use std::convert::Infallible;

trait Diagnostic {
    fn get_a_thing(&self) -> Option<String>;
}

impl Diagnostic for Infallible {
    fn get_a_thing(&self) -> Option<String> {
        match *self {}
    }
}

#[inline(never)]
pub fn do_the_thing(x: Infallible) -> Option<String> {
    x.get_a_thing()
}
<core::convert::Infallible as playground::Diagnostic>::get_a_thing:
	pushq	%rax
	leaq	.L__unnamed_1(%rip), %rdi
	leaq	.L__unnamed_2(%rip), %rdx
	movl	$40, %esi
	callq	*core::panicking::panic@GOTPCREL(%rip)

playground::do_the_thing:
	pushq	%rax
	leaq	.L__unnamed_1(%rip), %rdi
	leaq	.L__unnamed_2(%rip), %rdx
	movl	$40, %esi
	callq	*core::panicking::panic@GOTPCREL(%rip)

.L__unnamed_1:
	.ascii	"internal error: entered unreachable code"

.L__unnamed_3:
	.ascii	"src/lib.rs"

.L__unnamed_2:
	.quad	.L__unnamed_3
	.asciz	"\n\000\000\000\000\000\000\000\t\000\000\000\t\000\000"
playground::do_the_thing:
	ud2
playground::do_the_thing:
	ud2

@zkat zkat merged commit f3fb4c1 into zkat:main Sep 25, 2024
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants