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

Unsized return types are allowed on trait associated function declarations #109270

Open
Vlad-Shcherbina opened this issue Mar 17, 2023 · 2 comments
Labels
A-type-system Area: Type system C-discussion Category: Discussion or questions that doesn't represent real issues. T-types Relevant to the types team, which will review and decide on the PR/issue.

Comments

@Vlad-Shcherbina
Copy link

I tried this code:

trait MyTrait {
    fn f() -> [u8];  // Ok, but it shouldn't be
}

impl MyTrait for () {
    fn f() -> [u8] {  // Compilation error, as expected
        todo!()
    }
}

I expect the line marked with "Ok" to cause compilation error, because the return type is unsized.
It's better to produce diagnostics early, without waiting until somebody tries to implement this trait (which would be impossible anyway).

Instead, this happens: the compiler allows to declare the associated function f(), and only complains when I try to implement it for a concrete type.

I did a quick search in the issue tracker and it looks like it's maybe similar to #82633.

Meta

rustc --version --verbose:

rustc 1.70.0-nightly (7b4f48927 2023-03-12)
binary: rustc
commit-hash: 7b4f48927dce585f747a58083b45ab62b9d73a53
commit-date: 2023-03-12
host: x86_64-unknown-linux-gnu
release: 1.70.0-nightly
LLVM version: 15.0.7

@Vlad-Shcherbina Vlad-Shcherbina added the C-bug Category: This is a bug. label Mar 17, 2023
@HeroicKatora
Copy link
Contributor

Naming the type of such a function is also allowed too, without involving any trait.

type t = fn() -> [u8];

Both look perfectly fine to me. The trait definition itself only defines that: for each impl, they must have a member of such type. The fact that it currently uninhabited in practice, i.e. no impl can actually instantiate a value to satisfy the requirement, and so no impl can exist, makes it less useful but by no means implies it to be wrong, per-se. There's no need to forbid this effectively similar definition either:

enum Empty {}

trait Test {
    const A: Empty;
}

Maybe a lint could be helpful nevertheless. Definitely not deny-by-default though, that would be static_assert(false) with intermediate steps and we should definitely look at the long road of progress on that.

@Vlad-Shcherbina
Copy link
Author

Interesting. I see value in uninhabited types because they can still be used as parts of inhabited types. For example, Result<T, Uninhabited> could be used to signal that an error is impossible, even in places where the type system requires a Result<>. This works because types have a disjunction in the form of an enum.

But unimplementable traits seem completely useless unless I'm missing something. Trait constraints don't have disjunction, do they?

So, optimizing purely for user experience and ignoring implementation cost, my gut feeling is that this should be at least a warning (and the same goes for const A: Empty;).

@fmease fmease added A-type-system Area: Type system C-discussion Category: Discussion or questions that doesn't represent real issues. T-types Relevant to the types team, which will review and decide on the PR/issue. and removed needs-triage-legacy C-bug Category: This is a bug. labels Jan 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-type-system Area: Type system C-discussion Category: Discussion or questions that doesn't represent real issues. T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants