Skip to content

Commit 1c2f11d

Browse files
committed
feat: added ending point enforcment
1 parent ebb6262 commit 1c2f11d

6 files changed

Lines changed: 74 additions & 18 deletions

File tree

compiler/astoir_hir/src/ctx.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,13 @@ impl HIRBranchedContext {
184184
return true;
185185
}
186186

187+
pub fn introduce_ending_point(&mut self, kind: EndingPointKind) {
188+
self.ending_points.push(HIRBranchedEndingPoint {
189+
introduced_in_era: self.current_branch,
190+
kind,
191+
})
192+
}
193+
187194
/// Determines if the element with the given index is still alive in the current branch.
188195
pub fn is_alive(&self, ind: usize) -> bool {
189196
let start_branch = self.variables[ind].introduced_in_era;
@@ -215,7 +222,7 @@ impl HIRBranchedContext {
215222
/// Determines if the current function meets the ending point requirement.
216223
/// The requirement is that every single branch should have an ending point that affects it.
217224
/// This function uses `is_code_alive` to check if the code ended on each branch before the current branch.
218-
/// This function should only be ran at the end of body parsing
225+
/// This function should only be ran at the end of body parsing
219226
pub fn meets_ending_point(&self) -> bool {
220227
if !self.is_code_alive(self.current_branch) {
221228
return true;

compiler/astoir_hir/src/nodes.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,13 @@ impl HIRNode {
270270
return false;
271271
}
272272

273+
pub fn is_ending_point(&self) -> bool {
274+
match self.kind {
275+
HIRNodeKind::ReturnStatement { .. } => true,
276+
_ => false,
277+
}
278+
}
279+
273280
pub fn get_variable_represent(&self) -> (usize, bool) {
274281
match &self.kind {
275282
HIRNodeKind::VariableReference { index, is_static } => return (*index, *is_static),

compiler/astoir_hir_lowering/src/func.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ use astoir_hir::{
55
};
66
use compiler_global_scope::key::EntryKey;
77
use compiler_typing::TypedGlobalScopeEntry;
8-
use diagnostics::{DiagnosticResult, builders::make_already_in_scope};
8+
use diagnostics::{
9+
DiagnosticResult,
10+
builders::{make_already_in_scope, make_ending_point_missing},
11+
};
912

1013
use crate::{lower_ast_body, types::lower_ast_type, values::lower_ast_value};
1114

@@ -115,6 +118,10 @@ pub fn lower_ast_function_declaration(
115118

116119
curr_ctx.end_branch(branch);
117120

121+
if !curr_ctx.meets_ending_point() {
122+
return Err(make_ending_point_missing(&*body[body.len() - 1]).into());
123+
}
124+
118125
let implementation = Box::new(HIRNode::new(
119126
HIRNodeKind::FunctionDeclaration {
120127
func_name: ind,

compiler/astoir_hir_lowering/src/lib.rs

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@ use ast::{
33
tree::{ASTTreeNode, ASTTreeNodeKind},
44
};
55
use astoir_hir::{
6-
ctx::{HIRBranchedContext, HIRContext},
6+
ctx::{EndingPointKind, HIRBranchedContext, HIRContext},
77
nodes::{HIRNode, HIRNodeKind},
88
};
9-
use diagnostics::{DiagnosticResult, DiagnosticSpanOrigin, move_current_diagnostic_pos};
9+
use diagnostics::{
10+
DiagnosticResult, DiagnosticSpanOrigin,
11+
builders::{make_ret_type_kind, make_unreachable_code},
12+
move_current_diagnostic_pos,
13+
};
1014
use prelude::apply_prelude;
1115

1216
use crate::{
@@ -68,20 +72,24 @@ pub fn lower_ast_body_node(
6872
ASTTreeNodeKind::ReturnStatement { val } => {
6973
let v;
7074

75+
if val.is_none() != curr_ctx.return_type.is_none() {
76+
return Err(make_ret_type_kind(&*node).into());
77+
}
78+
7179
if val.is_none() {
80+
curr_ctx.introduce_ending_point(EndingPointKind::NoneReturn);
81+
7282
v = None;
7383
} else {
74-
let mut k = lower_ast_value(context, curr_ctx, val.unwrap())?;
75-
76-
if curr_ctx.return_type.is_some() {
77-
k = Box::new(k.use_as(
78-
context,
79-
curr_ctx,
80-
curr_ctx.return_type.clone().unwrap(),
81-
&*node,
82-
None,
83-
)?);
84-
}
84+
curr_ctx.introduce_ending_point(EndingPointKind::Return);
85+
86+
let k = Box::new(lower_ast_value(context, curr_ctx, val.unwrap())?.use_as(
87+
context,
88+
curr_ctx,
89+
curr_ctx.return_type.clone().unwrap(),
90+
&*node,
91+
None,
92+
)?);
8593

8694
v = Some(k)
8795
}
@@ -129,7 +137,17 @@ pub fn lower_ast_body(
129137
}
130138

131139
for n in nodes {
132-
hir_nodes.push(lower_ast_body_node(context, curr_ctx, n)?);
140+
let is_code_dead_pre = !curr_ctx.is_code_alive(curr_ctx.current_branch);
141+
142+
let node = lower_ast_body_node(context, curr_ctx, n)?;
143+
144+
if !curr_ctx.is_code_alive(curr_ctx.current_branch) {
145+
if is_code_dead_pre || !node.is_ending_point() {
146+
return Err(make_unreachable_code(&*node).into());
147+
}
148+
}
149+
150+
hir_nodes.push(node);
133151
}
134152

135153
if introduce_era {

compiler/diagnostics/src/builders.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use crate::{
99
ERA_NOT_EXIST, EXPECTED_FREE, EXPECTED_TOKEN, EXPECTED_TYPE, FIELD_MISSING,
1010
FIELD_STRUCT_INIT, FIND_TYPE, FIND_TYPE_FIELD, FIND_TYPE_FUNCTION, FIND_VAR, FUNC_MISSING,
1111
INDEX_USAGE, INVALID_POINTING, INVALID_TYPE_REQ, IR_CAST, IR_INSTRUCTION_HELD_VAL,
12-
MATH_OPERATION_ASSIGNS, NOT_FOUND_USE, TRAIT_MISSING, TYPE_NOT_PART, UNEXPECTED_TOKEN,
13-
VARIABLE_UNINIT,
12+
MATH_OPERATION_ASSIGNS, NOT_FOUND_USE, RET_TYPE_NOT_MATCH, TRAIT_MISSING, TYPE_NOT_PART,
13+
UNEXPECTED_TOKEN, VARIABLE_UNINIT,
1414
},
1515
get_current_diagnostic_pos,
1616
warnings::UNUSED_VAR,
@@ -669,3 +669,15 @@ pub fn make_unreachable_code<K: DiagnosticSpanOrigin>(origin: &K) -> Diagnostic
669669
vec!["move this code before the ending point".to_string()],
670670
)
671671
}
672+
673+
pub fn make_ret_type_kind<K: DiagnosticSpanOrigin>(origin: &K) -> Diagnostic {
674+
origin.make_simple_diagnostic(
675+
RET_TYPE_NOT_MATCH.0,
676+
Level::Error,
677+
RET_TYPE_NOT_MATCH.1.to_string(),
678+
None,
679+
vec![],
680+
vec![],
681+
vec![],
682+
)
683+
}

compiler/diagnostics/src/errors.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,8 @@ declare_error!(NOT_FOUND_USE, 32, "element {} was not found in {}");
105105
declare_error!(CANNOT_FIND, 33, "cannot find {} in the current scope");
106106
declare_error!(ENDING_POINT_MISSING, 34, "missing ending point.");
107107
declare_error!(CODE_UNREACHABLE, 35, "unreachable code.");
108+
declare_error!(
109+
RET_TYPE_NOT_MATCH,
110+
36,
111+
"different return type kinds. one is empty and one is not."
112+
);

0 commit comments

Comments
 (0)