Skip to content

Commit ac04bfd

Browse files
committed
Add View Mir command and fix some bugs
1 parent a25710b commit ac04bfd

File tree

23 files changed

+876
-122
lines changed

23 files changed

+876
-122
lines changed

crates/hir-ty/src/db.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::{
1818
chalk_db,
1919
consteval::ConstEvalError,
2020
method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
21-
mir::{MirBody, MirLowerError},
21+
mir::{BorrowckResult, MirBody, MirLowerError},
2222
Binders, CallableDefId, Const, FnDefId, GenericArg, ImplTraitId, InferenceResult, Interner,
2323
PolyFnSig, QuantifiedWhereClause, ReturnTypeImplTraits, Substitution, TraitRef, Ty, TyDefId,
2424
ValueTyDefId,
@@ -38,6 +38,9 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
3838
#[salsa::cycle(crate::mir::mir_body_recover)]
3939
fn mir_body(&self, def: DefWithBodyId) -> Result<Arc<MirBody>, MirLowerError>;
4040

41+
#[salsa::invoke(crate::mir::borrowck_query)]
42+
fn borrowck(&self, def: DefWithBodyId) -> Result<Arc<BorrowckResult>, MirLowerError>;
43+
4144
#[salsa::invoke(crate::lower::ty_query)]
4245
#[salsa::cycle(crate::lower::ty_recover)]
4346
fn ty(&self, def: TyDefId) -> Binders<Ty>;

crates/hir-ty/src/display.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,7 @@ fn render_const_scalar(
531531
hir_def::AdtId::UnionId(u) => write!(f, "{}", f.db.union_data(u).name),
532532
hir_def::AdtId::EnumId(_) => f.write_str("<enum-not-supported>"),
533533
},
534+
chalk_ir::TyKind::FnDef(..) => ty.hir_fmt(f),
534535
_ => f.write_str("<not-supported>"),
535536
}
536537
}

crates/hir-ty/src/mir.rs

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! MIR definitions and implementation
22
3-
use std::iter;
3+
use std::{fmt::Display, iter};
44

55
use crate::{
66
infer::PointerCast, Const, ConstScalar, InferenceResult, Interner, MemoryMap, Substitution, Ty,
@@ -14,8 +14,10 @@ use la_arena::{Arena, ArenaMap, Idx, RawIdx};
1414

1515
mod eval;
1616
mod lower;
17-
pub mod borrowck;
17+
mod borrowck;
18+
mod pretty;
1819

20+
pub use borrowck::{borrowck_query, BorrowckResult, MutabilityReason};
1921
pub use eval::{interpret_mir, pad16, Evaluator, MirEvalError};
2022
pub use lower::{lower_to_mir, mir_body_query, mir_body_recover, MirLowerError};
2123
use smallvec::{smallvec, SmallVec};
@@ -32,13 +34,7 @@ fn return_slot() -> LocalId {
3234

3335
#[derive(Debug, PartialEq, Eq)]
3436
pub struct Local {
35-
pub mutability: Mutability,
36-
//pub local_info: Option<Box<LocalInfo>>,
37-
//pub internal: bool,
38-
//pub is_block_tail: Option<BlockTailInfo>,
3937
pub ty: Ty,
40-
//pub user_ty: Option<Box<UserTypeProjections>>,
41-
//pub source_info: SourceInfo,
4238
}
4339

4440
/// An operand in MIR represents a "value" in Rust, the definition of which is undecided and part of
@@ -564,6 +560,30 @@ pub enum BinOp {
564560
Offset,
565561
}
566562

563+
impl Display for BinOp {
564+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
565+
f.write_str(match self {
566+
BinOp::Add => "+",
567+
BinOp::Sub => "-",
568+
BinOp::Mul => "*",
569+
BinOp::Div => "/",
570+
BinOp::Rem => "%",
571+
BinOp::BitXor => "^",
572+
BinOp::BitAnd => "&",
573+
BinOp::BitOr => "|",
574+
BinOp::Shl => "<<",
575+
BinOp::Shr => ">>",
576+
BinOp::Eq => "==",
577+
BinOp::Lt => "<",
578+
BinOp::Le => "<=",
579+
BinOp::Ne => "!=",
580+
BinOp::Ge => ">=",
581+
BinOp::Gt => ">",
582+
BinOp::Offset => "`offset`",
583+
})
584+
}
585+
}
586+
567587
impl From<hir_def::expr::ArithOp> for BinOp {
568588
fn from(value: hir_def::expr::ArithOp) -> Self {
569589
match value {
@@ -822,10 +842,9 @@ pub struct MirBody {
822842
pub owner: DefWithBodyId,
823843
pub arg_count: usize,
824844
pub binding_locals: ArenaMap<BindingId, LocalId>,
845+
pub param_locals: Vec<LocalId>,
825846
}
826847

827-
impl MirBody {}
828-
829848
fn const_as_usize(c: &Const) -> usize {
830849
try_const_usize(c).unwrap() as usize
831850
}

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

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,43 @@
11
//! MIR borrow checker, which is used in diagnostics like `unused_mut`
22
33
// Currently it is an ad-hoc implementation, only useful for mutability analysis. Feel free to remove all of these
4-
// and implement a proper borrow checker.
4+
// if needed for implementing a proper borrow checker.
55

6+
use std::sync::Arc;
7+
8+
use hir_def::DefWithBodyId;
69
use la_arena::ArenaMap;
710
use stdx::never;
811

12+
use crate::db::HirDatabase;
13+
914
use super::{
10-
BasicBlockId, BorrowKind, LocalId, MirBody, MirSpan, Place, ProjectionElem, Rvalue,
11-
StatementKind, Terminator,
15+
BasicBlockId, BorrowKind, LocalId, MirBody, MirLowerError, MirSpan, Place, ProjectionElem,
16+
Rvalue, StatementKind, Terminator,
1217
};
1318

14-
#[derive(Debug)]
15-
pub enum Mutability {
16-
Mut { span: MirSpan },
19+
#[derive(Debug, Clone, PartialEq, Eq)]
20+
/// Stores spans which implies that the local should be mutable.
21+
pub enum MutabilityReason {
22+
Mut { spans: Vec<MirSpan> },
1723
Not,
1824
}
1925

26+
#[derive(Debug, Clone, PartialEq, Eq)]
27+
pub struct BorrowckResult {
28+
pub mir_body: Arc<MirBody>,
29+
pub mutability_of_locals: ArenaMap<LocalId, MutabilityReason>,
30+
}
31+
32+
pub fn borrowck_query(
33+
db: &dyn HirDatabase,
34+
def: DefWithBodyId,
35+
) -> Result<Arc<BorrowckResult>, MirLowerError> {
36+
let body = db.mir_body(def)?;
37+
let r = BorrowckResult { mutability_of_locals: mutability_of_locals(&body), mir_body: body };
38+
Ok(Arc::new(r))
39+
}
40+
2041
fn is_place_direct(lvalue: &Place) -> bool {
2142
!lvalue.projection.iter().any(|x| *x == ProjectionElem::Deref)
2243
}
@@ -116,49 +137,49 @@ fn ever_initialized_map(body: &MirBody) -> ArenaMap<BasicBlockId, ArenaMap<Local
116137
}
117138
}
118139
}
119-
for (b, block) in body.basic_blocks.iter() {
120-
for statement in &block.statements {
121-
if let StatementKind::Assign(p, _) = &statement.kind {
122-
if p.projection.len() == 0 {
123-
let l = p.local;
124-
if !result[b].contains_idx(l) {
125-
result[b].insert(l, false);
126-
dfs(body, b, l, &mut result);
127-
}
128-
}
129-
}
140+
for &l in &body.param_locals {
141+
result[body.start_block].insert(l, true);
142+
dfs(body, body.start_block, l, &mut result);
143+
}
144+
for l in body.locals.iter().map(|x| x.0) {
145+
if !result[body.start_block].contains_idx(l) {
146+
result[body.start_block].insert(l, false);
147+
dfs(body, body.start_block, l, &mut result);
130148
}
131149
}
132150
result
133151
}
134152

135-
pub fn mutability_of_locals(body: &MirBody) -> ArenaMap<LocalId, Mutability> {
136-
let mut result: ArenaMap<LocalId, Mutability> =
137-
body.locals.iter().map(|x| (x.0, Mutability::Not)).collect();
153+
fn mutability_of_locals(body: &MirBody) -> ArenaMap<LocalId, MutabilityReason> {
154+
let mut result: ArenaMap<LocalId, MutabilityReason> =
155+
body.locals.iter().map(|x| (x.0, MutabilityReason::Not)).collect();
156+
let mut push_mut_span = |local, span| match &mut result[local] {
157+
MutabilityReason::Mut { spans } => spans.push(span),
158+
x @ MutabilityReason::Not => *x = MutabilityReason::Mut { spans: vec![span] },
159+
};
138160
let ever_init_maps = ever_initialized_map(body);
139-
for (block_id, ever_init_map) in ever_init_maps.iter() {
140-
let mut ever_init_map = ever_init_map.clone();
161+
for (block_id, mut ever_init_map) in ever_init_maps.into_iter() {
141162
let block = &body.basic_blocks[block_id];
142163
for statement in &block.statements {
143164
match &statement.kind {
144165
StatementKind::Assign(place, value) => {
145166
match place_case(place) {
146167
ProjectionCase::Direct => {
147168
if ever_init_map.get(place.local).copied().unwrap_or_default() {
148-
result[place.local] = Mutability::Mut { span: statement.span };
169+
push_mut_span(place.local, statement.span);
149170
} else {
150171
ever_init_map.insert(place.local, true);
151172
}
152173
}
153174
ProjectionCase::DirectPart => {
154175
// Partial initialization is not supported, so it is definitely `mut`
155-
result[place.local] = Mutability::Mut { span: statement.span };
176+
push_mut_span(place.local, statement.span);
156177
}
157178
ProjectionCase::Indirect => (),
158179
}
159180
if let Rvalue::Ref(BorrowKind::Mut { .. }, p) = value {
160181
if is_place_direct(p) {
161-
result[p.local] = Mutability::Mut { span: statement.span };
182+
push_mut_span(p.local, statement.span);
162183
}
163184
}
164185
}
@@ -189,7 +210,7 @@ pub fn mutability_of_locals(body: &MirBody) -> ArenaMap<LocalId, Mutability> {
189210
Terminator::Call { destination, .. } => {
190211
if destination.projection.len() == 0 {
191212
if ever_init_map.get(destination.local).copied().unwrap_or_default() {
192-
result[destination.local] = Mutability::Mut { span: MirSpan::Unknown };
213+
push_mut_span(destination.local, MirSpan::Unknown);
193214
} else {
194215
ever_init_map.insert(destination.local, true);
195216
}

0 commit comments

Comments
 (0)