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

Inconsistent type inferring #36285

Closed
therustmonk opened this issue Sep 5, 2016 · 2 comments
Closed

Inconsistent type inferring #36285

therustmonk opened this issue Sep 5, 2016 · 2 comments

Comments

@therustmonk
Copy link
Contributor

I've found the case where type inferring is inconsistent (I think so):

use std::any::Any;
use std::sync::{Arc, Mutex};

pub type Wild = Box<Any + 'static + Send>;

pub fn with_wild(_: Option<Arc<Wild>>) { }

struct Modest;

fn main() {

    // Works
    with_wild(Some(Arc::new(Box::new(Mutex::new(Modest)))));

    // Doesn't work
    let fluffy = Some(Arc::new(Box::new(Mutex::new(Modest))));
    with_wild(fluffy); 

}

at playground

It fails with:

error[E0308]: mismatched types
  --> <anon>:17:15
   |
17 |     with_wild(fluffy);
   |               ^^^^^^ expected trait std::any::Any, found struct `std::sync::Mutex`
   |
   = note: expected type `std::option::Option<std::sync::Arc<Box<std::any::Any + Send + 'static>>>`
   = note:    found type `std::option::Option<std::sync::Arc<Box<std::sync::Mutex<Modest>>>>`

error: aborting due to previous error
@Aatch
Copy link
Contributor

Aatch commented Sep 5, 2016

This isn't really inconsistent. The reason the first one works and the other doesn't is because there's no inference happening in the first case. with_wild takes an Option<Arc<Box<Any + 'static + Send>>>, so when we check the type of Some(Arc::new(Box::new(Mutex::new(Modest)))) we can use the argument type. The type mismatch between Box<Mutex<Modest>> and Box<Any> is handled with a coercion from one to the other. In the second case, we don't have an pre-existing type information to go by, so we just infer the type of fluffy to be Option<Arc<Box<Mutex<Modest>>>.

Coercions aren't part of type inference, they're applied when we encounter a type mismatch, there's not really any inconsistency here. I don't think this behaviour will change, so this should probably be closed. @rust-lang/lang sound good?

@eddyb
Copy link
Member

eddyb commented Sep 5, 2016

@Aatch Indeed, in the first case the type information propagates down through Some and the Arc so the coercion is applied on the Box<_> whereas in the second case, fluffy is already an Option<Arc<Box<Mutex<_>>>> which doesn't coerce to anything.
You could argue that Option<T> should get T's coercions (see also rust-lang/rfcs#1403), but that won't help Arc<Box<_>>, as the Arc's allocation can't be changed after creation.

If you remove the double boxing (which AFAICT is completely redundant), you can work around it:

use std::any::Any;
use std::sync::{Arc, Mutex};

pub type Wild = Any + 'static + Send;

pub fn with_wild(_: Option<Arc<Wild>>) { }

struct Modest;

fn main() {

    // Works
    with_wild(Some(Arc::new(Mutex::new(Modest))));

    let fluffy = Some(Arc::new(Mutex::new(Modest)));
    with_wild(fluffy.map(|x| x as Arc<Wild>));

}

You can also do the manual case on the original fluffy line. I was hoping .map would coerce with just |x| x, but that doesn't work with methods, only free functions.

@eddyb eddyb closed this as completed Sep 5, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants