Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit e5c7228

Browse files
committed
Auto merge of rust-lang#14808 - HKalbasi:metrics, r=HKalbasi
Add metrics for unevaluated constants, failed mir bodies, and failed data layouts fix rust-lang#14803
2 parents cbd14e9 + 206a0b5 commit e5c7228

File tree

4 files changed

+113
-19
lines changed

4 files changed

+113
-19
lines changed

crates/hir-ty/src/consteval/tests.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2066,3 +2066,22 @@ fn type_error() {
20662066
|e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::TypeMismatch(_))),
20672067
);
20682068
}
2069+
2070+
#[test]
2071+
fn unsized_local() {
2072+
check_fail(
2073+
r#"
2074+
//- minicore: coerce_unsized, index, slice
2075+
const fn x() -> SomeUnknownTypeThatDereferenceToSlice {
2076+
SomeUnknownTypeThatDereferenceToSlice
2077+
}
2078+
2079+
const GOAL: u16 = {
2080+
let y = x();
2081+
let z: &[u16] = &y;
2082+
z[1]
2083+
};
2084+
"#,
2085+
|e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::UnsizedTemporary(_))),
2086+
);
2087+
}

crates/hir-ty/src/mir/lower.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ pub enum MirLowerError {
7575
RecordLiteralWithoutPath,
7676
UnresolvedMethod(String),
7777
UnresolvedField,
78+
UnsizedTemporary(Ty),
7879
MissingFunctionDefinition,
7980
TypeMismatch(TypeMismatch),
8081
/// This should be never happen. Type mismatch should catch everything.
@@ -108,6 +109,7 @@ impl MirLowerError {
108109
}
109110
}
110111
MirLowerError::LayoutError(_)
112+
| MirLowerError::UnsizedTemporary(_)
111113
| MirLowerError::IncompleteExpr
112114
| MirLowerError::UnaccessableLocal
113115
| MirLowerError::TraitFunctionDefinition(_, _)
@@ -199,7 +201,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
199201

200202
fn temp(&mut self, ty: Ty) -> Result<LocalId> {
201203
if matches!(ty.kind(Interner), TyKind::Slice(_) | TyKind::Dyn(_)) {
202-
implementation_error!("unsized temporaries");
204+
return Err(MirLowerError::UnsizedTemporary(ty));
203205
}
204206
Ok(self.result.locals.alloc(Local { ty }))
205207
}

crates/rust-analyzer/src/cli/analysis_stats.rs

Lines changed: 88 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
//! errors.
33
44
use std::{
5-
collections::HashMap,
65
env,
76
time::{SystemTime, UNIX_EPOCH},
87
};
@@ -16,7 +15,7 @@ use hir_def::{
1615
hir::{ExprId, PatId},
1716
FunctionId,
1817
};
19-
use hir_ty::{Interner, TyExt, TypeFlags};
18+
use hir_ty::{Interner, Substitution, TyExt, TypeFlags};
2019
use ide::{Analysis, AnalysisHost, LineCol, RootDatabase};
2120
use ide_db::base_db::{
2221
salsa::{self, debug::DebugQueryTable, ParallelDatabase},
@@ -122,14 +121,19 @@ impl flags::AnalysisStats {
122121
eprint!(" crates: {num_crates}");
123122
let mut num_decls = 0;
124123
let mut funcs = Vec::new();
124+
let mut adts = Vec::new();
125+
let mut consts = Vec::new();
125126
while let Some(module) = visit_queue.pop() {
126127
if visited_modules.insert(module) {
127128
visit_queue.extend(module.children(db));
128129

129130
for decl in module.declarations(db) {
130131
num_decls += 1;
131-
if let ModuleDef::Function(f) = decl {
132-
funcs.push(f);
132+
match decl {
133+
ModuleDef::Function(f) => funcs.push(f),
134+
ModuleDef::Adt(a) => adts.push(a),
135+
ModuleDef::Const(c) => consts.push(c),
136+
_ => (),
133137
}
134138
}
135139

@@ -154,10 +158,13 @@ impl flags::AnalysisStats {
154158
self.run_inference(&host, db, &vfs, &funcs, verbosity);
155159
}
156160

157-
if self.mir_stats {
158-
self.lower_mir(db, &funcs);
161+
if !self.skip_mir_stats {
162+
self.run_mir_lowering(db, &funcs, verbosity);
159163
}
160164

165+
self.run_data_layout(db, &adts, verbosity);
166+
self.run_const_eval(db, &consts, verbosity);
167+
161168
let total_span = analysis_sw.elapsed();
162169
eprintln!("{:<20} {total_span}", "Total:");
163170
report_metric("total time", total_span.time.as_millis() as u64, "ms");
@@ -193,22 +200,88 @@ impl flags::AnalysisStats {
193200
Ok(())
194201
}
195202

196-
fn lower_mir(&self, db: &RootDatabase, funcs: &[Function]) {
197-
let all = funcs.len();
203+
fn run_data_layout(&self, db: &RootDatabase, adts: &[hir::Adt], verbosity: Verbosity) {
204+
let mut sw = self.stop_watch();
205+
let mut all = 0;
206+
let mut fail = 0;
207+
for &a in adts {
208+
if db.generic_params(a.into()).iter().next().is_some() {
209+
// Data types with generics don't have layout.
210+
continue;
211+
}
212+
all += 1;
213+
let Err(e) = db.layout_of_adt(hir_def::AdtId::from(a).into(), Substitution::empty(Interner)) else {
214+
continue;
215+
};
216+
if verbosity.is_spammy() {
217+
let full_name = a
218+
.module(db)
219+
.path_to_root(db)
220+
.into_iter()
221+
.rev()
222+
.filter_map(|it| it.name(db))
223+
.chain(Some(a.name(db)))
224+
.join("::");
225+
println!("Data layout for {full_name} failed due {e:?}");
226+
}
227+
fail += 1;
228+
}
229+
eprintln!("{:<20} {}", "Data layouts:", sw.elapsed());
230+
eprintln!("Failed data layouts: {fail} ({}%)", fail * 100 / all);
231+
report_metric("failed data layouts", fail, "#");
232+
}
233+
234+
fn run_const_eval(&self, db: &RootDatabase, consts: &[hir::Const], verbosity: Verbosity) {
235+
let mut sw = self.stop_watch();
236+
let mut all = 0;
237+
let mut fail = 0;
238+
for &c in consts {
239+
all += 1;
240+
let Err(e) = c.render_eval(db) else {
241+
continue;
242+
};
243+
if verbosity.is_spammy() {
244+
let full_name = c
245+
.module(db)
246+
.path_to_root(db)
247+
.into_iter()
248+
.rev()
249+
.filter_map(|it| it.name(db))
250+
.chain(c.name(db))
251+
.join("::");
252+
println!("Const eval for {full_name} failed due {e:?}");
253+
}
254+
fail += 1;
255+
}
256+
eprintln!("{:<20} {}", "Const evaluation:", sw.elapsed());
257+
eprintln!("Failed const evals: {fail} ({}%)", fail * 100 / all);
258+
report_metric("failed const evals", fail, "#");
259+
}
260+
261+
fn run_mir_lowering(&self, db: &RootDatabase, funcs: &[Function], verbosity: Verbosity) {
262+
let mut sw = self.stop_watch();
263+
let all = funcs.len() as u64;
198264
let mut fail = 0;
199-
let mut h: HashMap<String, usize> = HashMap::new();
200265
for f in funcs {
201-
let f = FunctionId::from(*f);
202-
let Err(e) = db.mir_body(f.into()) else {
266+
let Err(e) = db.mir_body(FunctionId::from(*f).into()) else {
203267
continue;
204268
};
205-
let es = format!("{:?}", e);
206-
*h.entry(es).or_default() += 1;
269+
if verbosity.is_spammy() {
270+
let full_name = f
271+
.module(db)
272+
.path_to_root(db)
273+
.into_iter()
274+
.rev()
275+
.filter_map(|it| it.name(db))
276+
.chain(Some(f.name(db)))
277+
.join("::");
278+
println!("Mir body for {full_name} failed due {e:?}");
279+
}
207280
fail += 1;
208281
}
209-
let h = h.into_iter().sorted_by_key(|x| x.1).collect::<Vec<_>>();
210-
eprintln!("Mir failed reasons: {:#?}", h);
282+
eprintln!("{:<20} {}", "MIR lowering:", sw.elapsed());
211283
eprintln!("Mir failed bodies: {fail} ({}%)", fail * 100 / all);
284+
report_metric("mir failed bodies", fail, "#");
212285
}
213286

214287
fn run_inference(

crates/rust-analyzer/src/cli/flags.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ xflags::xflags! {
6666
optional --memory-usage
6767
/// Print the total length of all source and macro files (whitespace is not counted).
6868
optional --source-stats
69-
/// Print the number of bodies that fail to lower to mir, in addition to failed reasons.
70-
optional --mir-stats
69+
/// Only type check, skip lowering to mir
70+
optional --skip-mir-stats
7171

7272
/// Only analyze items matching this path.
7373
optional -o, --only path: String
@@ -171,7 +171,7 @@ pub struct AnalysisStats {
171171
pub parallel: bool,
172172
pub memory_usage: bool,
173173
pub source_stats: bool,
174-
pub mir_stats: bool,
174+
pub skip_mir_stats: bool,
175175
pub only: Option<String>,
176176
pub with_deps: bool,
177177
pub no_sysroot: bool,

0 commit comments

Comments
 (0)