mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-11-03 13:13:18 +00:00 
			
		
		
		
	fix: Fix expression scopes not being calculated for inline consts
This commit is contained in:
		
							parent
							
								
									ec941e599a
								
							
						
					
					
						commit
						ac389ce2ef
					
				@ -7,7 +7,7 @@ use crate::{
 | 
			
		||||
    body::Body,
 | 
			
		||||
    db::DefDatabase,
 | 
			
		||||
    hir::{Binding, BindingId, Expr, ExprId, LabelId, Pat, PatId, Statement},
 | 
			
		||||
    BlockId, DefWithBodyId,
 | 
			
		||||
    BlockId, ConstBlockId, DefWithBodyId,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub type ScopeId = Idx<ScopeData>;
 | 
			
		||||
@ -46,7 +46,9 @@ pub struct ScopeData {
 | 
			
		||||
impl ExprScopes {
 | 
			
		||||
    pub(crate) fn expr_scopes_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<ExprScopes> {
 | 
			
		||||
        let body = db.body(def);
 | 
			
		||||
        let mut scopes = ExprScopes::new(&body);
 | 
			
		||||
        let mut scopes = ExprScopes::new(&body, |const_block| {
 | 
			
		||||
            db.lookup_intern_anonymous_const(const_block).root
 | 
			
		||||
        });
 | 
			
		||||
        scopes.shrink_to_fit();
 | 
			
		||||
        Arc::new(scopes)
 | 
			
		||||
    }
 | 
			
		||||
@ -89,7 +91,10 @@ fn empty_entries(idx: usize) -> IdxRange<ScopeEntry> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ExprScopes {
 | 
			
		||||
    fn new(body: &Body) -> ExprScopes {
 | 
			
		||||
    fn new(
 | 
			
		||||
        body: &Body,
 | 
			
		||||
        resolve_const_block: impl (Fn(ConstBlockId) -> ExprId) + Copy,
 | 
			
		||||
    ) -> ExprScopes {
 | 
			
		||||
        let mut scopes = ExprScopes {
 | 
			
		||||
            scopes: Arena::default(),
 | 
			
		||||
            scope_entries: Arena::default(),
 | 
			
		||||
@ -100,7 +105,7 @@ impl ExprScopes {
 | 
			
		||||
            scopes.add_bindings(body, root, self_param);
 | 
			
		||||
        }
 | 
			
		||||
        scopes.add_params_bindings(body, root, &body.params);
 | 
			
		||||
        compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root);
 | 
			
		||||
        compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root, resolve_const_block);
 | 
			
		||||
        scopes
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -183,35 +188,46 @@ fn compute_block_scopes(
 | 
			
		||||
    body: &Body,
 | 
			
		||||
    scopes: &mut ExprScopes,
 | 
			
		||||
    scope: &mut ScopeId,
 | 
			
		||||
    resolve_const_block: impl (Fn(ConstBlockId) -> ExprId) + Copy,
 | 
			
		||||
) {
 | 
			
		||||
    for stmt in statements {
 | 
			
		||||
        match stmt {
 | 
			
		||||
            Statement::Let { pat, initializer, else_branch, .. } => {
 | 
			
		||||
                if let Some(expr) = initializer {
 | 
			
		||||
                    compute_expr_scopes(*expr, body, scopes, scope);
 | 
			
		||||
                    compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block);
 | 
			
		||||
                }
 | 
			
		||||
                if let Some(expr) = else_branch {
 | 
			
		||||
                    compute_expr_scopes(*expr, body, scopes, scope);
 | 
			
		||||
                    compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                *scope = scopes.new_scope(*scope);
 | 
			
		||||
                scopes.add_pat_bindings(body, *scope, *pat);
 | 
			
		||||
            }
 | 
			
		||||
            Statement::Expr { expr, .. } => {
 | 
			
		||||
                compute_expr_scopes(*expr, body, scopes, scope);
 | 
			
		||||
                compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block);
 | 
			
		||||
            }
 | 
			
		||||
            Statement::Item => (),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if let Some(expr) = tail {
 | 
			
		||||
        compute_expr_scopes(expr, body, scopes, scope);
 | 
			
		||||
        compute_expr_scopes(expr, body, scopes, scope, resolve_const_block);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: &mut ScopeId) {
 | 
			
		||||
fn compute_expr_scopes(
 | 
			
		||||
    expr: ExprId,
 | 
			
		||||
    body: &Body,
 | 
			
		||||
    scopes: &mut ExprScopes,
 | 
			
		||||
    scope: &mut ScopeId,
 | 
			
		||||
    resolve_const_block: impl (Fn(ConstBlockId) -> ExprId) + Copy,
 | 
			
		||||
) {
 | 
			
		||||
    let make_label =
 | 
			
		||||
        |label: &Option<LabelId>| label.map(|label| (label, body.labels[label].name.clone()));
 | 
			
		||||
 | 
			
		||||
    let compute_expr_scopes = |scopes: &mut ExprScopes, expr: ExprId, scope: &mut ScopeId| {
 | 
			
		||||
        compute_expr_scopes(expr, body, scopes, scope, resolve_const_block)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    scopes.set_scope(expr, *scope);
 | 
			
		||||
    match &body[expr] {
 | 
			
		||||
        Expr::Block { statements, tail, id, label } => {
 | 
			
		||||
@ -219,53 +235,54 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
 | 
			
		||||
            // Overwrite the old scope for the block expr, so that every block scope can be found
 | 
			
		||||
            // via the block itself (important for blocks that only contain items, no expressions).
 | 
			
		||||
            scopes.set_scope(expr, scope);
 | 
			
		||||
            compute_block_scopes(statements, *tail, body, scopes, &mut scope);
 | 
			
		||||
            compute_block_scopes(statements, *tail, body, scopes, &mut scope, resolve_const_block);
 | 
			
		||||
        }
 | 
			
		||||
        Expr::Const(_) => {
 | 
			
		||||
            // FIXME: This is broken.
 | 
			
		||||
        Expr::Const(id) => {
 | 
			
		||||
            let mut scope = scopes.root_scope();
 | 
			
		||||
            compute_expr_scopes(scopes, resolve_const_block(*id), &mut scope);
 | 
			
		||||
        }
 | 
			
		||||
        Expr::Unsafe { id, statements, tail } | Expr::Async { id, statements, tail } => {
 | 
			
		||||
            let mut scope = scopes.new_block_scope(*scope, *id, None);
 | 
			
		||||
            // Overwrite the old scope for the block expr, so that every block scope can be found
 | 
			
		||||
            // via the block itself (important for blocks that only contain items, no expressions).
 | 
			
		||||
            scopes.set_scope(expr, scope);
 | 
			
		||||
            compute_block_scopes(statements, *tail, body, scopes, &mut scope);
 | 
			
		||||
            compute_block_scopes(statements, *tail, body, scopes, &mut scope, resolve_const_block);
 | 
			
		||||
        }
 | 
			
		||||
        Expr::Loop { body: body_expr, label } => {
 | 
			
		||||
            let mut scope = scopes.new_labeled_scope(*scope, make_label(label));
 | 
			
		||||
            compute_expr_scopes(*body_expr, body, scopes, &mut scope);
 | 
			
		||||
            compute_expr_scopes(scopes, *body_expr, &mut scope);
 | 
			
		||||
        }
 | 
			
		||||
        Expr::Closure { args, body: body_expr, .. } => {
 | 
			
		||||
            let mut scope = scopes.new_scope(*scope);
 | 
			
		||||
            scopes.add_params_bindings(body, scope, args);
 | 
			
		||||
            compute_expr_scopes(*body_expr, body, scopes, &mut scope);
 | 
			
		||||
            compute_expr_scopes(scopes, *body_expr, &mut scope);
 | 
			
		||||
        }
 | 
			
		||||
        Expr::Match { expr, arms } => {
 | 
			
		||||
            compute_expr_scopes(*expr, body, scopes, scope);
 | 
			
		||||
            compute_expr_scopes(scopes, *expr, scope);
 | 
			
		||||
            for arm in arms.iter() {
 | 
			
		||||
                let mut scope = scopes.new_scope(*scope);
 | 
			
		||||
                scopes.add_pat_bindings(body, scope, arm.pat);
 | 
			
		||||
                if let Some(guard) = arm.guard {
 | 
			
		||||
                    scope = scopes.new_scope(scope);
 | 
			
		||||
                    compute_expr_scopes(guard, body, scopes, &mut scope);
 | 
			
		||||
                    compute_expr_scopes(scopes, guard, &mut scope);
 | 
			
		||||
                }
 | 
			
		||||
                compute_expr_scopes(arm.expr, body, scopes, &mut scope);
 | 
			
		||||
                compute_expr_scopes(scopes, arm.expr, &mut scope);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        &Expr::If { condition, then_branch, else_branch } => {
 | 
			
		||||
            let mut then_branch_scope = scopes.new_scope(*scope);
 | 
			
		||||
            compute_expr_scopes(condition, body, scopes, &mut then_branch_scope);
 | 
			
		||||
            compute_expr_scopes(then_branch, body, scopes, &mut then_branch_scope);
 | 
			
		||||
            compute_expr_scopes(scopes, condition, &mut then_branch_scope);
 | 
			
		||||
            compute_expr_scopes(scopes, then_branch, &mut then_branch_scope);
 | 
			
		||||
            if let Some(else_branch) = else_branch {
 | 
			
		||||
                compute_expr_scopes(else_branch, body, scopes, scope);
 | 
			
		||||
                compute_expr_scopes(scopes, else_branch, scope);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        &Expr::Let { pat, expr } => {
 | 
			
		||||
            compute_expr_scopes(expr, body, scopes, scope);
 | 
			
		||||
            compute_expr_scopes(scopes, expr, scope);
 | 
			
		||||
            *scope = scopes.new_scope(*scope);
 | 
			
		||||
            scopes.add_pat_bindings(body, *scope, pat);
 | 
			
		||||
        }
 | 
			
		||||
        e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)),
 | 
			
		||||
        e => e.walk_child_exprs(|e| compute_expr_scopes(scopes, e, scope)),
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -68,10 +68,10 @@ use crate::{
 | 
			
		||||
pub struct RawVisibilityId(u32);
 | 
			
		||||
 | 
			
		||||
impl RawVisibilityId {
 | 
			
		||||
    pub const PUB: Self = RawVisibilityId(u32::max_value());
 | 
			
		||||
    pub const PRIV_IMPLICIT: Self = RawVisibilityId(u32::max_value() - 1);
 | 
			
		||||
    pub const PRIV_EXPLICIT: Self = RawVisibilityId(u32::max_value() - 2);
 | 
			
		||||
    pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 3);
 | 
			
		||||
    pub const PUB: Self = RawVisibilityId(u32::MAX);
 | 
			
		||||
    pub const PRIV_IMPLICIT: Self = RawVisibilityId(u32::MAX - 1);
 | 
			
		||||
    pub const PRIV_EXPLICIT: Self = RawVisibilityId(u32::MAX - 2);
 | 
			
		||||
    pub const PUB_CRATE: Self = RawVisibilityId(u32::MAX - 3);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Debug for RawVisibilityId {
 | 
			
		||||
 | 
			
		||||
@ -3664,3 +3664,21 @@ fn main() {
 | 
			
		||||
"#,
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn inline_const_expression() {
 | 
			
		||||
    check(
 | 
			
		||||
        r#"
 | 
			
		||||
fn main() {
 | 
			
		||||
    let foo = 0;
 | 
			
		||||
    const {
 | 
			
		||||
        let bar = 1;
 | 
			
		||||
        let unresolved = foo;
 | 
			
		||||
         // ^^^^^^^^^^ type: {unknown}
 | 
			
		||||
        let resolved = bar;
 | 
			
		||||
         // ^^^^^^^^ type: i32
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
"#,
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -77,7 +77,7 @@ pub(crate) fn reorder_impl_items(acc: &mut Assists, ctx: &AssistContext<'_>) ->
 | 
			
		||||
                ast::AssocItem::MacroCall(_) => None,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            name.and_then(|n| ranks.get(&n.to_string()).copied()).unwrap_or(usize::max_value())
 | 
			
		||||
            name.and_then(|n| ranks.get(&n.to_string()).copied()).unwrap_or(usize::MAX)
 | 
			
		||||
        })
 | 
			
		||||
        .collect();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -301,8 +301,8 @@ impl SymbolIndex {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn range_to_map_value(start: usize, end: usize) -> u64 {
 | 
			
		||||
        debug_assert![start <= (std::u32::MAX as usize)];
 | 
			
		||||
        debug_assert![end <= (std::u32::MAX as usize)];
 | 
			
		||||
        debug_assert![start <= (u32::MAX as usize)];
 | 
			
		||||
        debug_assert![end <= (u32::MAX as usize)];
 | 
			
		||||
 | 
			
		||||
        ((start as u64) << 32) | end as u64
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -285,7 +285,7 @@ where
 | 
			
		||||
 | 
			
		||||
impl Default for LruIndex {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self { index: AtomicUsize::new(std::usize::MAX) }
 | 
			
		||||
        Self { index: AtomicUsize::new(usize::MAX) }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -299,11 +299,11 @@ impl LruIndex {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn clear(&self) {
 | 
			
		||||
        self.store(std::usize::MAX);
 | 
			
		||||
        self.store(usize::MAX);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn is_in_lru(&self) -> bool {
 | 
			
		||||
        self.load() != std::usize::MAX
 | 
			
		||||
        self.load() != usize::MAX
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -60,7 +60,7 @@ impl AtomicRevision {
 | 
			
		||||
    /// Increment by 1, returning previous value.
 | 
			
		||||
    pub(crate) fn fetch_then_increment(&self) -> Revision {
 | 
			
		||||
        let v = self.data.fetch_add(1, Ordering::SeqCst);
 | 
			
		||||
        assert!(v != u32::max_value(), "revision overflow");
 | 
			
		||||
        assert!(v != u32::MAX, "revision overflow");
 | 
			
		||||
        Revision::from(v)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user