Add definitions for match statement (#13147)

## Summary

This PR adds definition for match patterns.

## Test Plan

Update the existing test case for match statement symbols to verify that
the definitions are added as well.
This commit is contained in:
Dhruv Manilawala 2024-09-02 14:40:09 +05:30 committed by GitHub
parent 9986397d56
commit 17eb65b26f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 189 additions and 16 deletions

View file

@ -26,7 +26,7 @@ use crate::semantic_index::use_def::{FlowSnapshot, UseDefMapBuilder};
use crate::semantic_index::SemanticIndex;
use crate::Db;
use super::definition::WithItemDefinitionNodeRef;
use super::definition::{MatchPatternDefinitionNodeRef, WithItemDefinitionNodeRef};
pub(super) struct SemanticIndexBuilder<'db> {
// Builder state
@ -600,6 +600,17 @@ where
self.visit_body(body);
self.visit_body(orelse);
}
ast::Stmt::Match(ast::StmtMatch {
subject,
cases,
range: _,
}) => {
self.add_standalone_expression(subject);
self.visit_expr(subject);
for case in cases {
self.visit_match_case(case);
}
}
_ => {
walk_stmt(self, stmt);
}
@ -803,22 +814,77 @@ where
}
fn visit_pattern(&mut self, pattern: &'ast ast::Pattern) {
if let ast::Pattern::MatchAs(ast::PatternMatchAs {
name: Some(name), ..
})
| ast::Pattern::MatchStar(ast::PatternMatchStar {
// The definition visitor will recurse into the pattern so avoid walking it here.
let mut definition_visitor = MatchPatternDefinitionVisitor::new(self, pattern);
definition_visitor.visit_pattern(pattern);
}
}
/// A visitor that adds symbols and definitions for the identifiers in a match pattern.
struct MatchPatternDefinitionVisitor<'a, 'db> {
/// The semantic index builder in which to add the symbols and definitions.
builder: &'a mut SemanticIndexBuilder<'db>,
/// The index of the current node in the pattern.
index: u32,
/// The pattern being visited. This pattern is the outermost pattern that is being visited
/// and is required to add the definitions.
pattern: &'a ast::Pattern,
}
impl<'a, 'db> MatchPatternDefinitionVisitor<'a, 'db> {
fn new(builder: &'a mut SemanticIndexBuilder<'db>, pattern: &'a ast::Pattern) -> Self {
Self {
index: 0,
builder,
pattern,
}
}
fn add_symbol_and_definition(&mut self, identifier: &ast::Identifier) {
let symbol = self
.builder
.add_or_update_symbol(identifier.id().clone(), SymbolFlags::IS_DEFINED);
self.builder.add_definition(
symbol,
MatchPatternDefinitionNodeRef {
pattern: self.pattern,
identifier,
index: self.index,
},
);
}
}
impl<'ast, 'db> Visitor<'ast> for MatchPatternDefinitionVisitor<'_, 'db>
where
'ast: 'db,
{
fn visit_expr(&mut self, expr: &'ast ast::Expr) {
self.builder.visit_expr(expr);
}
fn visit_pattern(&mut self, pattern: &'ast ast::Pattern) {
if let ast::Pattern::MatchStar(ast::PatternMatchStar {
name: Some(name),
range: _,
}) = pattern
{
self.add_symbol_and_definition(name);
}
walk_pattern(self, pattern);
if let ast::Pattern::MatchAs(ast::PatternMatchAs {
name: Some(name), ..
})
| ast::Pattern::MatchMapping(ast::PatternMatchMapping {
rest: Some(name), ..
}) = pattern
{
// TODO(dhruvmanila): Add definition
self.add_or_update_symbol(name.id.clone(), SymbolFlags::IS_DEFINED);
self.add_symbol_and_definition(name);
}
walk_pattern(self, pattern);
self.index += 1;
}
}