aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Daniel Faria <[email protected]>2020-05-28 03:21:20 +0100
committerPaul Daniel Faria <[email protected]>2020-06-27 15:10:26 +0100
commit7f2219dc76d6cddc46eadb2b2dd674795e0efce8 (patch)
tree7c2dbb2ea490684de4f49d28fb1c3928f1194728
parent9ce44be2ab7e9a99eece1c2e254f15ad1c6d73c5 (diff)
Track expr parents during lowering, use parent map when checking if unsafe exprs are within unsafe blocks
-rw-r--r--crates/ra_hir_def/src/body.rs1
-rw-r--r--crates/ra_hir_def/src/body/lower.rs252
-rw-r--r--crates/ra_hir_ty/src/expr.rs22
-rw-r--r--crates/ra_hir_ty/src/tests.rs2
4 files changed, 177 insertions, 100 deletions
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs
index 4f2350915..076d1a4fa 100644
--- a/crates/ra_hir_def/src/body.rs
+++ b/crates/ra_hir_def/src/body.rs
@@ -184,6 +184,7 @@ pub struct Body {
184 /// The `ExprId` of the actual body expression. 184 /// The `ExprId` of the actual body expression.
185 pub body_expr: ExprId, 185 pub body_expr: ExprId,
186 pub item_scope: ItemScope, 186 pub item_scope: ItemScope,
187 pub parent_map: FxHashMap<ExprId, ExprId>,
187} 188}
188 189
189pub type ExprPtr = AstPtr<ast::Expr>; 190pub type ExprPtr = AstPtr<ast::Expr>;
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index 6eb72e950..a1678adeb 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -15,6 +15,7 @@ use ra_syntax::{
15 }, 15 },
16 AstNode, AstPtr, 16 AstNode, AstPtr,
17}; 17};
18use rustc_hash::FxHashMap;
18use test_utils::mark; 19use test_utils::mark;
19 20
20use crate::{ 21use crate::{
@@ -74,6 +75,7 @@ pub(super) fn lower(
74 params: Vec::new(), 75 params: Vec::new(),
75 body_expr: dummy_expr_id(), 76 body_expr: dummy_expr_id(),
76 item_scope: Default::default(), 77 item_scope: Default::default(),
78 parent_map: FxHashMap::default(),
77 }, 79 },
78 item_trees: { 80 item_trees: {
79 let mut map = FxHashMap::default(); 81 let mut map = FxHashMap::default();
@@ -171,11 +173,28 @@ impl ExprCollector<'_> {
171 id 173 id
172 } 174 }
173 175
176 fn update_parent_map(
177 &mut self,
178 (parent_expr, children_exprs): (ExprId, Vec<ExprId>),
179 ) -> ExprId {
180 for child_expr in children_exprs {
181 self.body.parent_map.insert(child_expr, parent_expr);
182 }
183
184 parent_expr
185 }
186
174 fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { 187 fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
188 let parent_and_children = self.collect_expr_inner(expr);
189 self.update_parent_map(parent_and_children)
190 }
191
192 fn collect_expr_inner(&mut self, expr: ast::Expr) -> (ExprId, Vec<ExprId>) {
175 let syntax_ptr = AstPtr::new(&expr); 193 let syntax_ptr = AstPtr::new(&expr);
176 if !self.expander.is_cfg_enabled(&expr) { 194 if !self.expander.is_cfg_enabled(&expr) {
177 return self.missing_expr(); 195 return (self.missing_expr(), vec![]);
178 } 196 }
197
179 match expr { 198 match expr {
180 ast::Expr::IfExpr(e) => { 199 ast::Expr::IfExpr(e) => {
181 let then_branch = self.collect_block_opt(e.then_branch()); 200 let then_branch = self.collect_block_opt(e.then_branch());
@@ -205,32 +224,48 @@ impl ExprCollector<'_> {
205 guard: None, 224 guard: None,
206 }, 225 },
207 ]; 226 ];
208 return self 227 let children_exprs = if let Some(else_branch) = else_branch {
209 .alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr); 228 vec![match_expr, then_branch, else_branch]
229 } else {
230 vec![match_expr, then_branch]
231 };
232 return (
233 self.alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr),
234 children_exprs,
235 );
210 } 236 }
211 }, 237 },
212 }; 238 };
213 239
214 self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr) 240 let children_exprs = if let Some(else_branch) = else_branch {
241 vec![then_branch, else_branch, condition]
242 } else {
243 vec![then_branch, condition]
244 };
245
246 (
247 self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr),
248 children_exprs,
249 )
215 } 250 }
216 ast::Expr::EffectExpr(e) => match e.effect() { 251 ast::Expr::EffectExpr(e) => match e.effect() {
217 ast::Effect::Try(_) => { 252 ast::Effect::Try(_) => {
218 let body = self.collect_block_opt(e.block_expr()); 253 let body = self.collect_block_opt(e.block_expr());
219 self.alloc_expr(Expr::TryBlock { body }, syntax_ptr) 254 (self.alloc_expr(Expr::TryBlock { body }, syntax_ptr), vec![body])
220 } 255 }
221 ast::Effect::Unsafe(_) => { 256 ast::Effect::Unsafe(_) => {
222 let body = self.collect_block_opt(e.block_expr()); 257 let body = self.collect_block_opt(e.block_expr());
223 self.alloc_expr(Expr::Unsafe { body }, syntax_ptr) 258 (self.alloc_expr(Expr::Unsafe { body }, syntax_ptr), vec![body])
224 } 259 }
225 // FIXME: we need to record these effects somewhere... 260 // FIXME: we need to record these effects somewhere...
226 ast::Effect::Async(_) | ast::Effect::Label(_) => { 261 ast::Effect::Async(_) | ast::Effect::Label(_) => {
227 self.collect_block_opt(e.block_expr()) 262 (self.collect_block_opt(e.block_expr()), vec![])
228 } 263 }
229 }, 264 },
230 ast::Expr::BlockExpr(e) => self.collect_block(e), 265 ast::Expr::BlockExpr(e) => (self.collect_block(e), vec![]),
231 ast::Expr::LoopExpr(e) => { 266 ast::Expr::LoopExpr(e) => {
232 let body = self.collect_block_opt(e.loop_body()); 267 let body = self.collect_block_opt(e.loop_body());
233 self.alloc_expr( 268 (self.alloc_expr(
234 Expr::Loop { 269 Expr::Loop {
235 body, 270 body,
236 label: e 271 label: e
@@ -239,7 +274,7 @@ impl ExprCollector<'_> {
239 .map(|l| Name::new_lifetime(&l)), 274 .map(|l| Name::new_lifetime(&l)),
240 }, 275 },
241 syntax_ptr, 276 syntax_ptr,
242 ) 277 ), vec![body])
243 } 278 }
244 ast::Expr::WhileExpr(e) => { 279 ast::Expr::WhileExpr(e) => {
245 let body = self.collect_block_opt(e.loop_body()); 280 let body = self.collect_block_opt(e.loop_body());
@@ -250,6 +285,7 @@ impl ExprCollector<'_> {
250 None => self.collect_expr_opt(condition.expr()), 285 None => self.collect_expr_opt(condition.expr()),
251 // if let -- desugar to match 286 // if let -- desugar to match
252 Some(pat) => { 287 Some(pat) => {
288 // FIXME(pfaria) track the break and arms parents here?
253 mark::hit!(infer_resolve_while_let); 289 mark::hit!(infer_resolve_while_let);
254 let pat = self.collect_pat(pat); 290 let pat = self.collect_pat(pat);
255 let match_expr = self.collect_expr_opt(condition.expr()); 291 let match_expr = self.collect_expr_opt(condition.expr());
@@ -262,7 +298,7 @@ impl ExprCollector<'_> {
262 ]; 298 ];
263 let match_expr = 299 let match_expr =
264 self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms }); 300 self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms });
265 return self.alloc_expr( 301 return (self.alloc_expr(
266 Expr::Loop { 302 Expr::Loop {
267 body: match_expr, 303 body: match_expr,
268 label: e 304 label: e
@@ -271,12 +307,12 @@ impl ExprCollector<'_> {
271 .map(|l| Name::new_lifetime(&l)), 307 .map(|l| Name::new_lifetime(&l)),
272 }, 308 },
273 syntax_ptr, 309 syntax_ptr,
274 ); 310 ), vec![match_expr]);
275 } 311 }
276 }, 312 },
277 }; 313 };
278 314
279 self.alloc_expr( 315 (self.alloc_expr(
280 Expr::While { 316 Expr::While {
281 condition, 317 condition,
282 body, 318 body,
@@ -286,13 +322,13 @@ impl ExprCollector<'_> {
286 .map(|l| Name::new_lifetime(&l)), 322 .map(|l| Name::new_lifetime(&l)),
287 }, 323 },
288 syntax_ptr, 324 syntax_ptr,
289 ) 325 ), vec![body, condition])
290 } 326 }
291 ast::Expr::ForExpr(e) => { 327 ast::Expr::ForExpr(e) => {
292 let iterable = self.collect_expr_opt(e.iterable()); 328 let iterable = self.collect_expr_opt(e.iterable());
293 let pat = self.collect_pat_opt(e.pat()); 329 let pat = self.collect_pat_opt(e.pat());
294 let body = self.collect_block_opt(e.loop_body()); 330 let body = self.collect_block_opt(e.loop_body());
295 self.alloc_expr( 331 (self.alloc_expr(
296 Expr::For { 332 Expr::For {
297 iterable, 333 iterable,
298 pat, 334 pat,
@@ -303,7 +339,7 @@ impl ExprCollector<'_> {
303 .map(|l| Name::new_lifetime(&l)), 339 .map(|l| Name::new_lifetime(&l)),
304 }, 340 },
305 syntax_ptr, 341 syntax_ptr,
306 ) 342 ), vec![iterable, body])
307 } 343 }
308 ast::Expr::CallExpr(e) => { 344 ast::Expr::CallExpr(e) => {
309 let callee = self.collect_expr_opt(e.expr()); 345 let callee = self.collect_expr_opt(e.expr());
@@ -312,41 +348,56 @@ impl ExprCollector<'_> {
312 } else { 348 } else {
313 Vec::new() 349 Vec::new()
314 }; 350 };
315 self.alloc_expr(Expr::Call { callee, args }, syntax_ptr) 351 let mut children_exprs = args.clone();
352 children_exprs.push(callee);
353 (self.alloc_expr(Expr::Call { callee, args }, syntax_ptr), children_exprs)
316 } 354 }
317 ast::Expr::MethodCallExpr(e) => { 355 ast::Expr::MethodCallExpr(e) => {
318 let receiver = self.collect_expr_opt(e.expr()); 356 let receiver = self.collect_expr_opt(e.expr());
319 let args = if let Some(arg_list) = e.arg_list() { 357 let args = if let Some(arg_list) = e.arg_list() {
320 arg_list.args().map(|e| self.collect_expr(e)).collect() 358 arg_list.args().map(|e| self.collect_expr(e)).collect()
321 } else { 359 } else {
322 Vec::new() 360 vec![]
323 }; 361 };
324 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); 362 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
325 let generic_args = 363 let generic_args =
326 e.type_arg_list().and_then(|it| GenericArgs::from_ast(&self.ctx(), it)); 364 e.type_arg_list().and_then(|it| GenericArgs::from_ast(&self.ctx(), it));
327 self.alloc_expr( 365 let mut children_exprs = args.clone();
328 Expr::MethodCall { receiver, method_name, args, generic_args }, 366 children_exprs.push(receiver);
329 syntax_ptr, 367 (
368 self.alloc_expr(
369 Expr::MethodCall { receiver, method_name, args, generic_args },
370 syntax_ptr,
371 ),
372 children_exprs,
330 ) 373 )
331 } 374 }
332 ast::Expr::MatchExpr(e) => { 375 ast::Expr::MatchExpr(e) => {
333 let expr = self.collect_expr_opt(e.expr()); 376 let expr = self.collect_expr_opt(e.expr());
334 let arms = if let Some(match_arm_list) = e.match_arm_list() { 377 let (arms, mut children_exprs): (Vec<_>, Vec<_>) =
335 match_arm_list 378 if let Some(match_arm_list) = e.match_arm_list() {
336 .arms() 379 match_arm_list
337 .map(|arm| MatchArm { 380 .arms()
338 pat: self.collect_pat_opt(arm.pat()), 381 .map(|arm| {
339 expr: self.collect_expr_opt(arm.expr()), 382 let expr = self.collect_expr_opt(arm.expr());
340 guard: arm 383 (
341 .guard() 384 MatchArm {
342 .and_then(|guard| guard.expr()) 385 pat: self.collect_pat_opt(arm.pat()),
343 .map(|e| self.collect_expr(e)), 386 expr,
344 }) 387 guard: arm
345 .collect() 388 .guard()
346 } else { 389 .and_then(|guard| guard.expr())
347 Vec::new() 390 .map(|e| self.collect_expr(e)),
348 }; 391 },
349 self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr) 392 expr,
393 )
394 })
395 .unzip()
396 } else {
397 (vec![], vec![])
398 };
399 children_exprs.push(expr);
400 (self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr), children_exprs)
350 } 401 }
351 ast::Expr::PathExpr(e) => { 402 ast::Expr::PathExpr(e) => {
352 let path = e 403 let path = e
@@ -354,35 +405,35 @@ impl ExprCollector<'_> {
354 .and_then(|path| self.expander.parse_path(path)) 405 .and_then(|path| self.expander.parse_path(path))
355 .map(Expr::Path) 406 .map(Expr::Path)
356 .unwrap_or(Expr::Missing); 407 .unwrap_or(Expr::Missing);
357 self.alloc_expr(path, syntax_ptr) 408 (self.alloc_expr(path, syntax_ptr), vec![])
358 } 409 }
359 ast::Expr::ContinueExpr(e) => self.alloc_expr( 410 ast::Expr::ContinueExpr(e) => (self.alloc_expr(
360 Expr::Continue { label: e.lifetime_token().map(|l| Name::new_lifetime(&l)) }, 411 Expr::Continue { label: e.lifetime_token().map(|l| Name::new_lifetime(&l)) },
361 syntax_ptr, 412 syntax_ptr,
362 ), 413 ), vec![]),
363 ast::Expr::BreakExpr(e) => { 414 ast::Expr::BreakExpr(e) => {
364 let expr = e.expr().map(|e| self.collect_expr(e)); 415 let expr = e.expr().map(|e| self.collect_expr(e));
365 self.alloc_expr( 416 (self.alloc_expr(
366 Expr::Break { expr, label: e.lifetime_token().map(|l| Name::new_lifetime(&l)) }, 417 Expr::Break { expr, label: e.lifetime_token().map(|l| Name::new_lifetime(&l)) },
367 syntax_ptr, 418 syntax_ptr,
368 ) 419 ), expr.into_iter().collect())
369 } 420 }
370 ast::Expr::ParenExpr(e) => { 421 ast::Expr::ParenExpr(e) => {
371 let inner = self.collect_expr_opt(e.expr()); 422 let inner = self.collect_expr_opt(e.expr());
372 // make the paren expr point to the inner expression as well 423 // make the paren expr point to the inner expression as well
373 let src = self.expander.to_source(syntax_ptr); 424 let src = self.expander.to_source(syntax_ptr);
374 self.source_map.expr_map.insert(src, inner); 425 self.source_map.expr_map.insert(src, inner);
375 inner 426 (inner, vec![])
376 } 427 }
377 ast::Expr::ReturnExpr(e) => { 428 ast::Expr::ReturnExpr(e) => {
378 let expr = e.expr().map(|e| self.collect_expr(e)); 429 let expr = e.expr().map(|e| self.collect_expr(e));
379 self.alloc_expr(Expr::Return { expr }, syntax_ptr) 430 (self.alloc_expr(Expr::Return { expr }, syntax_ptr), expr.into_iter().collect())
380 } 431 }
381 ast::Expr::RecordLit(e) => { 432 ast::Expr::RecordLit(e) => {
382 let path = e.path().and_then(|path| self.expander.parse_path(path)); 433 let path = e.path().and_then(|path| self.expander.parse_path(path));
383 let mut field_ptrs = Vec::new(); 434 let mut field_ptrs = Vec::new();
384 let record_lit = if let Some(nfl) = e.record_field_list() { 435 let (record_lit, children) = if let Some(nfl) = e.record_field_list() {
385 let fields = nfl 436 let (fields, children): (Vec<_>, Vec<_>) = nfl
386 .fields() 437 .fields()
387 .inspect(|field| field_ptrs.push(AstPtr::new(field))) 438 .inspect(|field| field_ptrs.push(AstPtr::new(field)))
388 .filter_map(|field| { 439 .filter_map(|field| {
@@ -391,19 +442,20 @@ impl ExprCollector<'_> {
391 } 442 }
392 let name = field.field_name()?.as_name(); 443 let name = field.field_name()?.as_name();
393 444
394 Some(RecordLitField { 445 let expr = match field.expr() {
395 name, 446 Some(e) => self.collect_expr(e),
396 expr: match field.expr() { 447 None => self.missing_expr(),
397 Some(e) => self.collect_expr(e), 448 };
398 None => self.missing_expr(), 449 Some((RecordLitField { name, expr }, expr))
399 },
400 })
401 }) 450 })
402 .collect(); 451 .unzip();
403 let spread = nfl.spread().map(|s| self.collect_expr(s)); 452 let spread = nfl.spread().map(|s| self.collect_expr(s));
404 Expr::RecordLit { path, fields, spread } 453 (
454 Expr::RecordLit { path, fields, spread: spread },
455 children.into_iter().chain(spread.into_iter()).collect(),
456 )
405 } else { 457 } else {
406 Expr::RecordLit { path, fields: Vec::new(), spread: None } 458 (Expr::RecordLit { path, fields: Vec::new(), spread: None }, vec![])
407 }; 459 };
408 460
409 let res = self.alloc_expr(record_lit, syntax_ptr); 461 let res = self.alloc_expr(record_lit, syntax_ptr);
@@ -411,7 +463,7 @@ impl ExprCollector<'_> {
411 let src = self.expander.to_source(ptr); 463 let src = self.expander.to_source(ptr);
412 self.source_map.field_map.insert((res, i), src); 464 self.source_map.field_map.insert((res, i), src);
413 } 465 }
414 res 466 (res, children)
415 } 467 }
416 ast::Expr::FieldExpr(e) => { 468 ast::Expr::FieldExpr(e) => {
417 let expr = self.collect_expr_opt(e.expr()); 469 let expr = self.collect_expr_opt(e.expr());
@@ -419,20 +471,20 @@ impl ExprCollector<'_> {
419 Some(kind) => kind.as_name(), 471 Some(kind) => kind.as_name(),
420 _ => Name::missing(), 472 _ => Name::missing(),
421 }; 473 };
422 self.alloc_expr(Expr::Field { expr, name }, syntax_ptr) 474 (self.alloc_expr(Expr::Field { expr, name }, syntax_ptr), vec![expr])
423 } 475 }
424 ast::Expr::AwaitExpr(e) => { 476 ast::Expr::AwaitExpr(e) => {
425 let expr = self.collect_expr_opt(e.expr()); 477 let expr = self.collect_expr_opt(e.expr());
426 self.alloc_expr(Expr::Await { expr }, syntax_ptr) 478 (self.alloc_expr(Expr::Await { expr }, syntax_ptr), vec![expr])
427 } 479 }
428 ast::Expr::TryExpr(e) => { 480 ast::Expr::TryExpr(e) => {
429 let expr = self.collect_expr_opt(e.expr()); 481 let expr = self.collect_expr_opt(e.expr());
430 self.alloc_expr(Expr::Try { expr }, syntax_ptr) 482 (self.alloc_expr(Expr::Try { expr }, syntax_ptr), vec![expr])
431 } 483 }
432 ast::Expr::CastExpr(e) => { 484 ast::Expr::CastExpr(e) => {
433 let expr = self.collect_expr_opt(e.expr()); 485 let expr = self.collect_expr_opt(e.expr());
434 let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.type_ref()); 486 let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.type_ref());
435 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr) 487 (self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr), vec![expr])
436 } 488 }
437 ast::Expr::RefExpr(e) => { 489 ast::Expr::RefExpr(e) => {
438 let expr = self.collect_expr_opt(e.expr()); 490 let expr = self.collect_expr_opt(e.expr());
@@ -455,9 +507,9 @@ impl ExprCollector<'_> {
455 ast::Expr::PrefixExpr(e) => { 507 ast::Expr::PrefixExpr(e) => {
456 let expr = self.collect_expr_opt(e.expr()); 508 let expr = self.collect_expr_opt(e.expr());
457 if let Some(op) = e.op_kind() { 509 if let Some(op) = e.op_kind() {
458 self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr) 510 (self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr), vec![expr])
459 } else { 511 } else {
460 self.alloc_expr(Expr::Missing, syntax_ptr) 512 (self.alloc_expr(Expr::Missing, syntax_ptr), vec![])
461 } 513 }
462 } 514 }
463 ast::Expr::LambdaExpr(e) => { 515 ast::Expr::LambdaExpr(e) => {
@@ -477,21 +529,24 @@ impl ExprCollector<'_> {
477 .and_then(|r| r.type_ref()) 529 .and_then(|r| r.type_ref())
478 .map(|it| TypeRef::from_ast(&self.ctx(), it)); 530 .map(|it| TypeRef::from_ast(&self.ctx(), it));
479 let body = self.collect_expr_opt(e.body()); 531 let body = self.collect_expr_opt(e.body());
480 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr) 532 (
533 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr),
534 vec![body],
535 )
481 } 536 }
482 ast::Expr::BinExpr(e) => { 537 ast::Expr::BinExpr(e) => {
483 let lhs = self.collect_expr_opt(e.lhs()); 538 let lhs = self.collect_expr_opt(e.lhs());
484 let rhs = self.collect_expr_opt(e.rhs()); 539 let rhs = self.collect_expr_opt(e.rhs());
485 let op = e.op_kind().map(BinaryOp::from); 540 let op = e.op_kind().map(BinaryOp::from);
486 self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr) 541 (self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr), vec![lhs, rhs])
487 } 542 }
488 ast::Expr::TupleExpr(e) => { 543 ast::Expr::TupleExpr(e) => {
489 let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect(); 544 let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect::<Vec<_>>();
490 self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr) 545 (self.alloc_expr(Expr::Tuple { exprs: exprs.clone() }, syntax_ptr), exprs)
491 } 546 }
492 ast::Expr::BoxExpr(e) => { 547 ast::Expr::BoxExpr(e) => {
493 let expr = self.collect_expr_opt(e.expr()); 548 let expr = self.collect_expr_opt(e.expr());
494 self.alloc_expr(Expr::Box { expr }, syntax_ptr) 549 (self.alloc_expr(Expr::Box { expr }, syntax_ptr), vec![expr])
495 } 550 }
496 551
497 ast::Expr::ArrayExpr(e) => { 552 ast::Expr::ArrayExpr(e) => {
@@ -499,34 +554,46 @@ impl ExprCollector<'_> {
499 554
500 match kind { 555 match kind {
501 ArrayExprKind::ElementList(e) => { 556 ArrayExprKind::ElementList(e) => {
502 let exprs = e.map(|expr| self.collect_expr(expr)).collect(); 557 let exprs = e.map(|expr| self.collect_expr(expr)).collect::<Vec<_>>();
503 self.alloc_expr(Expr::Array(Array::ElementList(exprs)), syntax_ptr) 558 (
559 self.alloc_expr(
560 Expr::Array(Array::ElementList(exprs.clone())),
561 syntax_ptr,
562 ),
563 exprs,
564 )
504 } 565 }
505 ArrayExprKind::Repeat { initializer, repeat } => { 566 ArrayExprKind::Repeat { initializer, repeat } => {
506 let initializer = self.collect_expr_opt(initializer); 567 let initializer = self.collect_expr_opt(initializer);
507 let repeat = self.collect_expr_opt(repeat); 568 let repeat = self.collect_expr_opt(repeat);
508 self.alloc_expr( 569 (
509 Expr::Array(Array::Repeat { initializer, repeat }), 570 self.alloc_expr(
510 syntax_ptr, 571 Expr::Array(Array::Repeat { initializer, repeat }),
572 syntax_ptr,
573 ),
574 vec![initializer, repeat],
511 ) 575 )
512 } 576 }
513 } 577 }
514 } 578 }
515 579
516 ast::Expr::Literal(e) => self.alloc_expr(Expr::Literal(e.kind().into()), syntax_ptr), 580 ast::Expr::Literal(e) => {
581 (self.alloc_expr(Expr::Literal(e.kind().into()), syntax_ptr), vec![])
582 }
517 ast::Expr::IndexExpr(e) => { 583 ast::Expr::IndexExpr(e) => {
518 let base = self.collect_expr_opt(e.base()); 584 let base = self.collect_expr_opt(e.base());
519 let index = self.collect_expr_opt(e.index()); 585 let index = self.collect_expr_opt(e.index());
520 self.alloc_expr(Expr::Index { base, index }, syntax_ptr) 586 (self.alloc_expr(Expr::Index { base, index }, syntax_ptr), vec![base, index])
521 } 587 }
522 ast::Expr::RangeExpr(e) => { 588 ast::Expr::RangeExpr(e) => {
523 let lhs = e.start().map(|lhs| self.collect_expr(lhs)); 589 let lhs = e.start().map(|lhs| self.collect_expr(lhs));
524 let rhs = e.end().map(|rhs| self.collect_expr(rhs)); 590 let rhs = e.end().map(|rhs| self.collect_expr(rhs));
525 match e.op_kind() { 591 match e.op_kind() {
526 Some(range_type) => { 592 Some(range_type) => (
527 self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr) 593 self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr),
528 } 594 lhs.into_iter().chain(rhs.into_iter()).collect(),
529 None => self.alloc_expr(Expr::Missing, syntax_ptr), 595 ),
596 None => (self.alloc_expr(Expr::Missing, syntax_ptr), vec![]),
530 } 597 }
531 } 598 }
532 ast::Expr::MacroCall(e) => { 599 ast::Expr::MacroCall(e) => {
@@ -540,7 +607,7 @@ impl ExprCollector<'_> {
540 self.body.item_scope.define_legacy_macro(name, mac); 607 self.body.item_scope.define_legacy_macro(name, mac);
541 608
542 // FIXME: do we still need to allocate this as missing ? 609 // FIXME: do we still need to allocate this as missing ?
543 self.alloc_expr(Expr::Missing, syntax_ptr) 610 (self.alloc_expr(Expr::Missing, syntax_ptr), vec![])
544 } else { 611 } else {
545 let macro_call = self.expander.to_source(AstPtr::new(&e)); 612 let macro_call = self.expander.to_source(AstPtr::new(&e));
546 match self.expander.enter_expand(self.db, Some(&self.body.item_scope), e) { 613 match self.expander.enter_expand(self.db, Some(&self.body.item_scope), e) {
@@ -553,15 +620,15 @@ impl ExprCollector<'_> {
553 self.item_trees.insert(self.expander.current_file_id, item_tree); 620 self.item_trees.insert(self.expander.current_file_id, item_tree);
554 let id = self.collect_expr(expansion); 621 let id = self.collect_expr(expansion);
555 self.expander.exit(self.db, mark); 622 self.expander.exit(self.db, mark);
556 id 623 (id, vec![])
557 } 624 }
558 None => self.alloc_expr(Expr::Missing, syntax_ptr), 625 None => (self.alloc_expr(Expr::Missing, syntax_ptr), vec![]),
559 } 626 }
560 } 627 }
561 } 628 }
562 629
563 // FIXME implement HIR for these: 630 // FIXME implement HIR for these:
564 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 631 ast::Expr::Label(_e) => (self.alloc_expr(Expr::Missing, syntax_ptr), vec![]),
565 } 632 }
566 } 633 }
567 634
@@ -600,9 +667,14 @@ impl ExprCollector<'_> {
600 } 667 }
601 668
602 fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId { 669 fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
670 let parent_and_children = self.collect_block_inner(block);
671 self.update_parent_map(parent_and_children)
672 }
673
674 fn collect_block_inner(&mut self, block: ast::BlockExpr) -> (ExprId, Vec<ExprId>) {
603 let syntax_node_ptr = AstPtr::new(&block.clone().into()); 675 let syntax_node_ptr = AstPtr::new(&block.clone().into());
604 self.collect_block_items(&block); 676 self.collect_block_items(&block);
605 let statements = block 677 let (statements, children_exprs): (Vec<_>, Vec<_>) = block
606 .statements() 678 .statements()
607 .map(|s| match s { 679 .map(|s| match s {
608 ast::Stmt::LetStmt(stmt) => { 680 ast::Stmt::LetStmt(stmt) => {
@@ -610,14 +682,18 @@ impl ExprCollector<'_> {
610 let type_ref = 682 let type_ref =
611 stmt.ascribed_type().map(|it| TypeRef::from_ast(&self.ctx(), it)); 683 stmt.ascribed_type().map(|it| TypeRef::from_ast(&self.ctx(), it));
612 let initializer = stmt.initializer().map(|e| self.collect_expr(e)); 684 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
613 Statement::Let { pat, type_ref, initializer } 685 (Statement::Let { pat, type_ref, initializer }, initializer)
686 }
687 ast::Stmt::ExprStmt(stmt) => {
688 let expr = self.collect_expr_opt(stmt.expr());
689 (Statement::Expr(expr), Some(expr))
614 } 690 }
615 ast::Stmt::ExprStmt(stmt) => Statement::Expr(self.collect_expr_opt(stmt.expr())),
616 }) 691 })
617 .collect(); 692 .unzip();
618 let tail = block.expr().map(|e| self.collect_expr(e)); 693 let tail = block.expr().map(|e| self.collect_expr(e));
619 let label = block.label().and_then(|l| l.lifetime_token()).map(|t| Name::new_lifetime(&t)); 694 let label = block.label().and_then(|l| l.lifetime_token()).map(|t| Name::new_lifetime(&t));
620 self.alloc_expr(Expr::Block { statements, tail, label }, syntax_node_ptr) 695 let children_exprs = children_exprs.into_iter().flatten().chain(tail.into_iter()).collect();
696 (self.alloc_expr(Expr::Block { statements, tail, label }, syntax_node_ptr), children_exprs)
621 } 697 }
622 698
623 fn collect_block_items(&mut self, block: &ast::BlockExpr) { 699 fn collect_block_items(&mut self, block: &ast::BlockExpr) {
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs
index 5f332aadb..3942aada5 100644
--- a/crates/ra_hir_ty/src/expr.rs
+++ b/crates/ra_hir_ty/src/expr.rs
@@ -333,15 +333,12 @@ pub fn unsafe_expressions(
333 def: DefWithBodyId, 333 def: DefWithBodyId,
334) -> Vec<UnsafeExpr> { 334) -> Vec<UnsafeExpr> {
335 let mut unsafe_exprs = vec![]; 335 let mut unsafe_exprs = vec![];
336 let mut unsafe_block_scopes = vec![]; 336 let mut unsafe_block_exprs = FxHashSet::default();
337 let body = db.body(def); 337 let body = db.body(def);
338 let expr_scopes = db.expr_scopes(def);
339 for (id, expr) in body.exprs.iter() { 338 for (id, expr) in body.exprs.iter() {
340 match expr { 339 match expr {
341 Expr::Unsafe { body } => { 340 Expr::Unsafe { .. } => {
342 if let Some(scope) = expr_scopes.scope_for(*body) { 341 unsafe_block_exprs.insert(id);
343 unsafe_block_scopes.push(scope);
344 }
345 } 342 }
346 Expr::Call { callee, .. } => { 343 Expr::Call { callee, .. } => {
347 let ty = &infer[*callee]; 344 let ty = &infer[*callee];
@@ -374,12 +371,13 @@ pub fn unsafe_expressions(
374 } 371 }
375 372
376 'unsafe_exprs: for unsafe_expr in &mut unsafe_exprs { 373 'unsafe_exprs: for unsafe_expr in &mut unsafe_exprs {
377 let scope = expr_scopes.scope_for(unsafe_expr.expr); 374 let mut child = unsafe_expr.expr;
378 for scope in expr_scopes.scope_chain(scope) { 375 while let Some(parent) = body.parent_map.get(&child) {
379 if unsafe_block_scopes.contains(&scope) { 376 if unsafe_block_exprs.contains(parent) {
380 unsafe_expr.inside_unsafe_block = true; 377 unsafe_expr.inside_unsafe_block = true;
381 continue 'unsafe_exprs; 378 continue 'unsafe_exprs;
382 } 379 }
380 child = *parent;
383 } 381 }
384 } 382 }
385 383
@@ -417,8 +415,10 @@ impl<'a, 'b> UnsafeValidator<'a, 'b> {
417 415
418 let (_, body_source) = db.body_with_source_map(def); 416 let (_, body_source) = db.body_with_source_map(def);
419 for unsafe_expr in unsafe_expressions { 417 for unsafe_expr in unsafe_expressions {
420 if let Ok(in_file) = body_source.as_ref().expr_syntax(unsafe_expr.expr) { 418 if !unsafe_expr.inside_unsafe_block {
421 self.sink.push(MissingUnsafe { file: in_file.file_id, expr: in_file.value }) 419 if let Ok(in_file) = body_source.as_ref().expr_syntax(unsafe_expr.expr) {
420 self.sink.push(MissingUnsafe { file: in_file.file_id, expr: in_file.value })
421 }
422 } 422 }
423 } 423 }
424 } 424 }
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 26b3aeb50..496cb428b 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -638,7 +638,7 @@ fn nothing_to_see_move_along() {
638 .diagnostics() 638 .diagnostics()
639 .0; 639 .0;
640 640
641 assert_snapshot!(diagnostics, @""); 641 assert_snapshot!(diagnostics, @r#""*x": This operation is unsafe and requires an unsafe function or block"#);
642} 642}
643 643
644#[test] 644#[test]