-
Notifications
You must be signed in to change notification settings - Fork 13.6k
Closed
Labels
A-const-genericsArea: const generics (parameters and arguments)Area: const generics (parameters and arguments)A-diagnosticsArea: Messages for errors, warnings, and lintsArea: Messages for errors, warnings, and lintsC-bugCategory: This is a bug.Category: This is a bug.D-confusingDiagnostics: Confusing error or lint that should be reworked.Diagnostics: Confusing error or lint that should be reworked.D-terseDiagnostics: An error or lint that doesn't give enough information about the problem at hand.Diagnostics: An error or lint that doesn't give enough information about the problem at hand.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.requires-nightlyThis issue requires a nightly compiler in some way.This issue requires a nightly compiler in some way.
Description
I tried this code:
#![feature(const_generics)]
#![allow(incomplete_features)]
use std::fmt;
const fn max(a: usize, b: usize) -> usize {
[a, b][(a < b) as usize]
}
pub struct Foo<const N: usize>;
impl<const N: usize> fmt::Debug for Foo<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "Foo({:?})", N)
}
}
// ok
fn bar_let<const N: usize, const M: usize>(a: Foo<N>, b: Foo<M>) {
let a = Foo::<{ max(N, M) }>;
println!("{:?}", a);
}
// // fail to compile
fn bar_ret<const N: usize, const M: usize>(a: Foo<N>, b: Foo<M>) -> Foo<{ max(N, M) }> {
let a = Foo::<{ max(N, M) }>;
println!("{:?}", a);
a
}
fn main() {
let a = Foo::<{ max(2, 3) }>;
println!("{:?}", a);
bar_let(Foo::<5>, Foo::<3>);
let b = bar_ret(Foo::<5>, Foo::<3>);
}
I expected to see this happen:
compile success
Instead, this happened:
error[E0308]: mismatched types
--> src/main.rs:27:5
|
24 | fn bar_ret<const N: usize, const M: usize>(a: Foo<{ N }>, b: Foo<{ M }>) -> Foo<{ max(N, M) }> {
| ------------------ expected `Foo<{ max(N, M) }>` because of return type
...
27 | a
| ^ expected `{ max(N, M) }`, found `{ max(N, M) }`
|
= note: expected struct `Foo<{ max(N, M) }>`
found struct `Foo<{ max(N, M) }>`
Meta
rustc --version --verbose
:
rustc 1.43.0-nightly (564758c4c 2020-03-08)
binary: rustc
commit-hash: 564758c4c329e89722454dd2fbb35f1ac0b8b47c
commit-date: 2020-03-08
host: x86_64-apple-darwin
release: 1.43.0-nightly
LLVM version: 9.0
Backtrace
<backtrace>
Metadata
Metadata
Assignees
Labels
A-const-genericsArea: const generics (parameters and arguments)Area: const generics (parameters and arguments)A-diagnosticsArea: Messages for errors, warnings, and lintsArea: Messages for errors, warnings, and lintsC-bugCategory: This is a bug.Category: This is a bug.D-confusingDiagnostics: Confusing error or lint that should be reworked.Diagnostics: Confusing error or lint that should be reworked.D-terseDiagnostics: An error or lint that doesn't give enough information about the problem at hand.Diagnostics: An error or lint that doesn't give enough information about the problem at hand.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.requires-nightlyThis issue requires a nightly compiler in some way.This issue requires a nightly compiler in some way.
Type
Projects
Milestone
Relationships
Development
Select code repository
Activity
Patryk27 commentedon Mar 12, 2020
This is correct according to the const generics' RFC:
cksac commentedon Mar 12, 2020
thanks @Patryk27, seems it is an Unresolved questions according to the RFC. But the error message is a bit confusing.
slightlyoutofphase commentedon Mar 13, 2020
FYI, this kind of thing compiles fine and does exactly what you expect it to do as long as you're not explicit about the generic constraints inside the function body, and let the return type be inferred from what you've already declared it as.
Here's a working playground link of your code, where the only change is just doing
let a = Foo;
inside ofbar_ret
instead oflet a = Foo::<{ max(N, M) }>;
.cksac commentedon Mar 13, 2020
@slightlyoutofphase thanks, that works. but method call will fail to compiles
slightlyoutofphase commentedon Mar 13, 2020
Yeah, I guess that kind of direct "passthrough" where both functions have exactly the same generic constraints and the second one returns the result of the first doesn't quite work yet.
I feel like that's not a huge issue probably, though.
The sort of syntax that does compile, i.e. the
let b = bar_ret(Foo::<5>, Foo::<3>);
is IMO likely the more common way of using const generics.I'd say to me at least, also, having an actual "call" (so to speak) to the
max
const fn literally as a generic parameter seems like probably not the most expected way of going about it. I'd personally viewmax
as more something you'd call with literals to determine the genericN
of aFoo
, like:type MyFoo = Foo<{max(9, 18)}>;
None of this really matters though, just my two cents after having written a bunch of code using const generics, haha.
slightlyoutofphase commentedon Mar 13, 2020
Actually, wait, I was wrong, there's a way to make this work so that you're even able to call
bar_ret
frombar_ret_2
exactly like in your last comment. You just need to declare a type alias like this:type MaxFoo<const N: usize, const M: usize> = Foo<{ max(N, M) }>;
Here's a working playground link that expands on your code a bit and uses the
MaxFoo
alias (and also adds abar_ret_3
that in turn callsbar_ret_2
just to show it works).I guess the reason it works with an alias probably has something to do with forcing the
max
call to be evaluated earlier than it would be with themax
directly in the return type. Not sure though.Patryk27 commentedon Mar 13, 2020
Using a type alias is exactly what the original RFC proposes to solve this issue.
slightlyoutofphase commentedon Mar 13, 2020
Is it a purely technical limitation currently that it doesn't work with the "direct" use of
max
in the return type, then?I can't imagine it's intentional when it seems like most people would basically expect the direct use to amount to being completely equivalent to the alias in practice.
11 remaining items