Merge #8398
8398: Fix inference with conditionally compiled tails r=flodiebold a=DJMcNab Fixes #8378 Co-authored-by: Daniel McNab <36049421+DJMcNab@users.noreply.github.com>
This commit is contained in:
commit
da80dfc022
@ -205,7 +205,7 @@ fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
|
||||
self.maybe_collect_expr(expr).unwrap_or_else(|| self.missing_expr())
|
||||
}
|
||||
|
||||
/// Returns `None` if the expression is `#[cfg]`d out.
|
||||
/// Returns `None` if and only if the expression is `#[cfg]`d out.
|
||||
fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
|
||||
let syntax_ptr = AstPtr::new(&expr);
|
||||
self.check_cfg(&expr)?;
|
||||
@ -668,7 +668,7 @@ fn collect_stmt(&mut self, s: ast::Stmt) {
|
||||
if self.check_cfg(&stmt).is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
let has_semi = stmt.semicolon_token().is_some();
|
||||
// Note that macro could be expended to multiple statements
|
||||
if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
|
||||
let macro_ptr = AstPtr::new(&m);
|
||||
@ -685,18 +685,19 @@ fn collect_stmt(&mut self, s: ast::Stmt) {
|
||||
statements.statements().for_each(|stmt| this.collect_stmt(stmt));
|
||||
if let Some(expr) = statements.expr() {
|
||||
let expr = this.collect_expr(expr);
|
||||
this.statements_in_scope.push(Statement::Expr(expr));
|
||||
this.statements_in_scope
|
||||
.push(Statement::Expr { expr, has_semi });
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
|
||||
this.statements_in_scope.push(Statement::Expr(expr));
|
||||
this.statements_in_scope.push(Statement::Expr { expr, has_semi });
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
let expr = self.collect_expr_opt(stmt.expr());
|
||||
self.statements_in_scope.push(Statement::Expr(expr));
|
||||
self.statements_in_scope.push(Statement::Expr { expr, has_semi });
|
||||
}
|
||||
}
|
||||
ast::Stmt::Item(item) => {
|
||||
@ -725,8 +726,17 @@ fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
|
||||
let prev_statements = std::mem::take(&mut self.statements_in_scope);
|
||||
|
||||
block.statements().for_each(|s| self.collect_stmt(s));
|
||||
block.tail_expr().and_then(|e| {
|
||||
let expr = self.maybe_collect_expr(e)?;
|
||||
Some(self.statements_in_scope.push(Statement::Expr { expr, has_semi: false }))
|
||||
});
|
||||
|
||||
let tail = block.tail_expr().map(|e| self.collect_expr(e));
|
||||
let mut tail = None;
|
||||
if let Some(Statement::Expr { expr, has_semi: false }) = self.statements_in_scope.last() {
|
||||
tail = Some(*expr);
|
||||
self.statements_in_scope.pop();
|
||||
}
|
||||
let tail = tail;
|
||||
let statements = std::mem::replace(&mut self.statements_in_scope, prev_statements);
|
||||
let syntax_node_ptr = AstPtr::new(&block.into());
|
||||
let expr_id = self.alloc_expr(
|
||||
|
@ -157,7 +157,7 @@ fn compute_block_scopes(
|
||||
scope = scopes.new_scope(scope);
|
||||
scopes.add_bindings(body, scope, *pat);
|
||||
}
|
||||
Statement::Expr(expr) => {
|
||||
Statement::Expr { expr, .. } => {
|
||||
scopes.set_scope(*expr, scope);
|
||||
compute_expr_scopes(*expr, body, scopes, scope);
|
||||
}
|
||||
|
@ -242,7 +242,7 @@ pub struct RecordLitField {
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub enum Statement {
|
||||
Let { pat: PatId, type_ref: Option<Interned<TypeRef>>, initializer: Option<ExprId> },
|
||||
Expr(ExprId),
|
||||
Expr { expr: ExprId, has_semi: bool },
|
||||
}
|
||||
|
||||
impl Expr {
|
||||
@ -265,7 +265,7 @@ pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
|
||||
f(*expr);
|
||||
}
|
||||
}
|
||||
Statement::Expr(e) => f(*e),
|
||||
Statement::Expr { expr: expression, .. } => f(*expression),
|
||||
}
|
||||
}
|
||||
if let Some(expr) = tail {
|
||||
|
@ -83,7 +83,7 @@ pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) {
|
||||
if let Expr::Block { statements, tail, .. } = body_expr {
|
||||
if let Some(t) = tail {
|
||||
self.validate_results_in_tail_expr(body.body_expr, *t, db);
|
||||
} else if let Some(Statement::Expr(id)) = statements.last() {
|
||||
} else if let Some(Statement::Expr { expr: id, .. }) = statements.last() {
|
||||
self.validate_missing_tail_expr(body.body_expr, *id, db);
|
||||
}
|
||||
}
|
||||
|
@ -809,7 +809,7 @@ fn infer_block(
|
||||
let ty = self.resolve_ty_as_possible(ty);
|
||||
self.infer_pat(*pat, &ty, BindingMode::default());
|
||||
}
|
||||
Statement::Expr(expr) => {
|
||||
Statement::Expr { expr, .. } => {
|
||||
self.infer_expr(*expr, &Expectation::none());
|
||||
}
|
||||
}
|
||||
|
@ -1050,3 +1050,52 @@ fn test() {
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cfg_tail() {
|
||||
// https://github.com/rust-analyzer/rust-analyzer/issues/8378
|
||||
check_infer(
|
||||
r#"
|
||||
fn fake_tail(){
|
||||
{ "first" }
|
||||
#[cfg(never)] 9
|
||||
}
|
||||
fn multiple_fake(){
|
||||
{ "fake" }
|
||||
{ "fake" }
|
||||
{ "second" }
|
||||
#[cfg(never)] { 11 }
|
||||
#[cfg(never)] 12;
|
||||
#[cfg(never)] 13
|
||||
}
|
||||
fn no_normal_tail(){
|
||||
{ "third" }
|
||||
#[cfg(never)] 14;
|
||||
#[cfg(never)] 15;
|
||||
}
|
||||
fn no_actual_tail(){
|
||||
{ "fourth" };
|
||||
#[cfg(never)] 14;
|
||||
#[cfg(never)] 15
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
14..53 '{ ...)] 9 }': &str
|
||||
20..31 '{ "first" }': &str
|
||||
22..29 '"first"': &str
|
||||
72..190 '{ ...] 13 }': &str
|
||||
78..88 '{ "fake" }': &str
|
||||
80..86 '"fake"': &str
|
||||
93..103 '{ "fake" }': &str
|
||||
95..101 '"fake"': &str
|
||||
108..120 '{ "second" }': &str
|
||||
110..118 '"second"': &str
|
||||
210..273 '{ ... 15; }': &str
|
||||
216..227 '{ "third" }': &str
|
||||
218..225 '"third"': &str
|
||||
293..357 '{ ...] 15 }': ()
|
||||
299..311 '{ "fourth" }': &str
|
||||
301..309 '"fourth"': &str
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user