Make early returns work even without an explicit return
This commit is contained in:
parent
1aa9b3e76c
commit
b19a32cd8a
@ -9,5 +9,5 @@ fn fibonacci(value: u16) -> u16 {
|
|||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
return fibonacci(value - 1) + fibonacci(value - 2);
|
return fibonacci(value - 1) + fibonacci(value - 2);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ impl mir::Module {
|
|||||||
if !scope.block.delete_if_unused().unwrap() {
|
if !scope.block.delete_if_unused().unwrap() {
|
||||||
// Add a void return just in case if the block
|
// Add a void return just in case if the block
|
||||||
// wasn't unused but didn't have a terminator yet
|
// wasn't unused but didn't have a terminator yet
|
||||||
scope.block.terminate(Term::RetVoid).unwrap();
|
scope.block.terminate(Term::RetVoid).ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,11 +225,13 @@ impl mir::Expression {
|
|||||||
lhs_exp
|
lhs_exp
|
||||||
.return_type()
|
.return_type()
|
||||||
.expect("No ret type in lhs?")
|
.expect("No ret type in lhs?")
|
||||||
|
.1
|
||||||
.is_known()
|
.is_known()
|
||||||
.expect("lhs ret type is unknown");
|
.expect("lhs ret type is unknown");
|
||||||
rhs_exp
|
rhs_exp
|
||||||
.return_type()
|
.return_type()
|
||||||
.expect("No ret type in rhs?")
|
.expect("No ret type in rhs?")
|
||||||
|
.1
|
||||||
.is_known()
|
.is_known()
|
||||||
.expect("rhs ret type is unknown");
|
.expect("rhs ret type is unknown");
|
||||||
|
|
||||||
|
@ -177,7 +177,7 @@ pub enum CmpOperator {
|
|||||||
NE,
|
NE,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum ReturnKind {
|
pub enum ReturnKind {
|
||||||
Hard,
|
Hard,
|
||||||
Soft,
|
Soft,
|
||||||
|
@ -6,7 +6,10 @@ use crate::{mir::*, util::try_all};
|
|||||||
use TypeKind::*;
|
use TypeKind::*;
|
||||||
use VagueType::*;
|
use VagueType::*;
|
||||||
|
|
||||||
use super::pass::{Pass, PassState, ScopeFunction};
|
use super::{
|
||||||
|
pass::{Pass, PassState, ScopeFunction},
|
||||||
|
types::ReturnType,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug, Clone)]
|
#[derive(thiserror::Error, Debug, Clone)]
|
||||||
pub enum ErrorKind {
|
pub enum ErrorKind {
|
||||||
@ -86,8 +89,10 @@ impl Block {
|
|||||||
) -> Result<TypeKind, ErrorKind> {
|
) -> Result<TypeKind, ErrorKind> {
|
||||||
let mut state = state.inner();
|
let mut state = state.inner();
|
||||||
|
|
||||||
|
let mut early_return = None;
|
||||||
|
|
||||||
for statement in &mut self.statements {
|
for statement in &mut self.statements {
|
||||||
match &mut statement.0 {
|
let ret = match &mut statement.0 {
|
||||||
StmtKind::Let(variable_reference, expression) => {
|
StmtKind::Let(variable_reference, expression) => {
|
||||||
let res = expression.typecheck(&mut state, Some(variable_reference.0));
|
let res = expression.typecheck(&mut state, Some(variable_reference.0));
|
||||||
|
|
||||||
@ -118,15 +123,31 @@ impl Block {
|
|||||||
variable_reference.1.clone(),
|
variable_reference.1.clone(),
|
||||||
)));
|
)));
|
||||||
state.ok(res, variable_reference.2);
|
state.ok(res, variable_reference.2);
|
||||||
|
None
|
||||||
}
|
}
|
||||||
StmtKind::Import(_) => todo!(),
|
StmtKind::Import(_) => todo!(),
|
||||||
StmtKind::Expression(expression) => {
|
StmtKind::Expression(expression) => {
|
||||||
let res = expression.typecheck(&mut state, None);
|
let res = expression.typecheck(&mut state, None);
|
||||||
state.ok(res, expression.1);
|
let res_t = state.or_else(res, Void, expression.1);
|
||||||
|
if let Ok((kind, _)) = expression.return_type() {
|
||||||
|
Some((kind, expression))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some((ReturnKind::Hard, _)) = ret {
|
||||||
|
early_return = early_return.or(ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some((ReturnKind::Hard, expr)) = early_return {
|
||||||
|
let hint = state.scope.return_type_hint;
|
||||||
|
let res = expr.typecheck(&mut state, hint);
|
||||||
|
return Ok(state.or_else(res, Vague(Unknown), expr.1));
|
||||||
|
}
|
||||||
|
|
||||||
if let Some((return_kind, expr)) = &mut self.return_expression {
|
if let Some((return_kind, expr)) = &mut self.return_expression {
|
||||||
// Use function return type as hint if return is hard.
|
// Use function return type as hint if return is hard.
|
||||||
let ret_hint_t = match return_kind {
|
let ret_hint_t = match return_kind {
|
||||||
|
@ -9,20 +9,20 @@ pub enum ReturnTypeOther {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait ReturnType {
|
pub trait ReturnType {
|
||||||
fn return_type(&self) -> Result<TypeKind, ReturnTypeOther>;
|
fn return_type(&self) -> Result<(ReturnKind, TypeKind), ReturnTypeOther>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReturnType for Block {
|
impl ReturnType for Block {
|
||||||
fn return_type(&self) -> Result<TypeKind, ReturnTypeOther> {
|
fn return_type(&self) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
||||||
self.return_expression
|
self.return_expression
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.ok_or(ReturnTypeOther::NoBlockReturn(self.meta.range))
|
.ok_or(ReturnTypeOther::NoBlockReturn(self.meta.range))
|
||||||
.and_then(|(_, stmt)| stmt.return_type())
|
.and_then(|(kind, stmt)| Ok((*kind, stmt.return_type()?.1)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReturnType for Statement {
|
impl ReturnType for Statement {
|
||||||
fn return_type(&self) -> Result<TypeKind, ReturnTypeOther> {
|
fn return_type(&self) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
||||||
use StmtKind::*;
|
use StmtKind::*;
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
Expression(e) => e.return_type(),
|
Expression(e) => e.return_type(),
|
||||||
@ -33,12 +33,21 @@ impl ReturnType for Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ReturnType for Expression {
|
impl ReturnType for Expression {
|
||||||
fn return_type(&self) -> Result<TypeKind, ReturnTypeOther> {
|
fn return_type(&self) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
||||||
use ExprKind::*;
|
use ExprKind::*;
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
Literal(lit) => Ok(lit.as_type()),
|
Literal(lit) => Ok((ReturnKind::Soft, lit.as_type())),
|
||||||
Variable(var) => var.return_type(),
|
Variable(var) => var.return_type(),
|
||||||
BinOp(_, expr, _) => expr.return_type(),
|
BinOp(_, then_e, else_e) => {
|
||||||
|
let then_r = then_e.return_type()?;
|
||||||
|
let else_e = else_e.return_type()?;
|
||||||
|
let kind = if then_r.0 == ReturnKind::Hard && else_e.0 == ReturnKind::Hard {
|
||||||
|
ReturnKind::Hard
|
||||||
|
} else {
|
||||||
|
ReturnKind::Hard
|
||||||
|
};
|
||||||
|
Ok((kind, then_r.1))
|
||||||
|
}
|
||||||
Block(block) => block.return_type(),
|
Block(block) => block.return_type(),
|
||||||
FunctionCall(fcall) => fcall.return_type(),
|
FunctionCall(fcall) => fcall.return_type(),
|
||||||
If(expr) => expr.return_type(),
|
If(expr) => expr.return_type(),
|
||||||
@ -47,19 +56,19 @@ impl ReturnType for Expression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ReturnType for IfExpression {
|
impl ReturnType for IfExpression {
|
||||||
fn return_type(&self) -> Result<TypeKind, ReturnTypeOther> {
|
fn return_type(&self) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
||||||
self.1.return_type()
|
self.1.return_type()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReturnType for VariableReference {
|
impl ReturnType for VariableReference {
|
||||||
fn return_type(&self) -> Result<TypeKind, ReturnTypeOther> {
|
fn return_type(&self) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
||||||
Ok(self.0.clone())
|
Ok((ReturnKind::Soft, self.0.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReturnType for FunctionCall {
|
impl ReturnType for FunctionCall {
|
||||||
fn return_type(&self) -> Result<TypeKind, ReturnTypeOther> {
|
fn return_type(&self) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
||||||
Ok(self.return_type.clone())
|
Ok((ReturnKind::Soft, self.return_type.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user