The biggest problem Rust has is that "no_core" is so poorly understood at this point that i doubt a comprehensive spec is even possible to explain:
1. Type inference taking into account higher ranked trait bounds
- Slices in libcore work via the Index lang item so its like taking an index operator overload to a range lang item but the generic types in the range need to be unified with the higher ranked trait bound to eventually figure out that they are meant to be of usize.
2. Method resolution its almost a joke at this point how complicated it is in Rust.
- The autoderef cycle sounds simple when you read this: https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/deref-coercions.html
- But this misses so much extra context information
Some day I personally want to write a blog post about how complicated and under spec'd Rust is, then write one about the stuff i do like it such as iterators being part of libcore so i don't need reactive extensions.
No core _is_ the Rust language, libcore is just a library which adds the "Rust abstractions" so you can actually write a for loop or create a slice or deref, add or anything else.
Libcore just gets compiled like any other rust crate just it does not have access to abstractions.
For example, you can still write C code without libc because C is a language libc is just a library libcore is pretty much the same. Though Rust makes alot of assumptions that libcore _should_ be there but its possible for it not to be.
> For example, you can still write C code without libc because C is a language libc is just a library libcore is pretty much the same. Though Rust makes alot of assumptions that libcore _should_ be there but its possible for it not to be.
The same core/std distinction exists in C. The headers float.h, iso646.h, limits.h, stdalign.h, stdarg.h, stdbit.h, stdbool.h, stddef.h, stdint.h, stdnoreturn.h, and parts of string.h, stdlib.h, fenv.h, and math.h are required to be supported in freestanding mode.
And, frankly, just about every language has this kind of core library/standard library distinction; at some point, parts of the compiler implementation of the language need to work with the library implementation details, and vice versa. Languages like Rust and C are somewhat unusual in actually identifying a subset of the standard library that is usable without a complete implementation of the standard library.
core is part of the language (or at least, many parts of it are).
The way that rustc currently splits this up is an implementation detail of rustc, not something that must be copied exactly. Rust without core is not Rust. It's not even usable.
You need to provide the langitems, it's true that core has a lot more than just the langitems, but the langitems are a lot and as somebody pointed to me on HN recently, they chase through into related stuff.
I was like, Option isn't special but, well, you do need to provide Some and None, and those are clearly two halves of an enum, so - that's Option is what that is.
You need Try, and unless you're going to write Try yourself to have some other behaviour that means you're writing ControlFlow and Result as well as Option.
I think that the work needed to make Ipv4Addr::is_documentation - a predicate which tells you whether the IPv4 Address you've got is, in fact, one reserved for documentation by the IETF RFC 5737 - is tiny compared to the struggle to get u32::is_power_of_two - a predicate which tells you if a 32-bit integer is a power of two - and so even though doubtless Rust doesn't care whether the former part of the core library works you might just as well.
Sure, it's literally self.count_ones() == 1 -- so we just implement count_ones() and ah, well, we could do all this by hand but turns out (fill in name of CPU) has a CPU instruction specifically for this. Rust calls the intrinsic we're about to go write intrinsics::ctpop()
Now we're writing per-ISA intrinsics, what was our goal again? Maybe I was too oblique, this stuff is all rabbit holes is what I was getting at. We're lucky these people even re-surface periodically with work and a blog post.
This is true, I tried to make gccrs only have the AST and go from that stright to GCC GENERIC. This had a lot of problems for Rust in my opinion.
Many things in Rust are syntactic sugar and can be handled by desugaring the AST into another IR so you dont even have to think about it in other passes. The main issue for me is how complicate the type inference is.
So if i wanted to use GCC GENERIC for type resolution for this example:
```
let a;
a = 123;
let b:u32 = 1;
a += b;
```
How do you resolve the type of 'a' you must use inference variables and then update the TREE_TYPE as you go so this means walking the tree's over and over again as type information is gathered over time on the inference variable. Using a separate IR and using id's and side tables makes all of this much much more simple for Rust.
Its pretty sensible to have other IR's, we have many passes in gccrs simplifying things so the graph of what your working with is simpler and simpler each time.
I mean in GCC for C++ for example they use GENERIC and add a bunch of custom tree-codes such as LAMBDA_EXPR or TEMPLATE stuff for example then they keep substituting etc and finally as part of handing off to GCC middle-end it triggers the gimplification of all of these custom tree codes. So even the C++ front-end you could argue has two IR's.
I'm personally pretty excited to see where this goes. It could be the best way for gccrs to version itself. There are some immediate aspects I am pretty interested in relation to the spec:
1. Method resolution
2. Unstable?
In particular is it going to define lang items?
3. DST's
Rust has strange things like:
```
let a:&str = "str";
let b:&str = &"str";
```
Which is valid since str is a DST. Although slices and dyn trait are DST they have more strict rules there.
I would love to do a crater run, it could be be pretty exciting since we have our cargo gccrs layer. I think once we get libcore working, we could look at no_std crates :)
This is great news! Congratulations on the progress. I wish I had the time to jump in and contribute as I believe this project will provide a lot of value in the future.
It is indeed early to say, but the design of the compiler pipeline is very different to rustc, it is a more traditional pass based system with plenty of side table lookups. Some of the notions are similar we are using HIR but we are not using MIR, GCC's generic IR is very similar.
So we have
AST->HIR->GCC-Generic->GCC
where as rustc is:
AST->HIR->THIR->MIR->LLVM-IR->LLVM
The rust compiler used to be pass based too, but then became on-demand as that architecture is more amenable for incremental compilation. In that time the performance has improved, although I'm not sure how much this architectural change was responsible for it, I think it were mostly unrelated changes.
There are a variety of static checks that Rust performs in order to ensure memory safety. rustc might perform these checks at various parts of the pipeline, but it might be possible for a different compiler to perform these checks at other points depending on what information its chosen IRs encode (for example, borrow checking requires a control-flow graph, which only exists at the MIR stage in rustc).
1. Type inference taking into account higher ranked trait bounds
2. Method resolution its almost a joke at this point how complicated it is in Rust. 3. Macro invocations there are really subtle rules on how you treat macro invocations such as this which is not documented at all https://github.com/Rust-GCC/gccrs/blob/master/gcc/rust/expan...</rant>
Some day I personally want to write a blog post about how complicated and under spec'd Rust is, then write one about the stuff i do like it such as iterators being part of libcore so i don't need reactive extensions.