Skip to content

Commit 3c34021

Browse files
committed
Migrate signature checks to syntax AST
1 parent 0fd0537 commit 3c34021

5 files changed

Lines changed: 47 additions & 371 deletions

File tree

src/analyzer.rs

Lines changed: 26 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
1-
use crate::ast::{Program, parse_program};
21
use crate::checks;
32
use crate::diagnostic::Diagnostic;
43
use crate::hir::{FunctionSig, Hir, HirTypeKind};
54
use crate::lexer::{Token, lex};
6-
use crate::syntax::ast::{Callee, Item};
5+
use crate::syntax::ast::{Callee, EffectDecl, Item};
76
use crate::syntax::parse_source;
87

98
pub fn analyze_source(file: &str, source: &str) -> Vec<Diagnostic> {
109
let tokens = lex(file, source);
11-
let program = parse_program(&tokens);
1210
let syntax_program = parse_source(file, source);
1311
let hir = Hir::from_syntax(&syntax_program);
1412
let mut analyzer = Analyzer {
1513
tokens: &tokens,
16-
program,
1714
syntax_program,
1815
hir,
1916
diagnostics: Vec::new(),
@@ -24,7 +21,6 @@ pub fn analyze_source(file: &str, source: &str) -> Vec<Diagnostic> {
2421

2522
pub(crate) struct Analyzer<'a> {
2623
pub(crate) tokens: &'a [Token],
27-
pub(crate) program: Program,
2824
pub(crate) syntax_program: crate::syntax::ast::Program,
2925
pub(crate) hir: Hir,
3026
pub(crate) diagnostics: Vec<Diagnostic>,
@@ -42,7 +38,7 @@ impl Analyzer<'_> {
4238
}
4339

4440
fn check_file_mode_present(&mut self) {
45-
if self.program.mode.is_none() {
41+
if self.syntax_program.mode.is_none() {
4642
let span = self.tokens.first().map(|token| token.span.clone()).unwrap();
4743
self.diagnostics.push(
4844
Diagnostic::error(
@@ -61,23 +57,16 @@ impl Analyzer<'_> {
6157
}
6258

6359
fn check_signature_explicitness(&mut self) {
64-
for function in self.program.functions.values() {
65-
if function
66-
.return_type
67-
.as_deref()
68-
.unwrap_or_default()
69-
.is_empty()
70-
{
71-
let span = self
72-
.tokens
73-
.get(function.body_start.saturating_sub(1))
74-
.map(|token| token.span.clone())
75-
.unwrap_or_else(|| self.tokens[0].span.clone());
60+
for item in &self.syntax_program.items {
61+
let Item::Function(function) = item else {
62+
continue;
63+
};
64+
if function.return_ty.is_none() {
7665
self.diagnostics.push(
7766
Diagnostic::error(
7867
"RS0002",
7968
format!("function `{}` must declare an explicit return type.", function.name),
80-
span,
69+
function.span.clone(),
8170
"missing return type",
8271
)
8372
.with_cause("Public APIs must not rely on inference; this checker applies the canonical rule to all functions.")
@@ -86,20 +75,15 @@ impl Analyzer<'_> {
8675
}
8776

8877
for param in &function.params {
89-
if param.type_name.is_empty() {
90-
let span = self
91-
.tokens
92-
.get(function.body_start.saturating_sub(1))
93-
.map(|token| token.span.clone())
94-
.unwrap_or_else(|| self.tokens[0].span.clone());
78+
if param.ty.name.is_empty() {
9579
self.diagnostics.push(
9680
Diagnostic::error(
9781
"RS0003",
9882
format!(
9983
"parameter `{}` in `{}` must declare an explicit type.",
10084
param.name, function.name
10185
),
102-
span,
86+
param.span.clone(),
10387
"missing parameter type",
10488
)
10589
.with_fix(
@@ -112,23 +96,19 @@ impl Analyzer<'_> {
11296
}
11397

11498
for effect in &function.effects {
115-
let valid = effect == "no_panic"
116-
|| effect == "noalloc"
117-
|| effect == "no_block"
118-
|| effect == "pure"
119-
|| effect == "unsafe"
120-
|| effect == "native"
121-
|| effect.starts_with("retains(");
99+
let effect_name = effect_name(effect);
100+
let valid = effect_name == "no_panic"
101+
|| effect_name == "noalloc"
102+
|| effect_name == "no_block"
103+
|| effect_name == "pure"
104+
|| effect_name == "unsafe"
105+
|| effect_name == "native"
106+
|| matches!(effect, EffectDecl::Retains(_));
122107
if !valid {
123-
let span = self
124-
.tokens
125-
.get(function.body_start.saturating_sub(1))
126-
.map(|token| token.span.clone())
127-
.unwrap_or_else(|| self.tokens[0].span.clone());
128108
self.diagnostics.push(Diagnostic::warning(
129109
"RS0004",
130-
format!("unknown effect `{effect}` in `{}`.", function.name),
131-
span,
110+
format!("unknown effect `{effect_name}` in `{}`.", function.name),
111+
function.span.clone(),
132112
"unknown effect",
133113
));
134114
}
@@ -170,3 +150,9 @@ impl Analyzer<'_> {
170150
}
171151
}
172152
}
153+
154+
fn effect_name(effect: &EffectDecl) -> &str {
155+
match effect {
156+
EffectDecl::Name(name) | EffectDecl::Retains(name) => name,
157+
}
158+
}

0 commit comments

Comments
 (0)