Thanks again to Open Source Security, inc and Embecosm for their ongoing support for this project.
Array Capacity and constant folding
This week fixed several bugs in the compiler one of the big issues was constant expressions. In rust array capacities must be constant’s the default implementation simply just expected a LiteralExpression but this is not correct. Consider the example below:
let a:[_; 1+1+1] = [1,2,3];
This is a toy example but demonstrates that rust should be able to fold the capacity expression of (1+1+1). Constant folding is a complex piece of work to get right and respect all mathematical rules, but GCC already does this for us in gcc/fold-const.c so this PR-383 takes advantage of this.
const TEST:usize = 2;
let a:[_; TEST+1] = [1,2,3];
GCC also takes into account the fact that the name TEST is a const item such that it can then fold this example again into 3. However, there are limitations to constant folding in Rust consider this example:
let size = 2;
let a:[_; size+1] = [1,2,3];
Although it would indeed be possible for GCC to constant fold this into 3, rust disallows this and return:
error[E0435]: attempt to use a non-constant value in a constant
For more information about this error, try `rustc --explain E0435`.
When we have a variable reference in a constant expression it is not always possible to fold its values since it will depend on constant propagation as well as constant folding. Even when it references immutable values the initializer expression may not be constant so it won’t always be possible to determine the value at compile time.
Block Expressions and Never Type
New contributor lrh2000 proposed introducing the rust never type to make the compiler more in line with Rustc. This change breaks down into several building blocks in rust you can write:
fn test() -> i32 {
let a:u32 = 123;
let b:i32 = 456;
a;
b
}
Here the compiler needs to track the usage of the semi colon to track which is the final expression of the block, you can see this comment for more info on how rustc handles this.
This is where things start to get a little more complex consider this example:
fn test() -> i32 {
let a = return 123;
456
}
In this example, you can see those return expressions are valid expressions in rust. The old implementation in the compiler inferred return expressions as either unit or the type of the return expression. Rustc actually makes this a never type as it is a change in control flow. The old implementation also stripped unreachable code as a way to enforce the typing rules for cases such as:
fn test() -> i32 {
if x > 1 {
return 5;
} else {
return 0;
}
return 1;
}
When you have a block that is not the final expression in the block the type resolver needs to enforce the IfExpr resolves to unit type. Since the compiler used to type resolve the return expressions here into i32 instead of NeverType it meant that the rules were not correct. This is now fixed which his recent PRs.
Testsuite
As part of onboarding potential google summer of code students, we have been encouraging them to write test cases for the compiler. This has three benefits here:
- Learning to compile and invoke the compiler
- Understanding the state of the compiler as it stands
- The project gets free test cases
Arthur proposed xfail testcases but it was found that the compiler at the time was crashing on these at that point. It seems reasonable that XFAIL testsuite should be able to support cases which ICE such that when crashes are fixed we should see a change in the testsuite and update the relevant testcases appropriately. Thanks to Marc this is now available though the dg-ice annotation.
Milestone Progress
In rust when you specify a TypePath that needs substitution the compiler needs to error correctly (rustc –explain E0107), untill PR-381 this used to cause a crash.
struct Foo<A>(A);
fn main() {
let a: Foo = Foo::<i32>(123);
// { dg-error "Invalid number of generic arguments to generic type" "" { target { *-*-* } } .-1 }
}
This also extends over to cases such as:
struct Foo<A>(A);
impl Foo {
// { dg-error "Invalid number of generic arguments to generic type" "" { target { *-*-* } } .-1 }
fn test() -> i32 {
123
}
}
The reason this is important is that it is a building block for my work into defaults on Type Parameters since the following is valid rust code:
struct Foo<A=f32>(A);
impl Foo {
fn test() -> i32 {
123
}
}
Completed Activities
- Track Semicolon in block expressions like rustc – PR-380
- Fix crash when TypePath requiring generic substitution did not receive any generic arguments – PR-381
- Use GCC fold-const.c to enforce const expressions on array capacity – PR-383
- Add support to test suite to test for ICE to allow adding test cases which crash – PR-384
- Undo block expression work which removed unreachable code in HIR lowering – PR-387 PR-390
- Assign outer attributes in the AST as part of the IfLetExpr node constructor – PR-388
Overall Task Status
Category | Last Week | This Week | Delta |
TODO | 62 | 63 | +1 |
In Progress | 8 | 8 | – |
Completed | 118 | 121 | +3 |
Test Cases
Category | Last Week | This Week | Delta |
Passing | 1921 | 2092 | +171 |
XFAIL | 36 | 36 | – |
Failed | 0 | 0 | – |
XPASS | 0 | 0 | – |
Bugs
Category | Last Week | This Week | Delta |
TODO | 12 | 11 | -1 |
In Progress | 4 | 3 | -1 |
Completed | 31 | 33 | +2 |
Milestones Progress
Milestone | Last Week | This Week | Delta | Start Date | Completion Date | Target |
Data Structures 1 – Core | 100% | 100% | – | 30th Nov 2020 | 27th Jan 2021 | 29th Jan 2021 |
Control Flow 1 – Core | 100% | 100% | – | 28th Jan 2021 | 10th Feb 2021 | 26th Feb 2021 |
Data Structures 2 – Generics | 79% | 84% | +5% | 11th Feb 2021 | – | 28th May 2021 |
Data Structures 3 – Traits | 0% | 0% | – | – | – | 27th Aug 2021 |
Control Flow 2 – Pattern Matching | 0% | 0% | – | – | – | 29th Oct 2021 |
Imports and Visibility | 0% | 0% | – | – | – | TBD |
Risks
Risk | Impact (1-3) | Likelihood (0-10) | Risk (I*L) | Mitigation |
Copyright assignments | 2 | 5 | 10 | Be up front on all PRs that the code is destined to be upstreamed to FSF |
Rust Language Changes | 3 | 7 | 21 | Keep up to date with the Rust language on a regular basis |
Planned Activities
- Complete work on partial substitutions
- Complete work on default type parameters