fix stack overflow by enum and cont issue #36163
some paths were skipped while checking for recursion.
I fixed bug reproduces on win64 cargo test. In previous PR #36458 time complexity was exponential in case of linked const values. Now it's linear.
r? @alexcrichton
Adds `-Z mir-stats`, which is similar to `-Z hir-stats`.
Adds `-Z mir-stats`, which is similar to `-Z hir-stats`.
Some notes:
* This code attempts to present the breakdown of each variant for
every enum in the MIR. This is meant to guide decisions about how to
revise representations e.g. when to box payloads for rare variants
to shrink the size of the enum overall.
* I left out the "Total:" line that hir-stats presents, because this
implementation uses the MIR Visitor infrastructure, and the memory
usage of structures directly embedded in other structures (e.g. the
`func: Operand` in a `TerminatorKind:Call`) is not distinguished
from similar structures allocated in a `Vec` (e.g. the `args:
Vec<Operand>` in a `TerminatorKind::Call`). This means that a naive
summation of all the accumulated sizes is misleading, because it
will double-count the contribution of the `Operand` of the `func` as
well as the size of the whole `TerminatorKind`.
* I did consider abandoning the MIR Visitor and instead hand-coding
a traversal that distinguished embedded storage from indirect
storage. But such code would be fragile; better to just require
people to take care when interpreting the presented results.
* This traverses the `mir.promoted` rvalues to capture stats for MIR
stored there, even though the MIR visitor super_mir method does not
do so. (I did not observe any promoted mir being newly traversed when
compiling the rustc crate, however.)
* It might be nice to try to unify this code with hir-stats. Then
again, the reporting portion is the only common code (I think), and
it is small compared to the visitors in hir-stats and mir-stats.
Some notes:
* This code attempts to present the breakdown of each variant for
every enum in the MIR. This is meant to guide decisions about how to
revise representations e.g. when to box payloads for rare variants
to shrink the size of the enum overall.
* I left out the "Total:" line that hir-stats presents, because this
implementation uses the MIR Visitor infrastructure, and the memory
usage of structures directly embedded in other structures (e.g. the
`func: Operand` in a `TerminatorKind:Call`) is not distinguished
from similar structures allocated in a `Vec` (e.g. the `args:
Vec<Operand>` in a `TerminatorKind::Call`). This means that a naive
summation of all the accumulated sizes is misleading, because it
will double-count the contribution of the `Operand` of the `func` as
well as the size of the whole `TerminatorKind`.
* I did consider abandoning the MIR Visitor and instead hand-coding
a traversal that distinguished embedded storage from indirect
storage. But such code would be fragile; better to just require
people to take care when interpreting the presented results.
* This traverses the `mir.promoted` rvalues to capture stats for MIR
stored there, even though the MIR visitor super_mir method does not
do so. (I did not observe any new mir being traversed when compiling
the rustc crate, however.)
* It might be nice to try to unify this code with hir-stats. Then
again, the reporting portion is the only common code (I think), and
it is small compared to the visitors in hir-stats and mir-stats.
They don't implement FnLikeNode anymore, instead are handled differently
further up in the call tree. Also, keep less information (just def ids
for the args).
Support `?Sized` in where clauses
Implemented as described in https://github.com/rust-lang/rust/issues/20503#issuecomment-258677026 - `?Trait` bounds are moved on type parameter definitions when possible, reported as errors otherwise.
(It'd be nice to unify bounds and where clauses in HIR, but this is mostly blocked by rustdoc now - it needs to render bounds in pleasant way and the best way to do it so far is to mirror what was written in source code.)
Fixes https://github.com/rust-lang/rust/issues/20503
r? @nikomatsakis
Implement the `loop_break_value` feature.
This implements RFC 1624, tracking issue #37339.
- `FnCtxt` (in typeck) gets a stack of `LoopCtxt`s, which store the
currently deduced type of that loop, the desired type, and a list of
break expressions currently seen. `loop` loops get a fresh type
variable as their initial type (this logic is stolen from that for
arrays). `while` loops get `()`.
- `break {expr}` looks up the broken loop, and unifies the type of
`expr` with the type of the loop.
- `break` with no expr unifies the loop's type with `()`.
- When building MIR, loops no longer construct a `()` value at
termination of the loop; rather, the `break` expression assigns the
result of the loop.
- ~~I have also changed the loop scoping in MIR-building so that the test
of a while loop is not considered to be part of that loop. This makes
the rules consistent with #37360. The new loop scopes in typeck also
follow this rule. That means that `loop { while (break) {} }` now
terminates instead of looping forever. This is technically a breaking
change.~~
- ~~On that note, expressions like `while break {}` and `if break {}` no
longer parse because `{}` is interpreted as an expression argument to
`break`. But no code except compiler test cases should do that anyway
because it makes no sense.~~
- The RFC did not make it clear, but I chose to make `break ()` inside
of a `while` loop illegal, just in case we wanted to do anything with
that design space in the future.
This is my first time dealing with this part of rustc so I'm sure
there's plenty of problems to pick on here ^_^
This implements RFC 1624, tracking issue #37339.
- `FnCtxt` (in typeck) gets a stack of `LoopCtxt`s, which store the
currently deduced type of that loop, the desired type, and a list of
break expressions currently seen. `loop` loops get a fresh type
variable as their initial type (this logic is stolen from that for
arrays). `while` loops get `()`.
- `break {expr}` looks up the broken loop, and unifies the type of
`expr` with the type of the loop.
- `break` with no expr unifies the loop's type with `()`.
- When building MIR, `loop` loops no longer construct a `()` value at
termination of the loop; rather, the `break` expression assigns the
result of the loop. `while` loops are unchanged.
- `break` respects contexts in which expressions may not end with braced
blocks. That is, `while break { break-value } { while-body }` is
illegal; this preserves backwards compatibility.
- The RFC did not make it clear, but I chose to make `break ()` inside
of a `while` loop illegal, just in case we wanted to do anything with
that design space in the future.
This is my first time dealing with this part of rustc so I'm sure
there's plenty of problems to pick on here ^_^
This allows you to enable *all* nested visits in a future-compatible
sort of way. Moreover, if you choose to override the `visit_nested`
methods yourself, you can "future-proof" against omissions by overriding
`nested_visit_map` to panic.
[6/n] rustc: transition HIR function bodies from Block to Expr.
_This is part of a series ([prev](https://github.com/rust-lang/rust/pull/37408) | [next](https://github.com/rust-lang/rust/pull/37676)) of patches designed to rework rustc into an out-of-order on-demand pipeline model for both better feature support (e.g. [MIR-based](https://github.com/solson/miri) early constant evaluation) and incremental execution of compiler passes (e.g. type-checking), with beneficial consequences to IDE support as well.
If any motivation is unclear, please ask for additional PR description clarifications or code comments._
<hr>
The main change here is that functions and closures both use `Expr` instead of `Block` for their bodies.
For closures this actually allows a honest representation of brace-less closure bodies, e.g. `|x| x + 1` is now distinguishable from `|x| { x + 1 }`, therefore this PR is `[syntax-breaking]` (cc @Manishearth).
Using `Expr` allows more logic to be shared between constant bodies and function bodies, with some small such changes already part of this PR, and eventually easing #35078 and per-body type tables.
Incidentally, there used to be some corners cut here and there and as such I had to (re)write divergence tracking for type-checking so that it is capable of understanding basic structured control-flow:
``` rust
fn a(x: bool) -> i32 {
// match also works (as long as all arms diverge)
if x { panic!("true") } else { return 1; }
0 // "unreachable expression" after this PR
}
```
And since liveness' "not all control paths return a value" moved to type-checking we can have nice things:
``` rust
// before & after:
fn b() -> i32 { 0; } // help: consider removing this semicolon
// only after this PR
fn c() -> i32 { { 0; } } // help: consider removing this semicolon
fn d() { let x: i32 = { 0; }; } // help: consider removing this semicolon
fn e() { f({ 0; }); } // help: consider removing this semicolon
```
Replace FNV with a faster hash function.
Hash table lookups are very hot in rustc profiles and the time taken within `FnvHash` itself is a big part of that. Although FNV is a simple hash, it processes its input one byte at a time. In contrast, Firefox has a homespun hash function that is also simple but works on multiple bytes at a time. So I tried it out and the results are compelling:
```
futures-rs-test 4.326s vs 4.212s --> 1.027x faster (variance: 1.001x, 1.007x)
helloworld 0.233s vs 0.232s --> 1.004x faster (variance: 1.037x, 1.016x)
html5ever-2016- 5.397s vs 5.210s --> 1.036x faster (variance: 1.009x, 1.006x)
hyper.0.5.0 5.018s vs 4.905s --> 1.023x faster (variance: 1.007x, 1.006x)
inflate-0.1.0 4.889s vs 4.872s --> 1.004x faster (variance: 1.012x, 1.007x)
issue-32062-equ 0.347s vs 0.335s --> 1.035x faster (variance: 1.033x, 1.019x)
issue-32278-big 1.717s vs 1.622s --> 1.059x faster (variance: 1.027x, 1.028x)
jld-day15-parse 1.537s vs 1.459s --> 1.054x faster (variance: 1.005x, 1.003x)
piston-image-0. 11.863s vs 11.482s --> 1.033x faster (variance: 1.060x, 1.002x)
regex.0.1.30 2.517s vs 2.453s --> 1.026x faster (variance: 1.011x, 1.013x)
rust-encoding-0 2.080s vs 2.047s --> 1.016x faster (variance: 1.005x, 1.005x)
syntex-0.42.2 32.268s vs 31.275s --> 1.032x faster (variance: 1.014x, 1.022x)
syntex-0.42.2-i 17.629s vs 16.559s --> 1.065x faster (variance: 1.013x, 1.021x)
```
(That's a stage1 compiler doing debug builds. Results for a stage2 compiler are similar.)
The attached commit is not in a state suitable for landing because I changed the implementation of FnvHasher without changing its name (because that would have required touching many lines in the compiler). Nonetheless, it is a good place to start discussions.
Profiles show very clearly that this new hash function is a lot faster to compute than FNV. The quality of the new hash function is less clear -- it seems to do better in some cases and worse in others (judging by the number of instructions executed in `Hash{Map,Set}::get`).
CC @brson, @arthurprs
Stabilize `..` in tuple (struct) patterns
I'd like to nominate `..` in tuple and tuple struct patterns for stabilization.
This feature is a relatively small extension to existing stable functionality and doesn't have known blockers.
The feature first appeared in Rust 1.10 6 months ago.
An example of use: https://github.com/rust-lang/rust/pull/36203
Closes https://github.com/rust-lang/rust/issues/33627
r? @nikomatsakis
Diagnostics for struct path resolution errors in resolve and typeck are unified.
Self type is treated as a type alias in few places (not reachable yet).
Unsafe cell is seen in constants even through type aliases.
All checks for struct paths in typeck work on type level.