Skip to content

Commit 43c20c2

Browse files
authored
Merge pull request #18470 from Veykril/push-rxmtkvpulotn
Allow interpreting consts and statics with interpret function command
2 parents 72d9929 + 56e89bc commit 43c20c2

File tree

12 files changed

+114
-86
lines changed

12 files changed

+114
-86
lines changed

src/tools/rust-analyzer/crates/hir-def/src/data.rs

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ pub struct FunctionData {
3737
pub name: Name,
3838
pub params: Box<[TypeRefId]>,
3939
pub ret_type: TypeRefId,
40+
// FIXME: why are these stored here? They should be accessed via the query
4041
pub attrs: Attrs,
4142
pub visibility: RawVisibility,
4243
pub abi: Option<Symbol>,

src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs

+19-4
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,21 @@ pub enum ConstEvalError {
5656
MirEvalError(MirEvalError),
5757
}
5858

59+
impl ConstEvalError {
60+
pub fn pretty_print(
61+
&self,
62+
f: &mut String,
63+
db: &dyn HirDatabase,
64+
span_formatter: impl Fn(span::FileId, span::TextRange) -> String,
65+
edition: span::Edition,
66+
) -> std::result::Result<(), std::fmt::Error> {
67+
match self {
68+
ConstEvalError::MirLowerError(e) => e.pretty_print(f, db, span_formatter, edition),
69+
ConstEvalError::MirEvalError(e) => e.pretty_print(f, db, span_formatter, edition),
70+
}
71+
}
72+
}
73+
5974
impl From<MirLowerError> for ConstEvalError {
6075
fn from(value: MirLowerError) -> Self {
6176
match value {
@@ -253,7 +268,7 @@ pub(crate) fn const_eval_query(
253268
}
254269
GeneralConstId::InTypeConstId(c) => db.mir_body(c.into())?,
255270
};
256-
let c = interpret_mir(db, body, false, trait_env).0?;
271+
let c = interpret_mir(db, body, false, trait_env)?.0?;
257272
Ok(c)
258273
}
259274

@@ -266,7 +281,7 @@ pub(crate) fn const_eval_static_query(
266281
Substitution::empty(Interner),
267282
db.trait_environment_for_body(def.into()),
268283
)?;
269-
let c = interpret_mir(db, body, false, None).0?;
284+
let c = interpret_mir(db, body, false, None)?.0?;
270285
Ok(c)
271286
}
272287

@@ -298,7 +313,7 @@ pub(crate) fn const_eval_discriminant_variant(
298313
Substitution::empty(Interner),
299314
db.trait_environment_for_body(def),
300315
)?;
301-
let c = interpret_mir(db, mir_body, false, None).0?;
316+
let c = interpret_mir(db, mir_body, false, None)?.0?;
302317
let c = if is_signed {
303318
try_const_isize(db, &c).unwrap()
304319
} else {
@@ -339,7 +354,7 @@ pub(crate) fn eval_to_const(
339354
}
340355
}
341356
if let Ok(mir_body) = lower_to_mir(ctx.db, ctx.owner, ctx.body, &infer, expr) {
342-
if let Ok(result) = interpret_mir(db, Arc::new(mir_body), true, None).0 {
357+
if let Ok((Ok(result), _)) = interpret_mir(db, Arc::new(mir_body), true, None) {
343358
return result;
344359
}
345360
}

src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -585,13 +585,9 @@ pub fn interpret_mir(
585585
// (and probably should) do better here, for example by excluding bindings outside of the target expression.
586586
assert_placeholder_ty_is_unused: bool,
587587
trait_env: Option<Arc<TraitEnvironment>>,
588-
) -> (Result<Const>, MirOutput) {
588+
) -> Result<(Result<Const>, MirOutput)> {
589589
let ty = body.locals[return_slot()].ty.clone();
590-
let mut evaluator =
591-
match Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused, trait_env) {
592-
Ok(it) => it,
593-
Err(e) => return (Err(e), MirOutput { stdout: vec![], stderr: vec![] }),
594-
};
590+
let mut evaluator = Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused, trait_env)?;
595591
let it: Result<Const> = (|| {
596592
if evaluator.ptr_size() != std::mem::size_of::<usize>() {
597593
not_supported!("targets with different pointer size from host");
@@ -613,7 +609,7 @@ pub fn interpret_mir(
613609
};
614610
Ok(intern_const_scalar(ConstScalar::Bytes(bytes, memory_map), ty))
615611
})();
616-
(it, MirOutput { stdout: evaluator.stdout, stderr: evaluator.stderr })
612+
Ok((it, MirOutput { stdout: evaluator.stdout, stderr: evaluator.stderr }))
617613
}
618614

619615
#[cfg(test)]

src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String),
3232
)
3333
.map_err(|e| MirEvalError::MirLowerError(func_id, e))?;
3434

35-
let (result, output) = interpret_mir(db, body, false, None);
35+
let (result, output) = interpret_mir(db, body, false, None)?;
3636
result?;
3737
Ok((output.stdout().into_owned(), output.stderr().into_owned()))
3838
}

src/tools/rust-analyzer/crates/hir/src/lib.rs

+16-15
Original file line numberDiff line numberDiff line change
@@ -2306,22 +2306,15 @@ impl Function {
23062306
self,
23072307
db: &dyn HirDatabase,
23082308
span_formatter: impl Fn(FileId, TextRange) -> String,
2309-
) -> String {
2309+
) -> Result<String, ConstEvalError> {
23102310
let krate = HasModule::krate(&self.id, db.upcast());
23112311
let edition = db.crate_graph()[krate].edition;
2312-
let body = match db.monomorphized_mir_body(
2312+
let body = db.monomorphized_mir_body(
23132313
self.id.into(),
23142314
Substitution::empty(Interner),
23152315
db.trait_environment(self.id.into()),
2316-
) {
2317-
Ok(body) => body,
2318-
Err(e) => {
2319-
let mut r = String::new();
2320-
_ = e.pretty_print(&mut r, db, &span_formatter, edition);
2321-
return r;
2322-
}
2323-
};
2324-
let (result, output) = interpret_mir(db, body, false, None);
2316+
)?;
2317+
let (result, output) = interpret_mir(db, body, false, None)?;
23252318
let mut text = match result {
23262319
Ok(_) => "pass".to_owned(),
23272320
Err(e) => {
@@ -2340,7 +2333,7 @@ impl Function {
23402333
text += "\n--------- stderr ---------\n";
23412334
text += &stderr;
23422335
}
2343-
text
2336+
Ok(text)
23442337
}
23452338
}
23462339

@@ -2563,9 +2556,9 @@ impl Const {
25632556
/// Evaluate the constant and return the result as a string.
25642557
///
25652558
/// This function is intended for IDE assistance, different from [`Const::render_eval`].
2566-
pub fn eval(self, db: &dyn HirDatabase, edition: Edition) -> Result<String, ConstEvalError> {
2559+
pub fn eval(self, db: &dyn HirDatabase) -> Result<String, ConstEvalError> {
25672560
let c = db.const_eval(self.id.into(), Substitution::empty(Interner), None)?;
2568-
Ok(format!("{}", c.display(db, edition)))
2561+
Ok(format!("{}", c.display(db, self.krate(db).edition(db))))
25692562
}
25702563

25712564
/// Evaluate the constant and return the result as a string, with more detailed information.
@@ -2640,7 +2633,15 @@ impl Static {
26402633
Type::from_value_def(db, self.id)
26412634
}
26422635

2643-
/// Evaluate the constant and return the result as a string, with more detailed information.
2636+
/// Evaluate the static and return the result as a string.
2637+
///
2638+
/// This function is intended for IDE assistance, different from [`Static::render_eval`].
2639+
pub fn eval(self, db: &dyn HirDatabase) -> Result<String, ConstEvalError> {
2640+
let c = db.const_eval(self.id.into(), Substitution::empty(Interner), None)?;
2641+
Ok(format!("{}", c.display(db, self.krate(db).edition(db))))
2642+
}
2643+
2644+
/// Evaluate the static and return the result as a string, with more detailed information.
26442645
///
26452646
/// This function is intended for user-facing display.
26462647
pub fn render_eval(

src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,7 @@ pub(crate) fn inline_const_as_literal(acc: &mut Assists, ctx: &AssistContext<'_>
5151
| ast::Expr::MatchExpr(_)
5252
| ast::Expr::MacroExpr(_)
5353
| ast::Expr::BinExpr(_)
54-
| ast::Expr::CallExpr(_) => {
55-
let edition = ctx.sema.scope(variable.syntax())?.krate().edition(ctx.db());
56-
konst.eval(ctx.sema.db, edition).ok()?
57-
}
54+
| ast::Expr::CallExpr(_) => konst.eval(ctx.sema.db).ok()?,
5855
_ => return None,
5956
};
6057

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
use hir::{DefWithBody, Semantics};
2+
use ide_db::{base_db::SourceRootDatabase, FilePosition, LineIndexDatabase, RootDatabase};
3+
use std::time::{Duration, Instant};
4+
use stdx::format_to;
5+
use syntax::{algo::ancestors_at_offset, ast, AstNode, TextRange};
6+
7+
// Feature: Interpret a function, static or const.
8+
//
9+
// |===
10+
// | Editor | Action Name
11+
//
12+
// | VS Code | **rust-analyzer: Interpret**
13+
// |===
14+
pub(crate) fn interpret(db: &RootDatabase, position: FilePosition) -> String {
15+
match find_and_interpret(db, position) {
16+
Some((duration, mut result)) => {
17+
result.push('\n');
18+
format_to!(result, "----------------------\n");
19+
format_to!(result, " Finished in {}s\n", duration.as_secs_f32());
20+
result
21+
}
22+
_ => "Not inside a function, const or static".to_owned(),
23+
}
24+
}
25+
26+
fn find_and_interpret(db: &RootDatabase, position: FilePosition) -> Option<(Duration, String)> {
27+
let sema = Semantics::new(db);
28+
let source_file = sema.parse_guess_edition(position.file_id);
29+
30+
let item = ancestors_at_offset(source_file.syntax(), position.offset)
31+
.filter(|it| !ast::MacroCall::can_cast(it.kind()))
32+
.find_map(ast::Item::cast)?;
33+
let def: DefWithBody = match item {
34+
ast::Item::Fn(it) => sema.to_def(&it)?.into(),
35+
ast::Item::Const(it) => sema.to_def(&it)?.into(),
36+
ast::Item::Static(it) => sema.to_def(&it)?.into(),
37+
_ => return None,
38+
};
39+
let span_formatter = |file_id, text_range: TextRange| {
40+
let path = &db
41+
.source_root(db.file_source_root(file_id))
42+
.path_for_file(&file_id)
43+
.map(|x| x.to_string());
44+
let path = path.as_deref().unwrap_or("<unknown file>");
45+
match db.line_index(file_id).try_line_col(text_range.start()) {
46+
Some(line_col) => format!("file://{path}:{}:{}", line_col.line + 1, line_col.col),
47+
None => format!("file://{path} range {text_range:?}"),
48+
}
49+
};
50+
let start_time = Instant::now();
51+
let res = match def {
52+
DefWithBody::Function(it) => it.eval(db, span_formatter),
53+
DefWithBody::Static(it) => it.eval(db),
54+
DefWithBody::Const(it) => it.eval(db),
55+
_ => unreachable!(),
56+
};
57+
let res = res.unwrap_or_else(|e| {
58+
let mut r = String::new();
59+
_ = e.pretty_print(&mut r, db, span_formatter, def.module(db).krate().edition(db));
60+
r
61+
});
62+
let duration = Instant::now() - start_time;
63+
Some((duration, res))
64+
}

src/tools/rust-analyzer/crates/ide/src/interpret_function.rs

-47
This file was deleted.

src/tools/rust-analyzer/crates/ide/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ mod goto_type_definition;
3333
mod highlight_related;
3434
mod hover;
3535
mod inlay_hints;
36-
mod interpret_function;
36+
mod interpret;
3737
mod join_lines;
3838
mod markdown_remove;
3939
mod matching_brace;
@@ -350,7 +350,7 @@ impl Analysis {
350350
}
351351

352352
pub fn interpret_function(&self, position: FilePosition) -> Cancellable<String> {
353-
self.with_db(|db| interpret_function::interpret_function(db, position))
353+
self.with_db(|db| interpret::interpret(db, position))
354354
}
355355

356356
pub fn view_item_tree(&self, file_id: FileId) -> Cancellable<String> {

src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs

+2
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,8 @@ define_symbols! {
398398
rustc_const_panic_str,
399399
rustc_deprecated_safe_2024,
400400
rustc_has_incoherent_inherent_impls,
401+
rustc_intrinsic,
402+
rustc_intrinsic_must_be_overridden,
401403
rustc_layout_scalar_valid_range_end,
402404
rustc_layout_scalar_valid_range_start,
403405
rustc_legacy_const_generics,

src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,11 @@ impl flags::RunTests {
6161
}
6262
let mut sw_one = StopWatch::start();
6363
let result = test.eval(db, span_formatter);
64-
if result.trim() == "pass" {
65-
pass_count += 1;
66-
} else {
67-
fail_count += 1;
64+
match &result {
65+
Ok(result) if result.trim() == "pass" => pass_count += 1,
66+
_ => fail_count += 1,
6867
}
69-
println!("{result}");
68+
println!("{result:?}");
7069
eprintln!("{:<20} {}", format!("test {}", full_name), sw_one.elapsed());
7170
}
7271
println!("{pass_count} passed, {fail_count} failed, {ignore_count} ignored");

src/tools/rust-analyzer/editors/code/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@
125125
},
126126
{
127127
"command": "rust-analyzer.interpretFunction",
128-
"title": "Interpret Function",
128+
"title": "Interpret",
129129
"category": "rust-analyzer (debug command)"
130130
},
131131
{

0 commit comments

Comments
 (0)