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

Can't write non-overlapping blanket impls that involve associated type bindings #20400

Open
japaric opened this Issue Jan 1, 2015 · 11 comments

Comments

Projects
None yet
@japaric
Copy link
Member

japaric commented Jan 1, 2015

STR

Example from libcore:

#![crate_type = "lib"]
#![feature(associated_types)]
#![no_implicit_prelude]

trait Iterator {
    type Item;
}

trait AdditiveIterator {
    type Sum;

    fn sum(self) -> Self::Sum;
}

impl<I> AdditiveIterator for I where I: Iterator<Item=u8> {  //~error conflicting implementation
    type Sum = u8;

    fn sum(self) -> u8 { loop {} }
}

impl<I> AdditiveIterator for I where I: Iterator<Item=u16> {  //~note conflicting implementation here
    type Sum = u16;

    fn sum(self) -> u16 { loop {} }
}

Version

7d4f487

No type can implement both Iterator<Item=u8> and Iterator<Item=u16>, therefore these blanket impls are non overlapping and should be accepted.

cc @nikomatsakis

@lfairy

This comment has been minimized.

Copy link
Contributor

lfairy commented Jan 29, 2015

I encountered this bug too, while trying to optimize ToString (#18404):

pub enum Void {}

pub trait Display {
    // ...
    type AsStr = Void;
    fn fmt_as_str(&self) -> &<Self as Display>::AsStr { unimplemented!() }
}

pub trait ToString {
    fn to_string(&self) -> String;
}

impl<T: Display<AsStr=Void> + ?Sized> ToString for T {
    fn to_string(&self) -> String {
        format!("{}", self)
    }
}

impl<T: Display<AsStr=str> + ?Sized> ToString for T {
    fn to_string(&self) -> String {
        String::from_str(self.fmt_as_str())
    }
}

This change could speed up "".to_string() significantly (currently, String::from_str is between 2 and 5 times faster than format!) so I'd love to see this issue fixed.

@edwardw

This comment was marked as resolved.

Copy link
Contributor

edwardw commented Feb 15, 2015

cc me

1 similar comment
@jroesch

This comment was marked as resolved.

Copy link
Member

jroesch commented Feb 18, 2015

cc me

@withoutboats

This comment has been minimized.

Copy link
Contributor

withoutboats commented May 7, 2015

This is really causing problems for a crate I'm working on.

@cristicbz

This comment has been minimized.

Copy link
Contributor

cristicbz commented Oct 16, 2015

Is this bug likely to get any love? I keep hitting this (see #23341) too. I had a look around by I can't really follow how overlapping impls are determined, I would have liked to have a go at it.

@sgrif

This comment has been minimized.

Copy link
Contributor

sgrif commented Jan 18, 2016

Any chance of this getting triaged any time soon? Also feeling pains from this issue.

sgrif added a commit to diesel-rs/diesel that referenced this issue Jan 18, 2016

Remove the ability to have `Nullable<Nullable<T>>` as a type
This is part of a greater effort to clean up some of the messier bits of
our type system. Unfortunately, we still can't implement something both
for null and not null in a non-overlapping way most of the time, as we
still will bump into rust-lang/rust#20400.

Otherwise we could write something like:

```rust
impl<T, ST> Expression for Something<T> where
    T: Expression<SqlType=ST>,
    ST: NotNull,
{
}

impl<T, ST> Expression for Something<T> where
    T: Expression<SqlType=Nullable<ST>>,
    ST: NotNull,
{
}
```

While these clearly do not overlap, rust treats them as overlapping.
Unfortunately this is just one more type that we need to implement for
new SQL types added in the future. I can't just make `IntoNullable`
be a requirement of `NativeSqlType`, as it would require specifying the
nullable case when packing it into a trait object.

`NotNull` can just be replaced with an OIBIT in the future.
@Kixunil

This comment has been minimized.

Copy link

Kixunil commented May 1, 2017

I ran into this problem just now. I wanted to provide and_then() and map() methods for my type that would work if Trait::Type is Option or Result.

@ZerothLaw

This comment has been minimized.

Copy link

ZerothLaw commented Aug 13, 2018

What's needed to advance this issue towards a fix? Are we dependent on Chalk?

@ZerothLaw

This comment has been minimized.

Copy link

ZerothLaw commented Aug 13, 2018

Looks like you can kind of "trick" the compiler by using type specialization. On stable, 2015 edition:

https://play.rust-lang.org/?gist=d803059c64390d7182445bb21756f98c&version=stable&mode=debug&edition=2015

@skade

This comment has been minimized.

Copy link
Contributor

skade commented Dec 25, 2018

I'd like to add myself to the list of people that this causes problems for :).

@dbeckwith

This comment has been minimized.

Copy link

dbeckwith commented Feb 4, 2019

Looks like you can kind of "trick" the compiler by using type specialization. On stable, 2015 edition:

https://play.rust-lang.org/?gist=d803059c64390d7182445bb21756f98c&version=stable&mode=debug&edition=2015

@ZerothLaw could you explain your trick a bit? I think I'm running into this issue and am hoping for a workaround but I'm struggling to understand your example. If you could give some advice on how to apply that to the code in #58171 that would be great.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.