Skip to content

Trait bounds are not yet enforced in type definitions #21903

Open

Description

@Marwes

View all comments

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:

trait Stream {
    type Item;
}

trait Parser {
    type Input: Stream;
}

fn test<T>(u: T) -> T
    where T: Parser {
    panic!()
}

type Res<I: Stream> = (I, <I as Stream>::Item);

impl <'a> Stream for &'a str { type Item = char; }
impl <I> Parser for fn (I) -> Res<I> where I: Stream { type Input = I; }

//Works
//fn f(_: &str) -> (&str, char) {

//Errors
fn f(_: &str) -> Res<&str> {
    panic!()
}

fn main() {
    let _ = test(f as fn (_) -> _);
}

Activity

  1. jroesch commented on Feb 3, 2015

    @jroesch
    Contributor

    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:

    struct Res<I: Stream>((I, <I as Stream>::Item))
    

    Seems to work just fine on playground with the newtype: http://is.gd/krOTZv.

    cc @nikomatsakis

  2. Marwes commented on Feb 3, 2015

    @Marwes
    ContributorAuthor

    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.

  3. tamird commented on Apr 22, 2015

    @tamird
    Contributor

    Looks like warnings are now generated for this case, but not consistently[0].

    Should this be a compile-time error instead?

    [0] #20222 (comment)

  4. Marwes commented on Aug 9, 2015

    @Marwes
    ContributorAuthor

    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.

  5. bluss commented on Nov 26, 2015

    @bluss
    Contributor

    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>;
  6. added
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Dec 15, 2015
  7. nikomatsakis commented on Dec 15, 2015

    @nikomatsakis
    Contributor

    Nominating for discussion. Seems like backcompat hazard we should consider trying to address with a feature gate.

  8. bluss commented on Dec 15, 2015

    @bluss
    Contributor

    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(?).

  9. nikomatsakis commented on Dec 17, 2015

    @nikomatsakis
    Contributor

    triage: P-medium

    I think this might be not that hard to fix though!

  10. nixpulvis commented on Feb 9, 2016

    @nixpulvis

    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()));
    }
  11. pnkfelix commented on Feb 9, 2016

    @pnkfelix
    Contributor

    @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. .. ;)

  12. nixpulvis commented on Feb 9, 2016

    @nixpulvis

    @pnkfelix I was really just posting to confirm that I wasn't missing something. The warning sounds a bit scarier than it is in reality. I think this is tangental to #30503, as I do feel having type aliases which aren't check could be useful.

  13. 30 remaining items

  14. cedricschwyter commented on May 19, 2022

    @cedricschwyter

    this would be such a juicy feature, is there any chance this will ever be implemented?

  15. Skallwar commented on Jun 10, 2022

    @Skallwar

    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;
  16. fmease commented on Aug 25, 2023

    @fmease
    Member

    To give an update to the people subscribed to this issue, the (incomplete) feature lazy_type_alias implements the expected semantics for type aliases:

    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 https://github.com/rust-lang/rust/labels/F-lazy_type_alias.

  17. added a commit that references this issue on Sep 8, 2023
  18. added a commit that references this issue on Sep 8, 2023
  19. self-assigned this
    on Dec 28, 2023
  20. added
    T-typesRelevant to the types team, which will review and decide on the PR/issue.
    on Dec 21, 2024
  21. added
    fixed-by-retained-type-aliasesLowering to free alias types (as done by e.g., feature `checked_type_aliases`) fixes this issue.
    on Mar 18, 2026
  22. added 2 commits that reference this issue on Apr 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-trait-systemArea: Trait systemA-type-systemArea: Type systemC-future-incompatibilityCategory: Future-incompatibility lintsE-hardCall for participation: Hard difficulty. Experience needed to fix: A lot.I-needs-decisionIssue: In need of a decision.P-mediumMedium priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.fixed-by-retained-type-aliasesLowering to free alias types (as done by e.g., feature `checked_type_aliases`) fixes this issue.

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions