diff --git a/src/bin/languageserver/mod.rs b/src/bin/languageserver/mod.rs index c961842186..e8dc885056 100644 --- a/src/bin/languageserver/mod.rs +++ b/src/bin/languageserver/mod.rs @@ -368,7 +368,7 @@ struct Builder<'a> { hovers: Vec<(usize, HoverEntry)>, references: Vec<(usize, ReferenceEntry)>, scopes: Vec<(usize, ScopeEntry)>, - top_code_objects: Vec<(usize, (String, Option))>, + top_level_code_objects: Vec<(usize, (String, Option))>, definitions: Definitions, types: Types, @@ -385,7 +385,7 @@ impl<'a> Builder<'a> { hovers: Vec::new(), references: Vec::new(), scopes: Vec::new(), - top_code_objects: Vec::new(), + top_level_code_objects: Vec::new(), definitions: HashMap::new(), types: HashMap::new(), @@ -1325,7 +1325,7 @@ impl<'a> Builder<'a> { } if contract_no.is_none() { - self.top_code_objects.push(( + self.top_level_code_objects.push(( file_no, ( variable.name.clone(), @@ -1435,7 +1435,7 @@ impl<'a> Builder<'a> { ); if enum_decl.contract.is_none() { - self.top_code_objects + self.top_level_code_objects .push((file_no, (enum_decl.name.clone(), Some(di)))); } } @@ -1479,7 +1479,7 @@ impl<'a> Builder<'a> { ); if struct_decl.contract.is_none() { - self.top_code_objects + self.top_level_code_objects .push((file_no, (struct_decl.name.clone(), Some(di)))); } } @@ -1617,26 +1617,61 @@ impl<'a> Builder<'a> { .map(|stmt| stmt.loc()) .unwrap_or(func.loc) .exclusive_end(), + // val: func + // .symtable + // .vars + // .values() + // .map(|val| { + // ( + // val.id.name.clone(), + // get_type_definition(&val.ty).map(|dt| dt.into()), + // ) + // }) + // .collect(), val: func .symtable - .vars - .values() - .map(|val| { - ( - val.id.name.clone(), - get_type_definition(&val.ty).map(|dt| dt.into()), - ) + .names + .first() + .map(|curr_scope| { + curr_scope + .0 + .values() + .filter_map(|pos| { + func.symtable.vars.get(pos).map(|var| { + ( + var.id.name.clone(), + get_type_definition(&var.ty).map(|dt| dt.into()), + ) + }) + }) + .collect_vec() }) - .collect(), + .unwrap(), }, )); if func.contract_no.is_none() { - self.top_code_objects + self.top_level_code_objects .push((file_no, (func.name.clone(), None))) } } + self.scopes.extend(self.ns.scopes.iter().map(|(loc, vars)| { + let file_no = loc.file_no(); + let scope_entry = ScopeEntry { + start: loc.start(), + stop: loc.exclusive_end(), + val: vars + .iter() + .map(|(name, ty)| { + let ty = get_type_definition(ty).map(|dt| dt.into()); + (name.clone(), ty) + }) + .collect_vec(), + }; + (file_no, scope_entry) + })); + for (i, constant) in self.ns.constants.iter().enumerate() { let samptb = symtable::Symtable::new(); self.contract_variable(constant, &samptb, None, i); @@ -1829,7 +1864,7 @@ impl<'a> Builder<'a> { // Contracts can't be defined within other contracts. // So all the contracts are top level objects in a file. - self.top_code_objects + self.top_level_code_objects .push((file_no, (contract.name.clone(), Some(cdi)))); } @@ -1857,7 +1892,7 @@ impl<'a> Builder<'a> { .insert(di.clone(), loc_to_range(&event.loc, file)); if event.contract.is_none() { - self.top_code_objects + self.top_level_code_objects .push((file_no, (event.name.clone(), Some(di)))); } } @@ -1954,7 +1989,7 @@ impl<'a> Builder<'a> { .collect(), ), top_level_code_objects: self - .top_code_objects + .top_level_code_objects .iter_mut() .filter(|co| co.0 == i) .map(|co| { diff --git a/src/sema/ast.rs b/src/sema/ast.rs index 93da5a7fff..a7cab811ea 100644 --- a/src/sema/ast.rs +++ b/src/sema/ast.rs @@ -705,6 +705,8 @@ pub struct Namespace { pub var_constants: HashMap, /// Overrides for hover in the language server pub hover_overrides: HashMap, + + pub scopes: HashMap>, } #[derive(Debug)] diff --git a/src/sema/namespace.rs b/src/sema/namespace.rs index aa9d360ac2..a7e817f323 100644 --- a/src/sema/namespace.rs +++ b/src/sema/namespace.rs @@ -66,6 +66,8 @@ impl Namespace { next_id: 0, var_constants: HashMap::new(), hover_overrides: HashMap::new(), + + scopes: HashMap::new(), }; match target { diff --git a/src/sema/statements.rs b/src/sema/statements.rs index c24e0f7595..b15f6269e1 100644 --- a/src/sema/statements.rs +++ b/src/sema/statements.rs @@ -417,9 +417,9 @@ fn statement( Ok(true) } pt::Statement::Block { + loc, statements, unchecked, - .. } => { symtable.new_scope(); let mut reachable = true; @@ -438,7 +438,20 @@ fn statement( reachable = statement(stmt, res, &mut context, symtable, loops, ns, diagnostics)?; } - symtable.leave_scope(); + // symtable.leave_scope().map(|curr_scope| { + // let curr_scope = curr_scope + // .0 + // .values() + // .filter_map(|pos| { + // symtable + // .vars + // .get(pos) + // .map(|var| (var.id.name.clone(), var.ty.clone())) + // }) + // .collect(); + // ns.scopes.insert(*loc, curr_scope); + // }); + symtable.leave_scope(ns, *loc); Ok(reachable) } @@ -491,7 +504,7 @@ fn statement( ns, diagnostics, )?; - symtable.leave_scope(); + symtable.leave_scope(ns, *loc); loops.leave_scope(); res.push(Statement::While(*loc, true, cond, body_stmts)); @@ -523,7 +536,7 @@ fn statement( ns, diagnostics, )?; - symtable.leave_scope(); + symtable.leave_scope(ns, *loc); loops.leave_scope(); res.push(Statement::DoWhile(*loc, true, body_stmts, cond)); @@ -554,7 +567,7 @@ fn statement( ns, diagnostics, )?; - symtable.leave_scope(); + symtable.leave_scope(ns, *loc); let mut else_stmts = Vec::new(); if let Some(stmts) = else_ { @@ -569,7 +582,7 @@ fn statement( diagnostics, )?; - symtable.leave_scope(); + symtable.leave_scope(ns, *loc); } else { reachable = true; } @@ -634,7 +647,7 @@ fn statement( )?); } - symtable.leave_scope(); + symtable.leave_scope(ns, *loc); res.push(Statement::For { loc: *loc, @@ -713,7 +726,7 @@ fn statement( } } - symtable.leave_scope(); + symtable.leave_scope(ns, *loc); res.push(Statement::For { loc: *loc, @@ -2445,7 +2458,7 @@ fn try_catch( diagnostics, )?; - symtable.leave_scope(); + symtable.leave_scope(ns, *loc); let mut clauses_unique = HashSet::new(); let mut errors_resolved = Vec::new(); @@ -2470,7 +2483,7 @@ fn try_catch( } match clause_stmt { - CatchClause::Simple(_, param, stmt) => { + CatchClause::Simple(catch_loc, param, stmt) => { symtable.new_scope(); let mut catch_param = None; @@ -2536,7 +2549,7 @@ fn try_catch( finally_reachable |= reachable; - symtable.leave_scope(); + symtable.leave_scope(ns, *catch_loc); catch_all = Some(super::ast::CatchClause { param: catch_param, @@ -2546,7 +2559,7 @@ fn try_catch( Ok(()) } - CatchClause::Named(_, id, param, stmt) => { + CatchClause::Named(catch_loc, id, param, stmt) => { if id.name != "Error" && id.name != "Panic" { let message = format!( "only catch 'Error' and 'Panic' are supported, not '{}'", @@ -2626,7 +2639,7 @@ fn try_catch( finally_reachable |= reachable; - symtable.leave_scope(); + symtable.leave_scope(ns, *catch_loc); errors_resolved.push((error_pos, error_param, error_stmt_resolved)); diff --git a/src/sema/symtable.rs b/src/sema/symtable.rs index c8b9c261c3..2600056781 100644 --- a/src/sema/symtable.rs +++ b/src/sema/symtable.rs @@ -78,12 +78,12 @@ pub enum VariableUsage { } #[derive(Debug, Clone)] -struct VarScope(HashMap, Option>); +pub struct VarScope(pub HashMap, Option>); #[derive(Default, Debug, Clone)] pub struct Symtable { pub vars: IndexMap, - names: Vec, + pub names: Vec, pub arguments: Vec>, pub returns: Vec, } @@ -187,8 +187,19 @@ impl Symtable { self.names.push(VarScope(HashMap::new(), None)); } - pub fn leave_scope(&mut self) { - self.names.pop(); + pub fn leave_scope(&mut self, ns: &mut Namespace, loc: pt::Loc) { + if let Some(curr_scope) = self.names.pop() { + let curr_scope = curr_scope + .0 + .values() + .filter_map(|pos| { + self.vars + .get(pos) + .map(|var| (var.id.name.clone(), var.ty.clone())) + }) + .collect(); + ns.scopes.insert(loc, curr_scope); + } } pub fn get_name(&self, pos: usize) -> &str { @@ -245,3 +256,21 @@ impl LoopScopes { } } } + +// impl Namespace { +// pub fn add_scope(&mut self, loc: pt::Loc, scope: Option) { +// symtable.leave_scope().map(|curr_scope| { +// let curr_scope = curr_scope +// .0 +// .values() +// .filter_map(|pos| { +// symtable +// .vars +// .get(pos) +// .map(|var| (var.id.name.clone(), var.ty.clone())) +// }) +// .collect(); +// self.scopes.insert(loc, curr_scope); +// }); +// } +// } diff --git a/src/sema/yul/block.rs b/src/sema/yul/block.rs index d14f9e0489..3240965bd0 100644 --- a/src/sema/yul/block.rs +++ b/src/sema/yul/block.rs @@ -39,7 +39,7 @@ pub fn resolve_yul_block( ); next_reachable &= reachable; - symtable.leave_scope(); + symtable.leave_scope(ns, *loc); function_table.leave_scope(ns); ( diff --git a/src/sema/yul/for_loop.rs b/src/sema/yul/for_loop.rs index 83d912ddc5..010a1122e9 100644 --- a/src/sema/yul/for_loop.rs +++ b/src/sema/yul/for_loop.rs @@ -67,7 +67,7 @@ pub(crate) fn resolve_for_loop( ns, ); - symtable.leave_scope(); + symtable.leave_scope(ns, yul_for.loc); function_table.leave_scope(ns); Ok(( diff --git a/src/sema/yul/mod.rs b/src/sema/yul/mod.rs index ab4a64cbd1..69c35c9c31 100644 --- a/src/sema/yul/mod.rs +++ b/src/sema/yul/mod.rs @@ -46,7 +46,7 @@ pub fn resolve_inline_assembly( ns, ); - symtable.leave_scope(); + symtable.leave_scope(ns, *loc); functions_table.leave_scope(ns); let end = start + functions_table.resolved_functions.len(); ns.yul_functions