-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Trait bounds are not yet enforced in type definitions #21903
Comments
At first glance this is probably related to the internal messy-ness of bounds vs. where-clauses. I'm not sure if the predicate constraints for type aliases are propagated correctly. You should be able to use a newtype as a work around:
Seems to work just fine on playground with the newtype: http://is.gd/krOTZv. |
I would use a newtype but since the type I want to define is a specialized Result type that isn't possible in my case. I didn't really mention that since it is tangential to the bug itself. |
Looks like warnings are now generated for this case, but not consistently[0]. Should this be a compile-time error instead? [0] #20222 (comment) |
What is the status on trait bounds in type definitions? I worked around it the best I could for combine but it won't be as clean as it could be until bounds are allowed. |
Where bounds are allowed, they're not checked properly. I'm using this one and it compiles from Rust 1.0 or later pub type MapFn<I, B> where I: Iterator = iter::Map<I, fn(I::Item) -> B>; |
Nominating for discussion. Seems like backcompat hazard we should consider trying to address with a feature gate. |
Since the bounds provide writing types you couldn't do otherwise, they are very useful. A feature gate would be a breaking change without recourse(?). |
triage: P-medium I think this might be not that hard to fix though! |
Unless I'm missing something, this isn't a huge problem because bad things will still fail to type check right? For example the following doesn't compile. trait Foo {
fn foo(&self) -> u32 {
1
}
}
type Bar<F: Foo> = F;
fn foo(f: Bar<&str>) -> Bar<&str> {
f
}
fn main() {
let bar: Bar<&str> = "";
println!("{:?}", foo(bar.foo()));
} |
@nixpulvis I think the argument for checking type definitions is analogous to our philosophy about other polymorphic code: we don't do C++ style post template-instantiation type-checking; instead we check the polymorphic code at the definition site (even though both strategies are sound) Or maybe you are just saying the backwards incompatibility hit won't be that bad? (To which I say: famous last words. .. ;) |
So this issue is a regular annoyance. It's worth trying to figure out just what we want to do, however! The key problem is that type aliases are "invisible" to the type checker. You could almost just remove where-clauses from them altogether, but that we need them to resolve associated types in things like Enforcing all type bounds could be tricky, but may well be readily achievable. There is some backwards compatibility to worry about. I guess how we would implement it would be to extend the "item type" associated with a Another option would be to detect if the bound is needed (i.e., consumed by an associated type), and warn only if that is not the case. That would just be accepting that we allow where-clauses here even when they are not needed and will not be unenforced. Doesn't feel very good though. Seems like we might want to start by trying for the "better" fix, and then measuring the impact...? |
It's possible to `map_err_range` for `ParseResult<>` too, but it's awkward because the output type needs to be a compatible `StreamOnce`. As suggested in Marwes#86 (comment), it's probably best to either change the parse result type entirely, or wait for rust-lang/rust#21903. This at least helps consumers convert `ParseError<>` into something that can implement `std::fmt::Display`.
It's possible to `map_err_range` for `ParseResult<>` too, but it's awkward because the output type needs to be a compatible `StreamOnce`. As suggested in Marwes#86 (comment), it's probably best to either change the parse result type entirely, or wait for rust-lang/rust#21903. This at least helps consumers convert `ParseError<>` into something that can implement `std::fmt::Display`.
@nikomatsakis Would it be possible to remove that warning for these cases then? It's quite confusing. |
@RReverser I agree. I just added a to do item to try and investigate disabling the warnings. |
Yes. Originally I intended this to be a step towards turning the lint into a hard error eventually, but of course if this gets implemented properly that's even better. :) I can't imagine how to implement this in a nice backwards-compatible way, but well, you seem to have some idea :D |
…chenkov Improve lint for type alias bounds First of all, I learned just today that I was wrong assuming that the bounds in type aliases are entirely ignored: It turns out they are used to resolve associated types in type aliases. So: ```rust type T1<U: Bound> = U::Assoc; // compiles type T2<U> = U::Assoc; // fails type T3<U> = <U as Bound>::Assoc; // "correct" way to write this, maybe? ``` I am sorry for creating this mess. This PR changes the wording of the lint accordingly. Moreover, since just removing the bound is no longer always a possible fix, I tried to detect cases like `T1` above and show a helpful message to the user: ``` warning: bounds on generic parameters are not enforced in type aliases --> $DIR/type-alias-bounds.rs:57:12 | LL | type T1<U: Bound> = U::Assoc; //~ WARN not enforced in type aliases | ^^^^^ | = help: the bound will not be checked when the type alias is used, and should be removed help: use absolute paths (i.e., <T as Trait>::Assoc) to refer to associated types in type aliases --> $DIR/type-alias-bounds.rs:57:21 | LL | type T1<U: Bound> = U::Assoc; //~ WARN not enforced in type aliases | ^^^^^^^^ ``` I am not sure if I got this entirely right. Ideally, we could provide a suggestion involving the correct trait and type name -- however, while I have access to the HIR in the lint, I do not know how to get access to the resolved name information, like which trait `Assoc` belongs to above. The lint does not even run if that resolution fails, so I assume that information is available *somewhere*... This is a follow-up for (parts of) rust-lang#48326. Also see rust-lang#21903. This changes the name of a lint, but that lint was just merged to master yesterday and has never even been on beta.
Any progress here lately? (Trying to have a go at implementing trait aliases here.) |
Is there any chance this will be implemented in edition 2021? |
this would be such a juicy feature, is there any chance this will ever be implemented? |
I just encounter a case where depending on conditional compilation, my type alias could change but I wanted to make sure that whatever concrete type was chosen, at the end it will implement a trait. I posted about it here I wanted to do something like this: #[cfg(target_arch = "x86_64")]
type MyAlias: MyTrait = A;
#[cfg(target_arch = "riscv64")]
type MyAlias: MyTrait = B; |
Remake of "List matching impls on type aliases" * 4b1d13d * 6f552c8 * 2ce7cd9 Partially reverts "Fix infinite loop when retrieving impls for type alias", but keeps the test case. This version of the PR avoids the infinite loop by structurally matching types instead of using full unification. This version does not support type alias trait bounds, but the compiler does not enforce those anyway (rust-lang#21903).
To give an update to the people subscribed to this issue, the (incomplete) feature
The feature is nominated for stabilization in a future edition (202X). Its tracking issue #112792 basically supersedes this issue in my humble opinion. See also
F-lazy_type_alias
|
…l-list, r=GuillaumeGomez rustdoc: list matching impls on type aliases Fixes rust-lang#32077 Fixes rust-lang#99952 Remake of rust-lang#112429 Partially reverts rust-lang#112543, but keeps the test case. This version of the PR avoids the infinite loop by structurally matching types instead of using full unification. This version does not support type alias trait bounds, but the compiler does not enforce those anyway (rust-lang#21903). r? `@GuillaumeGomez` CC `@lcnr`
Rollup merge of rust-lang#115201 - notriddle:notriddle/type-alias-impl-list, r=GuillaumeGomez rustdoc: list matching impls on type aliases Fixes rust-lang#32077 Fixes rust-lang#99952 Remake of rust-lang#112429 Partially reverts rust-lang#112543, but keeps the test case. This version of the PR avoids the infinite loop by structurally matching types instead of using full unification. This version does not support type alias trait bounds, but the compiler does not enforce those anyway (rust-lang#21903). r? `@GuillaumeGomez` CC `@lcnr`
Opening an issue since I could not find any information on when/if this will be enforced. Would be really useful for some generalizing I am trying for parser-combinators which I can't do currently without complicating the API.
Specifically I'd like to use a trait bound in a type definition to access an associated type to avoid passing it seperately but due to this issue I simply get a compiler error.
Simplified code which exhibits the error:
The text was updated successfully, but these errors were encountered: