What types are handled in Rust in a magic way by the compiler?
I am working on a programming language, and working on the lowest-level types (the "primitive" types), like Int8, Float32, and contiguous arrays and bits. I have decided to essentially define the usage interface to these types, but not define their inner structure or implementation like you would higher-level types. Instead, the compiler is going to read these specific files, and know their type definitions are treated in a special way (i.e., they are implemented in a magic way, without defining it in the higher level language). This is necessary, as you have to end somewhere where the rubber meets the roads, and for this it's the primitive types.
In doing so, I am looking at Rust for inspiration on what types they chose and and how they work / how they are implemented. Some of the "primitive" or more base types seem to be handled in a magic way as far as I can tell so far (in Rust).
As far as I can tell, these are the primitive types:
never: The ! type, also called “never”.array: A fixed-size array, denoted[T; N], for the element type, T, and the non-negative compile-time constant size, N.bool: The boolean type.char: A character type.f32: A 32-bit floating point typef64: A 64-bit floating point typefn: Function pointers, likefn(usize) -> bool.i8: The 8-bit signed integer type.i16: The 16-bit signed integer type.i32: The 32-bit signed integer type.i64: The 64-bit signed integer type.i128: The 128-bit signed integer type.isize: The pointer-sized signed integer type.pointer: Raw, unsafe pointers,*const T, and *mut T.reference: References, both shared and mutable.slice: A dynamically-sized view into a contiguous sequence, [T].str: String slices.tuple: A finite heterogeneous sequence,(T, U, ..).u8: The 8-bit unsigned integer type.u16: The 16-bit unsigned integer type.u32: The 32-bit unsigned integer type.u64: The 64-bit unsigned integer type.u128: The 128-bit unsigned integer type.unit: The()type, also called “unit”.usize: The pointer-sized unsigned integer type.
Most of those I understand, except never, pointer, and reference. But not too worried about those for this post. I haven't found anywhere in the rust codebase where these were defined, so there is probably some magic going on under the hood for them somewhere there. But you don't see enum i32 or type i32 or struct i32 anywhere in the code, for example.
And even though not listed, it appears the vec! vector, and array, are also primitive types, though not sure.
But then there are other ones which appear to be handled specially by the compiler:
- Box
- Rc
- Cell
- RefCell
- Arc (Atomically Reference-Counted pointer)
- Weak
- Vec
That is, the compiler seems to do some magic on these types which are not defined in the type/struct definitions themselves, as far as I can tell. Please correct me if I'm wrong.
These last ones are actually defined in the codebase. Like Box:
pub struct Box<T: ?Sized, A: Allocator = Global>(Unique<T>, A);
Or Arc:
pub struct Arc<T: ?Sized> {
ptr: NonNull<ArcInner<T>>,
phantom: PhantomData<ArcInner<T>>,
}
There's probably a lot of hidden inner types too that are not defined and are magic, like I'm guessing Sized and when they do -Inner in the name.
The question is, is the compiler handling some of these "more special" types in a custom way? That is, even though Box is defined in the source code, it doesn't say anything about being heap allocated in the type definition (although maybe it does, maybe that's what the Allocator is?).
I don't know enough of Rust or the codebase yet to determine what types they treat in a magic way which is not defined in the higher level definitions directly. It would be helpful to know when designing a programming language, so it's clear how much you need to do in a magic way. So basically to summarize, what types are handled in a magic way in Rust and what aren't?