Skip to content

Commit 47fbb54

Browse files
committed
Require Result returns for try operator
1 parent d90e0de commit 47fbb54

3 files changed

Lines changed: 76 additions & 0 deletions

File tree

src/analyzer.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ impl Analyzer<'_> {
3535
self.check_removed_profile_declarations();
3636
self.check_duplicate_declarations();
3737
self.check_signature_explicitness();
38+
self.check_try_operator_result_returns();
3839
self.check_resource_fields();
3940
self.check_resource_pool_type_arguments();
4041
self.check_resource_generic_arguments();
@@ -311,6 +312,57 @@ impl Analyzer<'_> {
311312
}
312313
}
313314

315+
fn check_try_operator_result_returns(&mut self) {
316+
for (index, item) in self.syntax_program.items.iter().enumerate() {
317+
let Item::Function(function) = item else {
318+
continue;
319+
};
320+
if function
321+
.return_ty
322+
.as_ref()
323+
.is_some_and(|return_ty| return_ty.name == "Result")
324+
{
325+
continue;
326+
}
327+
328+
let start = self
329+
.tokens
330+
.iter()
331+
.position(|token| token.span == function.span)
332+
.unwrap_or(0);
333+
let end = self
334+
.syntax_program
335+
.items
336+
.iter()
337+
.skip(index + 1)
338+
.map(item_span)
339+
.find_map(|span| self.tokens.iter().position(|token| token.span == *span))
340+
.unwrap_or(self.tokens.len());
341+
342+
for token in &self.tokens[start..end] {
343+
if token.symbol("?") {
344+
self.diagnostics.push(
345+
Diagnostic::error(
346+
code::INVALID_TRY_OPERATOR,
347+
format!(
348+
"`?` in `{}` requires the function to return `Result<T, E>`.",
349+
function.name
350+
),
351+
token.span.clone(),
352+
"invalid try operator",
353+
)
354+
.with_cause("RSScript represents recoverable failure in explicit `Result` return types.")
355+
.with_fix(
356+
"return_result_or_handle_error",
357+
"Change the return type to `Result<..., E>` or handle the error explicitly.",
358+
"manual",
359+
),
360+
);
361+
}
362+
}
363+
}
364+
}
365+
314366
fn check_duplicate_declarations(&mut self) {
315367
for duplicate in self.hir.duplicate_symbols() {
316368
self.diagnostics.push(
@@ -702,6 +754,13 @@ fn removed_runtime_effect_replacement(effect_name: &str) -> Option<&'static str>
702754
}
703755
}
704756

757+
fn item_span(item: &Item) -> &crate::diagnostic::Span {
758+
match item {
759+
Item::Type(decl) => &decl.span,
760+
Item::Function(function) => &function.span,
761+
}
762+
}
763+
705764
fn duplicate_symbol_label(kind: DuplicateSymbolKind) -> &'static str {
706765
match kind {
707766
DuplicateSymbolKind::Function => "function",

src/diagnostic.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub mod code {
1313
pub const REMOVED_PROFILE_DECLARATION: &str = "RS0010";
1414
pub const REMOVED_SHARE_EFFECT: &str = "RS0011";
1515
pub const REMOVED_RUNTIME_EFFECT: &str = "RS0012";
16+
pub const INVALID_TRY_OPERATOR: &str = "RS0013";
1617
pub const FILE_MODE_VIOLATION: &str = "RS0101";
1718
pub const UNNAMED_ARGUMENT: &str = "RS0201";
1819
pub const MISSING_DATA_EFFECT: &str = "RS0202";
@@ -263,6 +264,11 @@ static DIAGNOSTIC_EXPLANATIONS: &[DiagnosticExplanation] = &[
263264
title: "removed runtime effect",
264265
explanation: "RSScript v0.4.1 uses reductive guarantees. Additive runtime effects such as `io`, `allocates`, `may_panic`, and `may_fail` are not valid effects.",
265266
},
267+
DiagnosticExplanation {
268+
code: code::INVALID_TRY_OPERATOR,
269+
title: "invalid try operator",
270+
explanation: "`?` may only be used inside functions that return a compatible `Result<T, E>` type.",
271+
},
266272
DiagnosticExplanation {
267273
code: code::FILE_MODE_VIOLATION,
268274
title: "file mode violation",
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// expect: RS0013
2+
mode: managed
3+
4+
struct Image {
5+
pixels: Buffer
6+
}
7+
8+
fn load_or_default(path: read Path) -> Image {
9+
let image = Image.load(path: read path)?
10+
return image
11+
}

0 commit comments

Comments
 (0)