Skip to content

3-tuple gets inferred to internal test runner types with --test if certain type is marked Send #21080

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

Closed
huonw opened this issue Jan 13, 2015 · 12 comments · Fixed by #21167
Closed
Assignees
Labels
A-type-system Area: Type system

Comments

@huonw
Copy link
Member

huonw commented Jan 13, 2015

// wtf-testrunner.rs

#![allow(unstable)]

pub fn join<J: ToJoin<T>, T: Send /* WTF */>(_: J) -> Future<T> {
    unimplemented!()
}
pub trait ToJoin<T> {}

impl<A1, T1, A2, T2> ToJoin<(T1, T2)> for (A1, A2) {}

impl<A1, T1, A2, T2, A3, T3> ToJoin<(T1, T2, T3)> for (A1, A2, A3) {}
impl<A1, T1, A2, T2, A3, T3, A4, T4> ToJoin<(T1, T2, T3, T4)> for (A1, A2, A3, A4) {}

pub struct Future<T>;

pub fn all_ok() {
    let f1 = Future::<i32>;
    let f2 = Future::<i32>;

    let _: Future<(i32, i32)> = join((f1, f2));
}
pub fn also_ok() {
    let f1 = Future::<i32>;
    let f2 = Future::<i32>;
    let f3 = Future::<i32>;
    let f4 = Future::<i32>;

    let _: Future<(i32, i32, i32, i32)> = join((f1, f2, f3, f4));
}

pub fn wtf() {
    let f1 = Future::<i32>;
    let f2 = Future::<i32>;
    let f3 = Future::<i32>;

    let _: Future<(i32, i32, i32)> = join((f1, f2, f3));
}

fn main() {}

Compiling with rustc wtf-testrunner.rs works fine, rustc --test wtf-testrunner.rs definitely does not, though:

wtf-testrunner.rs:35:38: 35:56 error: mismatched types: expected `Future<(i32, i32, i32)>`, found `Future<(test::TestDesc, test::TestResult, collections::vec::Vec<u8>)>` (expected i32, found struct test::TestDesc)
wtf-testrunner.rs:35     let _: Future<(i32, i32, i32)> = join((f1, f2, f3));
                                                          ^~~~~~~~~~~~~~~~~~
error: aborting due to previous error

And, if the Send bound in join is removed, the code compiles fine with or without --test.

So... somehow the test runner is causing a tuple of arity 3 specifically to be inferred to something completely ridiculous.

@huonw
Copy link
Member Author

huonw commented Jan 13, 2015

cc @nikomatsakis, I guess?

@huonw
Copy link
Member Author

huonw commented Jan 13, 2015

@klutzy points out that specifically having extern crate test; causes the problem.

@jdm
Copy link
Contributor

jdm commented Jan 13, 2015

cc me

@wycats
Copy link
Contributor

wycats commented Jan 13, 2015

FYI: @carllerche discovered this problem while working on https://github.com/carllerche/syncbox

@alexcrichton
Copy link
Member

Slightly more minimized:

extern crate test;                                                      

struct Future<T>;                                                       

fn join<J: ToJoin<T>, T: Send>(_: J) -> Future<T> { }                   

trait ToJoin<T> { }                                                     
impl <A1, T1, A2, T2, A3, T3> ToJoin<(T1, T2, T3)> for (A1, A2, A3) { } 

fn main() {                                                             
    let _: Future<(i32, i32, i32)> = join((0, 0, 0));                   
}                                                                       
$ rustc --crate-type lib wut.rs  
wut.rs:11:38: 11:53 error: mismatched types: expected `Future<(i32, i32, i32)>`, found `Future<(test::TestDesc, test::TestResult, collections::vec::Vec<u8>)>` (expected i32, found struct test::TestDesc)
wut.rs:11     let _: Future<(i32, i32, i32)> = join((0, 0, 0));
                                               ^~~~~~~~~~~~~~~
error: aborting due to previous error

@klutzy
Copy link
Contributor

klutzy commented Jan 13, 2015

libtest/lib.rs contains:

pub type MonitorMsg = (TestDesc, TestResult, Vec<u8> );

unsafe impl Send for MonitorMsg {}

This causes the problem.

@klutzy
Copy link
Contributor

klutzy commented Jan 13, 2015

struct MyStruct;
// this will cause issue for 2-tuple
unsafe impl Send for (MyStruct, MyStruct) {}

// error: mismatched types: expected `Future<(i32, i32)>`, found `Future<(MyStruct, MyStruct)>`
let _: Future<(i32, i32)> = join((f1, f2));
// no error
let _: Future<(i32, i32)> = join::<(Future<i32>, Future<i32>), (i32, i32)>((f1, f2));

// uncommenting the two lines resolves the error.
// struct MyStruct2;
// unsafe impl Send for (MyStruct2, MyStruct2) {}

@nikomatsakis
Copy link
Contributor

I'll take a look at it.

@nikomatsakis
Copy link
Contributor

Oh, I see @klutzy you tracked it down -- I thought it might be something like that. This is in fact something I was talking to @flaper87 about as a possible danger of the way we're treating builtin bounds right now, though in a different context.

@nikomatsakis
Copy link
Contributor

In fact, I think that the unsafe impl Send for a tuple ought to be a coherence violation to begin with, actually.

@nikomatsakis
Copy link
Contributor

(I think there was language about specifically this in the OIBIT RFC)

@flaper87 flaper87 self-assigned this Jan 13, 2015
@flaper87 flaper87 added the A-type-system Area: Type system label Jan 13, 2015
@flaper87
Copy link
Contributor

I agree with @nikomatsakis comments here and after a quick chat on IRC with him, we agreed that implementations of built-in traits (and likely default trait impls in the future) should be allowed just on struct and enums.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-type-system Area: Type system
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants