Program compiles even though a type cannot be inferred
The code below compiles, even though the type of the elements of the Vec is unknown.
use std::mem;
use std::os::raw::c_void;
#[no_mangle]
pub extern "C" fn alloc(size: usize) -> *mut c_void {
let mut buf = Vec::with_capacity(size);
let ptr = buf.as_mut_ptr();
mem::forget(buf);
return ptr as *mut c_void;
}
fn main() { }
Somehow, Rust is picking a type and compiling anyway. It is unclear to me which type that may be and whether this behavior is specified somewhere. The type could be anything, from () to String or something else. You can test this by adding a type annotation to the declaration of buf. The code compiles regardless of the type you choose.
Originally reported in https://github.com/badboy/hellorust/issues/4
Adolfo Ochagavía at 2017-11-29 07:55:25
I suppose when the compiler sees the expression
x as A, it first tries to unifytypeof(x)withA, and try coercion if the first unification fails.Therefore, my expectation is:
- If the element type is not specified, the unification succeeds and the element type is
c_void. - If the element type is specified, the unification fails and the
asexpression is assumed to do coercion.
I have two collateral evidences: first, if I specify only part of the element type:
use std::mem; use std::os::raw::c_void; #[no_mangle] pub extern "C" fn alloc(size: usize) -> *mut c_void { let mut buf = Vec::<(_, _)>::with_capacity(size); let ptr = buf.as_mut_ptr(); mem::forget(buf); ptr as *mut c_void } fn main() { }then they claim type annotations needed. This can be explained as a result of unification failure at the
asexpression.Second, if I try to print the result of
allocand insert anotherasexpression beforeptr as *mut c_void:use std::mem; use std::os::raw::c_void; #[no_mangle] pub extern "C" fn alloc(size: usize) -> *mut c_void { let mut buf = Vec::<_>::with_capacity(size); let ptr = buf.as_mut_ptr(); mem::forget(buf); // ptr as *mut (); // uncomment here ptr as *mut c_void } fn main() { println!("{:p}", alloc(10)); }Then it changes the behavior. When I put
ptr as *mut ()beforeptr as *mut c_void, it prints0x1. That means the element type became(). Note that Rust changes allocation behavior on zero-sized types.So my suggestion is in your case, the element type is
c_void.Masaki Hara at 2017-11-29 08:24:13
- If the element type is not specified, the unification succeeds and the element type is
Thanks for your reply, @qnighy. I just wanted to point out that specifying a different type does work (in your case, I guess using a tuple caused the error). For an example see this code:
pub extern "C" fn alloc(size: usize) -> *mut c_void { let mut buf = Vec::<()>::with_capacity(size); let ptr = buf.as_mut_ptr(); mem::forget(buf); return ptr as *mut c_void; }Adolfo Ochagavía at 2017-11-29 14:58:32
What I meant was: the compiler does different things when the element type is specified and when it's not specified. This is because the type inference algorithm behaves ad-hoc in the place where coercion involves.
in your case, I guess using a tuple caused the error
No, the inference fails anytime when there is a hole in the element type.
(_, _)fails.(u8, _)fails.(u32, u32)succeeds.Vec<_>fails.Box<_>fails.Box<str>succeeds. The only exception is when the whole element type is left blank. In this case, unification toc_void(which succeeds) fills in the hole.In short, there are only two cases the inference succeeds (if I understand correctly):
- When the element type is fully specified. In this case,
as *mut c_voidis interpreted as a coercion, as the unification of*mut <element type>and*mut c_voidfails. - When the whole element type is left blank. In this case,
as *mut c_voidis interpreted as an identity cast, as the unification of*mut <element type>and*mut c_voidsucceeds. Therefore the element type is inferred asc_void.
I still don't know whether this ad-hoc inference behavior is considered stable or not.
Masaki Hara at 2017-11-30 07:59:06
- When the element type is fully specified. In this case,
Triage: this still compiles.
Steve Klabnik at 2020-07-20 11:45:03