aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/expr/lower.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/expr/lower.rs')
-rw-r--r--crates/ra_hir/src/expr/lower.rs652
1 files changed, 652 insertions, 0 deletions
diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs
new file mode 100644
index 000000000..f6a75a379
--- /dev/null
+++ b/crates/ra_hir/src/expr/lower.rs
@@ -0,0 +1,652 @@
1use std::sync::Arc;
2
3use ra_arena::Arena;
4use ra_syntax::{
5 ast::{
6 self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, NameOwner,
7 TypeAscriptionOwner,
8 },
9 AstNode, AstPtr,
10};
11use test_utils::tested_by;
12
13use crate::{
14 name::{AsName, Name, SELF_PARAM},
15 path::GenericArgs,
16 ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy},
17 type_ref::TypeRef,
18 DefWithBody, Either, HasSource, HirDatabase, HirFileId, MacroCallLoc, MacroFileKind,
19 Mutability, Path, Resolver,
20};
21
22use super::{
23 ArithOp, Array, BinaryOp, BindingAnnotation, Body, BodySourceMap, CmpOp, Expr, ExprId, Literal,
24 LogicOp, MatchArm, Ordering, Pat, PatId, PatPtr, RecordFieldPat, RecordLitField, Statement,
25};
26
27pub(crate) struct ExprCollector<DB> {
28 db: DB,
29 owner: DefWithBody,
30 exprs: Arena<ExprId, Expr>,
31 pats: Arena<PatId, Pat>,
32 source_map: BodySourceMap,
33 params: Vec<PatId>,
34 body_expr: Option<ExprId>,
35 resolver: Resolver,
36 // Expr collector expands macros along the way. original points to the file
37 // we started with, current points to the current macro expansion. source
38 // maps don't support macros yet, so we only record info into source map if
39 // current == original (see #1196)
40 original_file_id: HirFileId,
41 current_file_id: HirFileId,
42}
43
44impl<'a, DB> ExprCollector<&'a DB>
45where
46 DB: HirDatabase,
47{
48 fn new(owner: DefWithBody, file_id: HirFileId, resolver: Resolver, db: &'a DB) -> Self {
49 ExprCollector {
50 owner,
51 resolver,
52 db,
53 exprs: Arena::default(),
54 pats: Arena::default(),
55 source_map: BodySourceMap::default(),
56 params: Vec::new(),
57 body_expr: None,
58 original_file_id: file_id,
59 current_file_id: file_id,
60 }
61 }
62 fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
63 let ptr = Either::A(ptr);
64 let id = self.exprs.alloc(expr);
65 if self.current_file_id == self.original_file_id {
66 self.source_map.expr_map.insert(ptr, id);
67 self.source_map.expr_map_back.insert(id, ptr);
68 }
69 id
70 }
71
72 fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
73 let id = self.pats.alloc(pat);
74
75 if self.current_file_id == self.original_file_id {
76 self.source_map.pat_map.insert(ptr, id);
77 self.source_map.pat_map_back.insert(id, ptr);
78 }
79
80 id
81 }
82
83 fn empty_block(&mut self) -> ExprId {
84 let block = Expr::Block { statements: Vec::new(), tail: None };
85 self.exprs.alloc(block)
86 }
87
88 fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
89 let syntax_ptr = AstPtr::new(&expr);
90 match expr {
91 ast::Expr::IfExpr(e) => {
92 let then_branch = self.collect_block_opt(e.then_branch());
93
94 let else_branch = e.else_branch().map(|b| match b {
95 ast::ElseBranch::Block(it) => self.collect_block(it),
96 ast::ElseBranch::IfExpr(elif) => {
97 let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap();
98 self.collect_expr(expr)
99 }
100 });
101
102 let condition = match e.condition() {
103 None => self.exprs.alloc(Expr::Missing),
104 Some(condition) => match condition.pat() {
105 None => self.collect_expr_opt(condition.expr()),
106 // if let -- desugar to match
107 Some(pat) => {
108 let pat = self.collect_pat(pat);
109 let match_expr = self.collect_expr_opt(condition.expr());
110 let placeholder_pat = self.pats.alloc(Pat::Missing);
111 let arms = vec![
112 MatchArm { pats: vec![pat], expr: then_branch, guard: None },
113 MatchArm {
114 pats: vec![placeholder_pat],
115 expr: else_branch.unwrap_or_else(|| self.empty_block()),
116 guard: None,
117 },
118 ];
119 return self
120 .alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr);
121 }
122 },
123 };
124
125 self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)
126 }
127 ast::Expr::TryBlockExpr(e) => {
128 let body = self.collect_block_opt(e.body());
129 self.alloc_expr(Expr::TryBlock { body }, syntax_ptr)
130 }
131 ast::Expr::BlockExpr(e) => self.collect_block(e),
132 ast::Expr::LoopExpr(e) => {
133 let body = self.collect_block_opt(e.loop_body());
134 self.alloc_expr(Expr::Loop { body }, syntax_ptr)
135 }
136 ast::Expr::WhileExpr(e) => {
137 let body = self.collect_block_opt(e.loop_body());
138
139 let condition = match e.condition() {
140 None => self.exprs.alloc(Expr::Missing),
141 Some(condition) => match condition.pat() {
142 None => self.collect_expr_opt(condition.expr()),
143 // if let -- desugar to match
144 Some(pat) => {
145 tested_by!(infer_while_let);
146 let pat = self.collect_pat(pat);
147 let match_expr = self.collect_expr_opt(condition.expr());
148 let placeholder_pat = self.pats.alloc(Pat::Missing);
149 let break_ = self.exprs.alloc(Expr::Break { expr: None });
150 let arms = vec![
151 MatchArm { pats: vec![pat], expr: body, guard: None },
152 MatchArm { pats: vec![placeholder_pat], expr: break_, guard: None },
153 ];
154 let match_expr =
155 self.exprs.alloc(Expr::Match { expr: match_expr, arms });
156 return self.alloc_expr(Expr::Loop { body: match_expr }, syntax_ptr);
157 }
158 },
159 };
160
161 self.alloc_expr(Expr::While { condition, body }, syntax_ptr)
162 }
163 ast::Expr::ForExpr(e) => {
164 let iterable = self.collect_expr_opt(e.iterable());
165 let pat = self.collect_pat_opt(e.pat());
166 let body = self.collect_block_opt(e.loop_body());
167 self.alloc_expr(Expr::For { iterable, pat, body }, syntax_ptr)
168 }
169 ast::Expr::CallExpr(e) => {
170 let callee = self.collect_expr_opt(e.expr());
171 let args = if let Some(arg_list) = e.arg_list() {
172 arg_list.args().map(|e| self.collect_expr(e)).collect()
173 } else {
174 Vec::new()
175 };
176 self.alloc_expr(Expr::Call { callee, args }, syntax_ptr)
177 }
178 ast::Expr::MethodCallExpr(e) => {
179 let receiver = self.collect_expr_opt(e.expr());
180 let args = if let Some(arg_list) = e.arg_list() {
181 arg_list.args().map(|e| self.collect_expr(e)).collect()
182 } else {
183 Vec::new()
184 };
185 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
186 let generic_args = e.type_arg_list().and_then(GenericArgs::from_ast);
187 self.alloc_expr(
188 Expr::MethodCall { receiver, method_name, args, generic_args },
189 syntax_ptr,
190 )
191 }
192 ast::Expr::MatchExpr(e) => {
193 let expr = self.collect_expr_opt(e.expr());
194 let arms = if let Some(match_arm_list) = e.match_arm_list() {
195 match_arm_list
196 .arms()
197 .map(|arm| MatchArm {
198 pats: arm.pats().map(|p| self.collect_pat(p)).collect(),
199 expr: self.collect_expr_opt(arm.expr()),
200 guard: arm
201 .guard()
202 .and_then(|guard| guard.expr())
203 .map(|e| self.collect_expr(e)),
204 })
205 .collect()
206 } else {
207 Vec::new()
208 };
209 self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
210 }
211 ast::Expr::PathExpr(e) => {
212 let path =
213 e.path().and_then(Path::from_ast).map(Expr::Path).unwrap_or(Expr::Missing);
214 self.alloc_expr(path, syntax_ptr)
215 }
216 ast::Expr::ContinueExpr(_e) => {
217 // FIXME: labels
218 self.alloc_expr(Expr::Continue, syntax_ptr)
219 }
220 ast::Expr::BreakExpr(e) => {
221 let expr = e.expr().map(|e| self.collect_expr(e));
222 self.alloc_expr(Expr::Break { expr }, syntax_ptr)
223 }
224 ast::Expr::ParenExpr(e) => {
225 let inner = self.collect_expr_opt(e.expr());
226 // make the paren expr point to the inner expression as well
227 self.source_map.expr_map.insert(Either::A(syntax_ptr), inner);
228 inner
229 }
230 ast::Expr::ReturnExpr(e) => {
231 let expr = e.expr().map(|e| self.collect_expr(e));
232 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
233 }
234 ast::Expr::RecordLit(e) => {
235 let path = e.path().and_then(Path::from_ast);
236 let mut field_ptrs = Vec::new();
237 let record_lit = if let Some(nfl) = e.record_field_list() {
238 let fields = nfl
239 .fields()
240 .inspect(|field| field_ptrs.push(AstPtr::new(field)))
241 .map(|field| RecordLitField {
242 name: field
243 .name_ref()
244 .map(|nr| nr.as_name())
245 .unwrap_or_else(Name::missing),
246 expr: if let Some(e) = field.expr() {
247 self.collect_expr(e)
248 } else if let Some(nr) = field.name_ref() {
249 // field shorthand
250 let id = self.exprs.alloc(Expr::Path(Path::from_name_ref(&nr)));
251 let ptr = Either::B(AstPtr::new(&field));
252 self.source_map.expr_map.insert(ptr, id);
253 self.source_map.expr_map_back.insert(id, ptr);
254 id
255 } else {
256 self.exprs.alloc(Expr::Missing)
257 },
258 })
259 .collect();
260 let spread = nfl.spread().map(|s| self.collect_expr(s));
261 Expr::RecordLit { path, fields, spread }
262 } else {
263 Expr::RecordLit { path, fields: Vec::new(), spread: None }
264 };
265
266 let res = self.alloc_expr(record_lit, syntax_ptr);
267 for (i, ptr) in field_ptrs.into_iter().enumerate() {
268 self.source_map.field_map.insert((res, i), ptr);
269 }
270 res
271 }
272 ast::Expr::FieldExpr(e) => {
273 let expr = self.collect_expr_opt(e.expr());
274 let name = match e.field_access() {
275 Some(kind) => kind.as_name(),
276 _ => Name::missing(),
277 };
278 self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
279 }
280 ast::Expr::AwaitExpr(e) => {
281 let expr = self.collect_expr_opt(e.expr());
282 self.alloc_expr(Expr::Await { expr }, syntax_ptr)
283 }
284 ast::Expr::TryExpr(e) => {
285 let expr = self.collect_expr_opt(e.expr());
286 self.alloc_expr(Expr::Try { expr }, syntax_ptr)
287 }
288 ast::Expr::CastExpr(e) => {
289 let expr = self.collect_expr_opt(e.expr());
290 let type_ref = TypeRef::from_ast_opt(e.type_ref());
291 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
292 }
293 ast::Expr::RefExpr(e) => {
294 let expr = self.collect_expr_opt(e.expr());
295 let mutability = Mutability::from_mutable(e.is_mut());
296 self.alloc_expr(Expr::Ref { expr, mutability }, syntax_ptr)
297 }
298 ast::Expr::PrefixExpr(e) => {
299 let expr = self.collect_expr_opt(e.expr());
300 if let Some(op) = e.op_kind() {
301 self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr)
302 } else {
303 self.alloc_expr(Expr::Missing, syntax_ptr)
304 }
305 }
306 ast::Expr::LambdaExpr(e) => {
307 let mut args = Vec::new();
308 let mut arg_types = Vec::new();
309 if let Some(pl) = e.param_list() {
310 for param in pl.params() {
311 let pat = self.collect_pat_opt(param.pat());
312 let type_ref = param.ascribed_type().map(TypeRef::from_ast);
313 args.push(pat);
314 arg_types.push(type_ref);
315 }
316 }
317 let body = self.collect_expr_opt(e.body());
318 self.alloc_expr(Expr::Lambda { args, arg_types, body }, syntax_ptr)
319 }
320 ast::Expr::BinExpr(e) => {
321 let lhs = self.collect_expr_opt(e.lhs());
322 let rhs = self.collect_expr_opt(e.rhs());
323 let op = e.op_kind().map(BinaryOp::from);
324 self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
325 }
326 ast::Expr::TupleExpr(e) => {
327 let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect();
328 self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr)
329 }
330
331 ast::Expr::ArrayExpr(e) => {
332 let kind = e.kind();
333
334 match kind {
335 ArrayExprKind::ElementList(e) => {
336 let exprs = e.map(|expr| self.collect_expr(expr)).collect();
337 self.alloc_expr(Expr::Array(Array::ElementList(exprs)), syntax_ptr)
338 }
339 ArrayExprKind::Repeat { initializer, repeat } => {
340 let initializer = self.collect_expr_opt(initializer);
341 let repeat = self.collect_expr_opt(repeat);
342 self.alloc_expr(
343 Expr::Array(Array::Repeat { initializer, repeat }),
344 syntax_ptr,
345 )
346 }
347 }
348 }
349
350 ast::Expr::Literal(e) => {
351 let lit = match e.kind() {
352 LiteralKind::IntNumber { suffix } => {
353 let known_name = suffix
354 .and_then(|it| IntTy::from_suffix(&it).map(UncertainIntTy::Known));
355
356 Literal::Int(
357 Default::default(),
358 known_name.unwrap_or(UncertainIntTy::Unknown),
359 )
360 }
361 LiteralKind::FloatNumber { suffix } => {
362 let known_name = suffix
363 .and_then(|it| FloatTy::from_suffix(&it).map(UncertainFloatTy::Known));
364
365 Literal::Float(
366 Default::default(),
367 known_name.unwrap_or(UncertainFloatTy::Unknown),
368 )
369 }
370 LiteralKind::ByteString => Literal::ByteString(Default::default()),
371 LiteralKind::String => Literal::String(Default::default()),
372 LiteralKind::Byte => {
373 Literal::Int(Default::default(), UncertainIntTy::Known(IntTy::u8()))
374 }
375 LiteralKind::Bool => Literal::Bool(Default::default()),
376 LiteralKind::Char => Literal::Char(Default::default()),
377 };
378 self.alloc_expr(Expr::Literal(lit), syntax_ptr)
379 }
380 ast::Expr::IndexExpr(e) => {
381 let base = self.collect_expr_opt(e.base());
382 let index = self.collect_expr_opt(e.index());
383 self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
384 }
385
386 // FIXME implement HIR for these:
387 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
388 ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
389 ast::Expr::MacroCall(e) => {
390 let ast_id = self
391 .db
392 .ast_id_map(self.current_file_id)
393 .ast_id(&e)
394 .with_file_id(self.current_file_id);
395
396 if let Some(path) = e.path().and_then(Path::from_ast) {
397 if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) {
398 let call_id = MacroCallLoc { def: def.id, ast_id }.id(self.db);
399 let file_id = call_id.as_file(MacroFileKind::Expr);
400 if let Some(node) = self.db.parse_or_expand(file_id) {
401 if let Some(expr) = ast::Expr::cast(node) {
402 log::debug!("macro expansion {:#?}", expr.syntax());
403 let old_file_id =
404 std::mem::replace(&mut self.current_file_id, file_id);
405 let id = self.collect_expr(expr);
406 self.current_file_id = old_file_id;
407 return id;
408 }
409 }
410 }
411 }
412 // FIXME: Instead of just dropping the error from expansion
413 // report it
414 self.alloc_expr(Expr::Missing, syntax_ptr)
415 }
416 }
417 }
418
419 fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
420 if let Some(expr) = expr {
421 self.collect_expr(expr)
422 } else {
423 self.exprs.alloc(Expr::Missing)
424 }
425 }
426
427 fn collect_block(&mut self, expr: ast::BlockExpr) -> ExprId {
428 let syntax_node_ptr = AstPtr::new(&expr.clone().into());
429 let block = match expr.block() {
430 Some(block) => block,
431 None => return self.alloc_expr(Expr::Missing, syntax_node_ptr),
432 };
433 let statements = block
434 .statements()
435 .map(|s| match s {
436 ast::Stmt::LetStmt(stmt) => {
437 let pat = self.collect_pat_opt(stmt.pat());
438 let type_ref = stmt.ascribed_type().map(TypeRef::from_ast);
439 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
440 Statement::Let { pat, type_ref, initializer }
441 }
442 ast::Stmt::ExprStmt(stmt) => Statement::Expr(self.collect_expr_opt(stmt.expr())),
443 })
444 .collect();
445 let tail = block.expr().map(|e| self.collect_expr(e));
446 self.alloc_expr(Expr::Block { statements, tail }, syntax_node_ptr)
447 }
448
449 fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
450 if let Some(block) = expr {
451 self.collect_block(block)
452 } else {
453 self.exprs.alloc(Expr::Missing)
454 }
455 }
456
457 fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
458 let pattern = match &pat {
459 ast::Pat::BindPat(bp) => {
460 let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
461 let annotation = BindingAnnotation::new(bp.is_mutable(), bp.is_ref());
462 let subpat = bp.pat().map(|subpat| self.collect_pat(subpat));
463 Pat::Bind { name, mode: annotation, subpat }
464 }
465 ast::Pat::TupleStructPat(p) => {
466 let path = p.path().and_then(Path::from_ast);
467 let args = p.args().map(|p| self.collect_pat(p)).collect();
468 Pat::TupleStruct { path, args }
469 }
470 ast::Pat::RefPat(p) => {
471 let pat = self.collect_pat_opt(p.pat());
472 let mutability = Mutability::from_mutable(p.is_mut());
473 Pat::Ref { pat, mutability }
474 }
475 ast::Pat::PathPat(p) => {
476 let path = p.path().and_then(Path::from_ast);
477 path.map(Pat::Path).unwrap_or(Pat::Missing)
478 }
479 ast::Pat::TuplePat(p) => {
480 let args = p.args().map(|p| self.collect_pat(p)).collect();
481 Pat::Tuple(args)
482 }
483 ast::Pat::PlaceholderPat(_) => Pat::Wild,
484 ast::Pat::RecordPat(p) => {
485 let path = p.path().and_then(Path::from_ast);
486 let record_field_pat_list =
487 p.record_field_pat_list().expect("every struct should have a field list");
488 let mut fields: Vec<_> = record_field_pat_list
489 .bind_pats()
490 .filter_map(|bind_pat| {
491 let ast_pat =
492 ast::Pat::cast(bind_pat.syntax().clone()).expect("bind pat is a pat");
493 let pat = self.collect_pat(ast_pat);
494 let name = bind_pat.name()?.as_name();
495 Some(RecordFieldPat { name, pat })
496 })
497 .collect();
498 let iter = record_field_pat_list.record_field_pats().filter_map(|f| {
499 let ast_pat = f.pat()?;
500 let pat = self.collect_pat(ast_pat);
501 let name = f.name()?.as_name();
502 Some(RecordFieldPat { name, pat })
503 });
504 fields.extend(iter);
505
506 Pat::Record { path, args: fields }
507 }
508
509 // FIXME: implement
510 ast::Pat::BoxPat(_) => Pat::Missing,
511 ast::Pat::LiteralPat(_) => Pat::Missing,
512 ast::Pat::SlicePat(_) | ast::Pat::RangePat(_) => Pat::Missing,
513 };
514 let ptr = AstPtr::new(&pat);
515 self.alloc_pat(pattern, Either::A(ptr))
516 }
517
518 fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
519 if let Some(pat) = pat {
520 self.collect_pat(pat)
521 } else {
522 self.pats.alloc(Pat::Missing)
523 }
524 }
525
526 fn collect_const_body(&mut self, node: ast::ConstDef) {
527 let body = self.collect_expr_opt(node.body());
528 self.body_expr = Some(body);
529 }
530
531 fn collect_static_body(&mut self, node: ast::StaticDef) {
532 let body = self.collect_expr_opt(node.body());
533 self.body_expr = Some(body);
534 }
535
536 fn collect_fn_body(&mut self, node: ast::FnDef) {
537 if let Some(param_list) = node.param_list() {
538 if let Some(self_param) = param_list.self_param() {
539 let ptr = AstPtr::new(&self_param);
540 let param_pat = self.alloc_pat(
541 Pat::Bind {
542 name: SELF_PARAM,
543 mode: BindingAnnotation::Unannotated,
544 subpat: None,
545 },
546 Either::B(ptr),
547 );
548 self.params.push(param_pat);
549 }
550
551 for param in param_list.params() {
552 let pat = if let Some(pat) = param.pat() {
553 pat
554 } else {
555 continue;
556 };
557 let param_pat = self.collect_pat(pat);
558 self.params.push(param_pat);
559 }
560 };
561
562 let body = self.collect_block_opt(node.body());
563 self.body_expr = Some(body);
564 }
565
566 fn finish(self) -> (Body, BodySourceMap) {
567 let body = Body {
568 owner: self.owner,
569 exprs: self.exprs,
570 pats: self.pats,
571 params: self.params,
572 body_expr: self.body_expr.expect("A body should have been collected"),
573 };
574 (body, self.source_map)
575 }
576}
577
578impl From<ast::BinOp> for BinaryOp {
579 fn from(ast_op: ast::BinOp) -> Self {
580 match ast_op {
581 ast::BinOp::BooleanOr => BinaryOp::LogicOp(LogicOp::Or),
582 ast::BinOp::BooleanAnd => BinaryOp::LogicOp(LogicOp::And),
583 ast::BinOp::EqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: false }),
584 ast::BinOp::NegatedEqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: true }),
585 ast::BinOp::LesserEqualTest => {
586 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: false })
587 }
588 ast::BinOp::GreaterEqualTest => {
589 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: false })
590 }
591 ast::BinOp::LesserTest => {
592 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: true })
593 }
594 ast::BinOp::GreaterTest => {
595 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: true })
596 }
597 ast::BinOp::Addition => BinaryOp::ArithOp(ArithOp::Add),
598 ast::BinOp::Multiplication => BinaryOp::ArithOp(ArithOp::Mul),
599 ast::BinOp::Subtraction => BinaryOp::ArithOp(ArithOp::Sub),
600 ast::BinOp::Division => BinaryOp::ArithOp(ArithOp::Div),
601 ast::BinOp::Remainder => BinaryOp::ArithOp(ArithOp::Rem),
602 ast::BinOp::LeftShift => BinaryOp::ArithOp(ArithOp::Shl),
603 ast::BinOp::RightShift => BinaryOp::ArithOp(ArithOp::Shr),
604 ast::BinOp::BitwiseXor => BinaryOp::ArithOp(ArithOp::BitXor),
605 ast::BinOp::BitwiseOr => BinaryOp::ArithOp(ArithOp::BitOr),
606 ast::BinOp::BitwiseAnd => BinaryOp::ArithOp(ArithOp::BitAnd),
607 ast::BinOp::Assignment => BinaryOp::Assignment { op: None },
608 ast::BinOp::AddAssign => BinaryOp::Assignment { op: Some(ArithOp::Add) },
609 ast::BinOp::DivAssign => BinaryOp::Assignment { op: Some(ArithOp::Div) },
610 ast::BinOp::MulAssign => BinaryOp::Assignment { op: Some(ArithOp::Mul) },
611 ast::BinOp::RemAssign => BinaryOp::Assignment { op: Some(ArithOp::Rem) },
612 ast::BinOp::ShlAssign => BinaryOp::Assignment { op: Some(ArithOp::Shl) },
613 ast::BinOp::ShrAssign => BinaryOp::Assignment { op: Some(ArithOp::Shr) },
614 ast::BinOp::SubAssign => BinaryOp::Assignment { op: Some(ArithOp::Sub) },
615 ast::BinOp::BitOrAssign => BinaryOp::Assignment { op: Some(ArithOp::BitOr) },
616 ast::BinOp::BitAndAssign => BinaryOp::Assignment { op: Some(ArithOp::BitAnd) },
617 ast::BinOp::BitXorAssign => BinaryOp::Assignment { op: Some(ArithOp::BitXor) },
618 }
619 }
620}
621
622pub(crate) fn body_with_source_map_query(
623 db: &impl HirDatabase,
624 def: DefWithBody,
625) -> (Arc<Body>, Arc<BodySourceMap>) {
626 let mut collector;
627
628 match def {
629 DefWithBody::Const(ref c) => {
630 let src = c.source(db);
631 collector = ExprCollector::new(def, src.file_id, def.resolver(db), db);
632 collector.collect_const_body(src.ast)
633 }
634 DefWithBody::Function(ref f) => {
635 let src = f.source(db);
636 collector = ExprCollector::new(def, src.file_id, def.resolver(db), db);
637 collector.collect_fn_body(src.ast)
638 }
639 DefWithBody::Static(ref s) => {
640 let src = s.source(db);
641 collector = ExprCollector::new(def, src.file_id, def.resolver(db), db);
642 collector.collect_static_body(src.ast)
643 }
644 }
645
646 let (body, source_map) = collector.finish();
647 (Arc::new(body), Arc::new(source_map))
648}
649
650pub(crate) fn body_hir_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<Body> {
651 db.body_with_source_map(def).0
652}