From: Lukas Wirth Date: Wed, 23 Jun 2021 15:21:47 +0000 (+0200) Subject: Mark (method-)calls with never type as exit points X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=f283fce59467d20c0bc7247592b27015d0f52e73;p=rust.git Mark (method-)calls with never type as exit points --- diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 3f000088971..3a901cbbf86 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2075,10 +2075,15 @@ fn from_def( pub fn is_unit(&self) -> bool { matches!(self.ty.kind(&Interner), TyKind::Tuple(0, ..)) } + pub fn is_bool(&self) -> bool { matches!(self.ty.kind(&Interner), TyKind::Scalar(Scalar::Bool)) } + pub fn is_never(&self) -> bool { + matches!(self.ty.kind(&Interner), TyKind::Never) + } + pub fn is_mutable_reference(&self) -> bool { matches!(self.ty.kind(&Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..)) } diff --git a/crates/ide/src/highlight_related.rs b/crates/ide/src/highlight_related.rs index 48777223aa2..de918ac86f4 100644 --- a/crates/ide/src/highlight_related.rs +++ b/crates/ide/src/highlight_related.rs @@ -36,7 +36,7 @@ pub(crate) fn highlight_related( })?; match token.kind() { - QUESTION | RETURN_KW | THIN_ARROW => highlight_exit_points(token), + QUESTION | RETURN_KW | THIN_ARROW => highlight_exit_points(sema, token), AWAIT_KW | ASYNC_KW => highlight_yield_points(token), _ => highlight_references(sema, &syntax, position), } @@ -74,8 +74,14 @@ fn highlight_references( Some(res) } -fn highlight_exit_points(token: SyntaxToken) -> Option> { - fn hl(body: Option) -> Option> { +fn highlight_exit_points( + sema: &Semantics, + token: SyntaxToken, +) -> Option> { + fn hl( + sema: &Semantics, + body: Option, + ) -> Option> { let mut highlights = Vec::new(); let body = body?; walk(&body, |node| { @@ -93,9 +99,19 @@ fn hl(body: Option) -> Option> { range: token.text_range(), }); }, - // All the following are different contexts so skip them - ast::EffectExpr(effect) => return effect.async_token().is_some() || effect.try_token().is_some(), - ast::ClosureExpr(__) => return true, + ast::Expr(expr) => match expr { + ast::Expr::MethodCallExpr(_) | ast::Expr::CallExpr(_) | ast::Expr::MacroCall(_) => { + if sema.type_of_expr(&expr).map_or(false, |ty| ty.is_never()) { + highlights.push(DocumentHighlight { + access: None, + range: expr.syntax().text_range(), + }); + } + }, + ast::Expr::EffectExpr(effect) => return effect.async_token().is_some() || effect.try_token().is_some(), + ast::Expr::ClosureExpr(_) => return true, + _ => (), + }, ast::Item(__) => return true, // Don't look into const args ast::Path(__) => return true, @@ -116,10 +132,10 @@ fn hl(body: Option) -> Option> { for anc in token.ancestors() { return match_ast! { match anc { - ast::Fn(fn_) => hl(fn_.body().map(ast::Expr::BlockExpr)), - ast::ClosureExpr(closure) => hl(closure.body()), + ast::Fn(fn_) => hl(sema, fn_.body().map(ast::Expr::BlockExpr)), + ast::ClosureExpr(closure) => hl(sema, closure.body()), ast::EffectExpr(effect) => if effect.async_token().is_some() || effect.try_token().is_some() { - hl(effect.block_expr().map(ast::Expr::BlockExpr)) + hl(sema, effect.block_expr().map(ast::Expr::BlockExpr)) } else { continue; }, @@ -399,6 +415,34 @@ fn foo() -> u32 { foo$0() // ^^^ } +"#, + ); + } + + #[test] + fn test_hl_never_call_is_exit_point() { + check( + r#" +struct Never; +impl Never { + fn never(self) -> ! { loop {} } +} +macro_rules! never { + () => { never() } +} +fn never() -> ! { loop {} } +fn foo() ->$0 u32 { + never(); + // ^^^^^^^ + never!(); + // FIXME sema doesnt give us types for macrocalls + + Never.never(); + // ^^^^^^^^^^^^^ + + 0 + // ^ +} "#, ); }