Skip to content

Commit 460ce4e

Browse files
authored
Merge pull request #1367 from harehare/feat/type-narrowing
✨ feat: add type predicate-based narrowing for union types in if/elif branches
2 parents 76e5ed6 + b829496 commit 460ce4e

File tree

16 files changed

+2239
-1082
lines changed

16 files changed

+2239
-1082
lines changed

crates/mq-hir/src/hir.rs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -227,17 +227,19 @@ impl Hir {
227227

228228
let selector_keys: Vec<_> = self.builtin.selectors.keys().cloned().collect();
229229
for name in selector_keys {
230-
self.add_symbol(Symbol {
231-
value: Some(name.clone()),
232-
kind: SymbolKind::Selector,
233-
source: SourceInfo::new(Some(self.builtin.source_id), None),
234-
scope: self.builtin.scope_id,
235-
doc: vec![(
236-
mq_lang::Range::default(),
237-
mq_lang::BUILTIN_SELECTOR_DOC[&name].description.to_string(),
238-
)],
239-
parent: None,
240-
});
230+
if let Ok(selector) = mq_lang::Selector::try_from(&mq_lang::Token::new(TokenKind::Selector(name.clone()))) {
231+
self.add_symbol(Symbol {
232+
value: Some(name.clone()),
233+
kind: SymbolKind::Selector(selector),
234+
source: SourceInfo::new(Some(self.builtin.source_id), None),
235+
scope: self.builtin.scope_id,
236+
doc: vec![(
237+
mq_lang::Range::default(),
238+
mq_lang::BUILTIN_SELECTOR_DOC[&name].description.to_string(),
239+
)],
240+
parent: None,
241+
});
242+
}
241243
}
242244

243245
self.builtin.loaded = true;
@@ -951,10 +953,12 @@ impl Hir {
951953
kind: mq_lang::CstNodeKind::Selector,
952954
..
953955
} = &**node
956+
&& let Some(token) = &node.token
957+
&& let Ok(selector) = mq_lang::Selector::try_from(&**token)
954958
{
955959
let symbol_id = self.symbols.insert(Symbol {
956960
value: node.name(),
957-
kind: SymbolKind::Selector,
961+
kind: SymbolKind::Selector(selector),
958962
source: SourceInfo::new(Some(source_id), Some(node.range())),
959963
scope: scope_id,
960964
doc: node.comments(),
@@ -1919,8 +1923,8 @@ def foo(): 1", vec![" test".to_owned(), " test".to_owned(), "".to_owned()], vec!
19191923
#[case::elif_("if (true): 1 elif (false): 2 else: 3;", "elif", SymbolKind::Elif)]
19201924
#[case::else_("if (true): 1 else: 2;", "else", SymbolKind::Else)]
19211925
#[case::literal("42", "42", SymbolKind::Number)]
1922-
#[case::selector(".h", ".h", SymbolKind::Selector)]
1923-
#[case::selector(".code.lang", ".code", SymbolKind::Selector)]
1926+
#[case::selector(".h", ".h", SymbolKind::Selector(mq_lang::Selector::Heading(None)))]
1927+
#[case::selector(".code.lang", ".code", SymbolKind::Selector(mq_lang::Selector::Code))]
19241928
#[case::interpolated_string("s\"hello ${world}\"", "world", SymbolKind::Variable)]
19251929
#[case::include("include \"foo\"", "foo", SymbolKind::Include(SourceId::default()))]
19261930
#[case::fn_expr("fn(): 42", "fn", SymbolKind::Keyword)]

crates/mq-hir/src/symbol.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ pub enum SymbolKind {
7777
Pattern,
7878
PatternVariable,
7979
Ref,
80-
Selector,
80+
Selector(mq_lang::Selector),
8181
String,
8282
Symbol,
8383
UnaryOp,

crates/mq-lang/src/lexer/token.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ use std::fmt::{self, Display, Formatter};
33
use itertools::Itertools;
44
use smol_str::SmolStr;
55

6-
#[cfg(feature = "ast-json")]
7-
use crate::ArenaId;
8-
use crate::{module::ModuleId, number::Number, range::Range};
6+
use crate::{ArenaId, module::ModuleId, number::Number, range::Range};
97
#[cfg(feature = "ast-json")]
108
use serde::{Deserialize, Serialize};
119

@@ -25,7 +23,6 @@ impl Display for StringSegment {
2523
}
2624
}
2725

28-
#[cfg(feature = "ast-json")]
2926
fn default_module_id() -> ModuleId {
3027
ArenaId::new(0)
3128
}
@@ -129,6 +126,14 @@ pub enum TokenKind {
129126
}
130127

131128
impl Token {
129+
pub fn new(kind: TokenKind) -> Self {
130+
Self {
131+
kind,
132+
range: Range::default(),
133+
module_id: default_module_id(),
134+
}
135+
}
136+
132137
#[inline(always)]
133138
pub fn is_eof(&self) -> bool {
134139
matches!(self.kind, TokenKind::Eof)
@@ -232,6 +237,7 @@ impl Display for TokenKind {
232237
}
233238
}
234239
}
240+
235241
#[cfg(test)]
236242
mod tests {
237243
use super::*;

crates/mq-lsp/src/completions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ pub fn response(
123123
..Default::default()
124124
})
125125
}
126-
mq_hir::SymbolKind::Selector => {
126+
mq_hir::SymbolKind::Selector(_) => {
127127
let deprecated = symbol.is_deprecated();
128128
Some(CompletionItem {
129129
label: symbol.value.clone().unwrap_or_default().to_string(),

crates/mq-lsp/src/semantic_tokens.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ pub fn response(hir: Arc<RwLock<mq_hir::Hir>>, url: Url) -> Vec<SemanticToken> {
8686
mq_hir::SymbolKind::Number => token_type(ls_types::SemanticTokenType::NUMBER),
8787
mq_hir::SymbolKind::Parameter => token_type(ls_types::SemanticTokenType::PARAMETER),
8888
mq_hir::SymbolKind::Ref => token_type(ls_types::SemanticTokenType::VARIABLE),
89-
mq_hir::SymbolKind::Selector => token_type(ls_types::SemanticTokenType::METHOD),
89+
mq_hir::SymbolKind::Selector(_) => token_type(ls_types::SemanticTokenType::METHOD),
9090
mq_hir::SymbolKind::String => token_type(ls_types::SemanticTokenType::STRING),
9191
mq_hir::SymbolKind::Variable
9292
| mq_hir::SymbolKind::Symbol

0 commit comments

Comments
 (0)