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

Specialization influnces inference #36262

Open
arielb1 opened this issue Sep 4, 2016 · 3 comments
Open

Specialization influnces inference #36262

arielb1 opened this issue Sep 4, 2016 · 3 comments
Labels
A-inference Area: Type inference A-specialization Area: Trait impl specialization A-trait-system Area: Trait system C-bug Category: This is a bug. F-specialization `#![feature(specialization)]` requires-nightly This issue requires a nightly compiler in some way. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@arielb1
Copy link
Contributor

arielb1 commented Sep 4, 2016

STR

#![feature(specialization)]

struct My<T>(T);

trait Conv<T> {
    fn conv(self) -> T;
}

impl<T> Conv<T> for My<T> {
    default fn conv(self) -> T { self.0 }
}

#[cfg(broken)]
impl Conv<u32> for My<u32> {
    default fn conv(self) -> u32 { self.0 }
}

fn main() {
    let x = My(0);
    x.conv() + 0i32;
}

Expected Result

Adding a specialized impl will not affect type inference.

Actual Result

After adding the specialized impl, inference is guided to take it:

error[E0308]: mismatched types
  --> <anon>:20:16
   |
20 |     x.conv() + 0i32;
   |                ^^^^ expected u32, found i32

error[E0277]: the trait bound `u32: std::ops::Add<i32>` is not satisfied
  --> <anon>:20:5
   |
20 |     x.conv() + 0i32;
   |     ^^^^^^^^^^^^^^^ trait `u32: std::ops::Add<i32>` not satisfied
   |
   = help: the following implementations were found:
   = help:   <u32 as std::ops::Add>
   = help:   <&'a u32 as std::ops::Add<u32>>
   = help:   <u32 as std::ops::Add<&'a u32>>
   = help:   <&'b u32 as std::ops::Add<&'a u32>>

error: aborting due to 2 previous errors

cc @aturon @nikomatsakis

@Mark-Simulacrum
Copy link
Member

Another example:

#![feature(specialization)]
use std::marker::PhantomData;

trait Trait {
    type A;
    type B;

    fn foo(&self, a: Self::A, b: Self::B);
}

struct Foo<A, B> {
    a: PhantomData<A>,
    b: PhantomData<B>,
}

impl<A, B> Foo<A, B> {
    fn new() -> Self {
        Foo {
            a: PhantomData,
            b: PhantomData,
        }
    }
}

impl<A, B> Trait for Foo<A, B> {
    type A = A;
    type B = B;
    default fn foo(&self, _: A, _: B) {
        println!("default impl");
    }
}

// Specialized
impl<A, B: Eq> Trait for Foo<A, B> {
    fn foo(&self, _: A, _: B) {
        println!("specialized");
    }
}

fn main() {
    let a = "a";
    let b = "b";

    let f = Foo::new(); // Need to specify concrete type here to compile
    f.foo(a, b);
}

@Mark-Simulacrum Mark-Simulacrum added the C-bug Category: This is a bug. label Jul 26, 2017
@oberien
Copy link
Contributor

oberien commented Dec 20, 2017

I don't have an sscce, but I produced this small patch for the current master branch of rust, which breaks type inference regarding specialization of iterators.
The interesting thing is, if I don't directly specialize the iterator, but instead create a new trait which I specialize, it compiles just fine. The patch for this can be found here.

@Emerentius
Copy link
Contributor

Emerentius commented May 12, 2018

I have a patch specializing SliceConcatExt<T> for T: Copy which causes type inference to fail on a call to concat inside rustc. It happens even if I don't actually specialize anything. If I delete the empty impl block and leave the general impl block as-is, including the defaults, it works. Just the existence of the specializing impl block is enough to break it.

Edit: I've misinterpreted the issue. Explanation at the end

// general block
impl<T: Clone, V: Borrow<[T]>> SliceConcatExt<T> for [V] {
    type Output = Vec<T>;
    default fn concat(&self) -> Vec<T> { ... }
    /* other methods */
}

// specializing block
impl<T: Copy, V: Borrow<[T]>> SliceConcatExt<T> for [V] {
    /* empty */
}

The call where inference breaks is src/librustc_typeck/collect.rs Line 1299

The error is:

type annotations required: cannot resolve `<[&[rustc::ty::Predicate<'_>]] as std::slice::SliceConcatExt<_>>::Output == std::vec::Vec<rustc::ty::Predicate<'_>>`

Previously only one impl of SliceConcatExt<T> could produce a Vec<_>. With the specialization it's two, but one is a subset of the other.

Edit:
Actually, the issue has not to do with the associated type but with the generic T. concat has no information about T. join has a T separator parameter and does not have the inference problem but concat could work for any T for which V: Borrow<[T]>.
That genericity might require one to add a turbofish but in that case above in the stdlib, it was not necessary. The specialization should not change that.

@jonas-schievink jonas-schievink added F-specialization `#![feature(specialization)]` requires-nightly This issue requires a nightly compiler in some way. labels Aug 29, 2019
@jonas-schievink jonas-schievink added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. A-inference Area: Type inference labels May 9, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-inference Area: Type inference A-specialization Area: Trait impl specialization A-trait-system Area: Trait system C-bug Category: This is a bug. F-specialization `#![feature(specialization)]` requires-nightly This issue requires a nightly compiler in some way. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

5 participants