fix(sema, ir): Potential elvate bugs
This commit is contained in:
@@ -205,6 +205,12 @@ impl Parser {
|
|||||||
self.advance(1);
|
self.advance(1);
|
||||||
return Ok(vec![]);
|
return Ok(vec![]);
|
||||||
}
|
}
|
||||||
|
if self.peek().value == TokenValue::TypeIdent(TypeIdent::Void)
|
||||||
|
&& self.peek_n(1).value == TokenValue::RParen
|
||||||
|
{
|
||||||
|
self.advance(2);
|
||||||
|
return Ok(vec![]);
|
||||||
|
}
|
||||||
|
|
||||||
let mut params = vec![];
|
let mut params = vec![];
|
||||||
loop {
|
loop {
|
||||||
@@ -328,6 +334,30 @@ impl Parser {
|
|||||||
Ok(Some(self.parse_expr()?))
|
Ok(Some(self.parse_expr()?))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn skip_initializer_list(&mut self) -> Result<(), ParseProcessError> {
|
||||||
|
let mut depth = 0usize;
|
||||||
|
loop {
|
||||||
|
let token = self.next().clone();
|
||||||
|
match token.value {
|
||||||
|
TokenValue::LBrace => depth += 1,
|
||||||
|
TokenValue::RBrace => {
|
||||||
|
depth -= 1;
|
||||||
|
if depth == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TokenValue::Eof => {
|
||||||
|
self.diagnostics.add_from_frontend_error(
|
||||||
|
ParseError::ExpectedBefore(TokenValue::Eof, "`}`"),
|
||||||
|
token.span,
|
||||||
|
);
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn init_declarator_to_var_value(
|
fn init_declarator_to_var_value(
|
||||||
&mut self,
|
&mut self,
|
||||||
init_declarator: InitDeclarator,
|
init_declarator: InitDeclarator,
|
||||||
|
|||||||
@@ -59,6 +59,10 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_stmt(&mut self) -> Result<Statement, ParseProcessError> {
|
fn parse_stmt(&mut self) -> Result<Statement, ParseProcessError> {
|
||||||
|
if self.peek().value == TokenValue::Semicolon {
|
||||||
|
self.advance(1);
|
||||||
|
return Ok(Statement::Block(BlockStmt { statements: vec![] }));
|
||||||
|
}
|
||||||
match self.parse_var_decl_stmt(ParseType::TryParse) {
|
match self.parse_var_decl_stmt(ParseType::TryParse) {
|
||||||
Ok(var_decl) => return Ok(Statement::VarDecl(var_decl)),
|
Ok(var_decl) => return Ok(Statement::VarDecl(var_decl)),
|
||||||
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
|
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
|
||||||
|
|||||||
+93
-28
@@ -84,7 +84,7 @@ impl<'a> Generator<'a> {
|
|||||||
}
|
}
|
||||||
} else if let Some(init) = value.value {
|
} else if let Some(init) = value.value {
|
||||||
self.current_exit_label.push(None);
|
self.current_exit_label.push(None);
|
||||||
let (init_instrs, init_var) = match self.generate_expr(init) {
|
let (mut init_instrs, init_var) = match self.generate_expr(init) {
|
||||||
Some(res) => res,
|
Some(res) => res,
|
||||||
None => {
|
None => {
|
||||||
self.current_exit_label.pop();
|
self.current_exit_label.pop();
|
||||||
@@ -93,8 +93,9 @@ impl<'a> Generator<'a> {
|
|||||||
};
|
};
|
||||||
self.current_exit_label.pop();
|
self.current_exit_label.pop();
|
||||||
let target = self.var_manager.get_symbol(value.symbol).unwrap();
|
let target = self.var_manager.get_symbol(value.symbol).unwrap();
|
||||||
|
let init_var = self.coerce_value(&mut init_instrs, init_var.unwrap(), &target.data_type);
|
||||||
instrs.extend(init_instrs);
|
instrs.extend(init_instrs);
|
||||||
instrs.push(IRInstr::Move(target, MoveRValue::Var(init_var.unwrap())));
|
instrs.push(IRInstr::Move(target, MoveRValue::Var(init_var)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,19 +109,26 @@ impl<'a> Generator<'a> {
|
|||||||
let value = Self::const_init_value(operand)?;
|
let value = Self::const_init_value(operand)?;
|
||||||
match op {
|
match op {
|
||||||
AstUnaryOp::Add => Some(value),
|
AstUnaryOp::Add => Some(value),
|
||||||
AstUnaryOp::Sub => value.checked_neg(),
|
AstUnaryOp::Sub => Some(value.wrapping_neg()),
|
||||||
AstUnaryOp::Not => Some((value == 0) as i32),
|
AstUnaryOp::Not => Some((value == 0) as i32),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HirExprValue::BinaryOp { lhs, op, rhs } => {
|
HirExprValue::BinaryOp { lhs, op, rhs } => {
|
||||||
let lhs = Self::const_init_value(lhs)?;
|
let lhs = Self::const_init_value(lhs)?;
|
||||||
|
match op {
|
||||||
|
AstBinaryOp::And if lhs == 0 => return Some(0),
|
||||||
|
AstBinaryOp::Or if lhs != 0 => return Some(1),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
let rhs = Self::const_init_value(rhs)?;
|
let rhs = Self::const_init_value(rhs)?;
|
||||||
match op {
|
match op {
|
||||||
AstBinaryOp::Add => lhs.checked_add(rhs),
|
AstBinaryOp::Add => Some(lhs.wrapping_add(rhs)),
|
||||||
AstBinaryOp::Sub => lhs.checked_sub(rhs),
|
AstBinaryOp::Sub => Some(lhs.wrapping_sub(rhs)),
|
||||||
AstBinaryOp::Mul => lhs.checked_mul(rhs),
|
AstBinaryOp::Mul => Some(lhs.wrapping_mul(rhs)),
|
||||||
AstBinaryOp::Div => lhs.checked_div(rhs),
|
AstBinaryOp::Div if rhs != 0 => Some(lhs.wrapping_div(rhs)),
|
||||||
AstBinaryOp::Mod => lhs.checked_rem(rhs),
|
AstBinaryOp::Div => None,
|
||||||
|
AstBinaryOp::Mod if rhs != 0 => Some(lhs.wrapping_rem(rhs)),
|
||||||
|
AstBinaryOp::Mod => None,
|
||||||
AstBinaryOp::Equal => Some((lhs == rhs) as i32),
|
AstBinaryOp::Equal => Some((lhs == rhs) as i32),
|
||||||
AstBinaryOp::NotEqual => Some((lhs != rhs) as i32),
|
AstBinaryOp::NotEqual => Some((lhs != rhs) as i32),
|
||||||
AstBinaryOp::Less => Some((lhs < rhs) as i32),
|
AstBinaryOp::Less => Some((lhs < rhs) as i32),
|
||||||
@@ -214,7 +222,7 @@ impl<'a> Generator<'a> {
|
|||||||
match return_stmt.value {
|
match return_stmt.value {
|
||||||
Some(expr) => {
|
Some(expr) => {
|
||||||
self.current_exit_label.push(None);
|
self.current_exit_label.push(None);
|
||||||
let (value_instrs, value_var) = match self.generate_expr(expr) {
|
let (mut value_instrs, value_var) = match self.generate_expr(expr) {
|
||||||
Some(res) => res,
|
Some(res) => res,
|
||||||
None => {
|
None => {
|
||||||
self.current_exit_label.pop();
|
self.current_exit_label.pop();
|
||||||
@@ -222,8 +230,10 @@ impl<'a> Generator<'a> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.current_exit_label.pop();
|
self.current_exit_label.pop();
|
||||||
|
let target = func_exit.1.unwrap();
|
||||||
|
let value_var = self.coerce_value(&mut value_instrs, value_var.unwrap(), &target.data_type);
|
||||||
instrs.extend(value_instrs);
|
instrs.extend(value_instrs);
|
||||||
instrs.push(IRInstr::Move(func_exit.1.unwrap(), MoveRValue::Var(value_var.unwrap())));
|
instrs.push(IRInstr::Move(target, MoveRValue::Var(value_var)));
|
||||||
}
|
}
|
||||||
None => {},
|
None => {},
|
||||||
}
|
}
|
||||||
@@ -387,6 +397,35 @@ impl<'a> Generator<'a> {
|
|||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn coerce_value(&mut self, instrs: &mut Vec<IRInstr>, var: Variable, target_type: &IRType) -> Variable {
|
||||||
|
if &var.data_type == target_type {
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
match (&var.data_type, target_type) {
|
||||||
|
(IRType::I1, IRType::I32) => {
|
||||||
|
let dest = self.var_manager.declare_unamed_local(IRType::I32);
|
||||||
|
let true_label = self.request_label();
|
||||||
|
let false_label = self.request_label();
|
||||||
|
let final_label = self.request_label();
|
||||||
|
instrs.push(IRInstr::CondGoto(var, true_label, false_label));
|
||||||
|
instrs.push(IRInstr::Label(true_label));
|
||||||
|
instrs.push(IRInstr::Move(dest.clone(), MoveRValue::ConstInt(1)));
|
||||||
|
instrs.push(IRInstr::Goto(final_label));
|
||||||
|
instrs.push(IRInstr::Label(false_label));
|
||||||
|
instrs.push(IRInstr::Move(dest.clone(), MoveRValue::ConstInt(0)));
|
||||||
|
instrs.push(IRInstr::Goto(final_label));
|
||||||
|
instrs.push(IRInstr::Label(final_label));
|
||||||
|
dest
|
||||||
|
}
|
||||||
|
(IRType::I32, IRType::I1) => {
|
||||||
|
let dest = self.var_manager.declare_temp(IRType::I1);
|
||||||
|
instrs.push(IRInstr::Cmp(dest.clone(), VariableOrIntLit::Var(var), CmpOp::Ne, VariableOrIntLit::IntLit(0)));
|
||||||
|
dest
|
||||||
|
}
|
||||||
|
_ => var,
|
||||||
|
}
|
||||||
|
}
|
||||||
fn generate_expr(&mut self, expr: HirExpr) -> Option<(Vec<IRInstr>, Option<Variable>)> {
|
fn generate_expr(&mut self, expr: HirExpr) -> Option<(Vec<IRInstr>, Option<Variable>)> {
|
||||||
// there may be some expr that doesn't produce value, like void func call
|
// there may be some expr that doesn't produce value, like void func call
|
||||||
let (mut instrs, var) = match expr.value {
|
let (mut instrs, var) = match expr.value {
|
||||||
@@ -414,6 +453,7 @@ impl<'a> Generator<'a> {
|
|||||||
self.current_exit_label.push(None);
|
self.current_exit_label.push(None);
|
||||||
let (mut instrs, rvalue_var) = self.generate_expr(*rvalue)?;
|
let (mut instrs, rvalue_var) = self.generate_expr(*rvalue)?;
|
||||||
self.current_exit_label.pop();
|
self.current_exit_label.pop();
|
||||||
|
let rvalue_var = self.coerce_value(&mut instrs, rvalue_var.unwrap(), &lvalue_ty);
|
||||||
let (lvalue_instrs, target, is_addr) = self.generate_lvalue(*lvalue)?;
|
let (lvalue_instrs, target, is_addr) = self.generate_lvalue(*lvalue)?;
|
||||||
instrs.extend(lvalue_instrs);
|
instrs.extend(lvalue_instrs);
|
||||||
if is_addr {
|
if is_addr {
|
||||||
@@ -509,17 +549,22 @@ impl<'a> Generator<'a> {
|
|||||||
let operand_var = operand_var.unwrap();
|
let operand_var = operand_var.unwrap();
|
||||||
let dest_var = match op {
|
let dest_var = match op {
|
||||||
AstUnaryOp::Add => {
|
AstUnaryOp::Add => {
|
||||||
let dest_var = self.var_manager.declare_temp(operand_var.data_type.clone());
|
let target_ty = if operand_var.data_type == IRType::I1 { IRType::I32 } else { operand_var.data_type.clone() };
|
||||||
|
let operand_var = self.coerce_value(&mut instrs, operand_var, &target_ty);
|
||||||
|
let dest_var = self.var_manager.declare_temp(target_ty);
|
||||||
instrs.push(IRInstr::Move(dest_var.clone(), MoveRValue::Var(operand_var)));
|
instrs.push(IRInstr::Move(dest_var.clone(), MoveRValue::Var(operand_var)));
|
||||||
dest_var
|
dest_var
|
||||||
},
|
},
|
||||||
AstUnaryOp::Sub => {
|
AstUnaryOp::Sub => {
|
||||||
let dest_var = self.var_manager.declare_temp(operand_var.data_type.clone());
|
let target_ty = if operand_var.data_type == IRType::I1 { IRType::I32 } else { operand_var.data_type.clone() };
|
||||||
|
let operand_var = self.coerce_value(&mut instrs, operand_var, &target_ty);
|
||||||
|
let dest_var = self.var_manager.declare_temp(target_ty);
|
||||||
instrs.push(IRInstr::Unary(dest_var.clone(), UnaryOp::Neg, operand_var));
|
instrs.push(IRInstr::Unary(dest_var.clone(), UnaryOp::Neg, operand_var));
|
||||||
dest_var
|
dest_var
|
||||||
},
|
},
|
||||||
AstUnaryOp::Not => {
|
AstUnaryOp::Not => {
|
||||||
let dest_var = self.var_manager.declare_unamed_local(operand_var.data_type.clone());
|
let dest_ty = if parent_is_logical { IRType::I1 } else { IRType::I32 };
|
||||||
|
let dest_var = self.var_manager.declare_unamed_local(dest_ty);
|
||||||
// child will do the cmp
|
// child will do the cmp
|
||||||
if !parent_is_logical {
|
if !parent_is_logical {
|
||||||
let exit = exit_passdown.unwrap(); // (false_exit, true_exit) (consider `not`)
|
let exit = exit_passdown.unwrap(); // (false_exit, true_exit) (consider `not`)
|
||||||
@@ -626,9 +671,7 @@ impl<'a> Generator<'a> {
|
|||||||
// do implicit convert if needed
|
// do implicit convert if needed
|
||||||
// TODO: further check
|
// TODO: further check
|
||||||
if !op.is_logical() && convert_to != left_var.data_type {
|
if !op.is_logical() && convert_to != left_var.data_type {
|
||||||
let temp_var = self.var_manager.declare_temp(convert_to.clone());
|
left_var = self.coerce_value(&mut instrs, left_var, &convert_to);
|
||||||
instrs.push(IRInstr::Move(temp_var.clone(), MoveRValue::Var(left_var)));
|
|
||||||
left_var = temp_var;
|
|
||||||
}
|
}
|
||||||
let result_type;
|
let result_type;
|
||||||
match op {
|
match op {
|
||||||
@@ -640,7 +683,13 @@ impl<'a> Generator<'a> {
|
|||||||
result_type = IRType::I1;
|
result_type = IRType::I1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let dest_var = self.var_manager.declare_temp(result_type);
|
let dest_var = if op.is_logical() && parent_exit.is_none() {
|
||||||
|
self.var_manager.declare_unamed_local(IRType::I32)
|
||||||
|
} else if op.is_logical() {
|
||||||
|
self.var_manager.declare_unamed_local(result_type)
|
||||||
|
} else {
|
||||||
|
self.var_manager.declare_temp(result_type)
|
||||||
|
};
|
||||||
match op {
|
match op {
|
||||||
AstBinaryOp::And | AstBinaryOp::Or => {
|
AstBinaryOp::And | AstBinaryOp::Or => {
|
||||||
instrs.push(IRInstr::Label(exit.unwrap().1));
|
instrs.push(IRInstr::Label(exit.unwrap().1));
|
||||||
@@ -666,9 +715,7 @@ impl<'a> Generator<'a> {
|
|||||||
// true_exit:
|
// true_exit:
|
||||||
instrs.extend(right_instrs);
|
instrs.extend(right_instrs);
|
||||||
if !op.is_logical() && convert_to != right_var.data_type {
|
if !op.is_logical() && convert_to != right_var.data_type {
|
||||||
let temp_var = self.var_manager.declare_temp(convert_to);
|
right_var = self.coerce_value(&mut instrs, right_var, &convert_to);
|
||||||
instrs.push(IRInstr::Move(temp_var.clone(), MoveRValue::Var(right_var)));
|
|
||||||
right_var = temp_var;
|
|
||||||
}
|
}
|
||||||
if !op.is_logical() {
|
if !op.is_logical() {
|
||||||
if let Some((true_exit, false_exit)) = parent_exit {
|
if let Some((true_exit, false_exit)) = parent_exit {
|
||||||
@@ -684,6 +731,17 @@ impl<'a> Generator<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if op.is_logical() {
|
if op.is_logical() {
|
||||||
|
if parent_exit.is_none() {
|
||||||
|
let (true_exit, _, false_exit) = exit.unwrap();
|
||||||
|
let final_exit = self.request_label();
|
||||||
|
instrs.push(IRInstr::Label(true_exit));
|
||||||
|
instrs.push(IRInstr::Move(dest_var.clone(), MoveRValue::ConstInt(1)));
|
||||||
|
instrs.push(IRInstr::Goto(final_exit));
|
||||||
|
instrs.push(IRInstr::Label(false_exit));
|
||||||
|
instrs.push(IRInstr::Move(dest_var.clone(), MoveRValue::ConstInt(0)));
|
||||||
|
instrs.push(IRInstr::Goto(final_exit));
|
||||||
|
instrs.push(IRInstr::Label(final_exit));
|
||||||
|
}
|
||||||
return Some((instrs, Some(dest_var)));
|
return Some((instrs, Some(dest_var)));
|
||||||
} else {
|
} else {
|
||||||
if op.is_cmp() {
|
if op.is_cmp() {
|
||||||
@@ -713,12 +771,13 @@ impl<'a> Generator<'a> {
|
|||||||
let mut arg_vars = vec![];
|
let mut arg_vars = vec![];
|
||||||
let func_def = self.ir_function(func_id);
|
let func_def = self.ir_function(func_id);
|
||||||
|
|
||||||
for arg in args.into_iter() {
|
for (arg, param_type) in args.into_iter().zip(func_def.parameter_types.iter()) {
|
||||||
self.current_exit_label.push(None);
|
self.current_exit_label.push(None);
|
||||||
let (arg_instrs, arg_var) = self.generate_expr(arg)?;
|
let (mut arg_instrs, arg_var) = self.generate_expr(arg)?;
|
||||||
self.current_exit_label.pop();
|
self.current_exit_label.pop();
|
||||||
|
let arg_var = self.coerce_value(&mut arg_instrs, arg_var.unwrap(), param_type);
|
||||||
instrs.extend(arg_instrs);
|
instrs.extend(arg_instrs);
|
||||||
arg_vars.push(arg_var.unwrap());
|
arg_vars.push(arg_var);
|
||||||
}
|
}
|
||||||
let ret_variable = if matches!(func_def.return_type, IRType::Void) {
|
let ret_variable = if matches!(func_def.return_type, IRType::Void) {
|
||||||
None
|
None
|
||||||
@@ -730,10 +789,15 @@ impl<'a> Generator<'a> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Some((true_exit, false_exit)) = self.current_exit_label.last().cloned().flatten() {
|
if let Some((true_exit, false_exit)) = self.current_exit_label.last().cloned().flatten() {
|
||||||
let cmp_var = self.var_manager.declare_temp(IRType::I1);
|
let var = var.clone().unwrap();
|
||||||
instrs.push(IRInstr::Cmp(cmp_var.clone(), VariableOrIntLit::Var(var.clone().unwrap()), CmpOp::Ne, VariableOrIntLit::IntLit(0)));
|
if matches!(var.data_type, IRType::Array(_, _) | IRType::Ptr(_)) {
|
||||||
instrs.push(IRInstr::CondGoto(cmp_var, true_exit, false_exit));
|
instrs.push(IRInstr::Goto(true_exit));
|
||||||
Some((instrs, var))
|
} else {
|
||||||
|
let cmp_var = self.var_manager.declare_temp(IRType::I1);
|
||||||
|
instrs.push(IRInstr::Cmp(cmp_var.clone(), VariableOrIntLit::Var(var.clone()), CmpOp::Ne, VariableOrIntLit::IntLit(0)));
|
||||||
|
instrs.push(IRInstr::CondGoto(cmp_var, true_exit, false_exit));
|
||||||
|
}
|
||||||
|
Some((instrs, Some(var)))
|
||||||
} else {
|
} else {
|
||||||
Some((instrs, var))
|
Some((instrs, var))
|
||||||
}
|
}
|
||||||
@@ -777,12 +841,13 @@ impl<'a> Generator<'a> {
|
|||||||
let (index_instrs, index_var) = self.generate_expr(index)?;
|
let (index_instrs, index_var) = self.generate_expr(index)?;
|
||||||
self.current_exit_label.pop();
|
self.current_exit_label.pop();
|
||||||
instrs.extend(index_instrs);
|
instrs.extend(index_instrs);
|
||||||
|
let index_var = self.coerce_value(&mut instrs, index_var.unwrap(), &IRType::I32);
|
||||||
let addr_ty = IRType::Ptr(Box::new(elem_ty.into()));
|
let addr_ty = IRType::Ptr(Box::new(elem_ty.into()));
|
||||||
let dest = self.var_manager.declare_temp(addr_ty);
|
let dest = self.var_manager.declare_temp(addr_ty);
|
||||||
let elem_size_var = self.var_manager.declare_temp(IRType::I32);
|
let elem_size_var = self.var_manager.declare_temp(IRType::I32);
|
||||||
let offset = self.var_manager.declare_temp(IRType::I32);
|
let offset = self.var_manager.declare_temp(IRType::I32);
|
||||||
instrs.push(IRInstr::Move(elem_size_var.clone(), MoveRValue::ConstInt(elem_size as i32)));
|
instrs.push(IRInstr::Move(elem_size_var.clone(), MoveRValue::ConstInt(elem_size as i32)));
|
||||||
instrs.push(IRInstr::Binary(offset.clone(), index_var.unwrap(), AstBinaryOp::Mul.into(), elem_size_var));
|
instrs.push(IRInstr::Binary(offset.clone(), index_var, AstBinaryOp::Mul.into(), elem_size_var));
|
||||||
instrs.push(IRInstr::Binary(dest.clone(), base, AstBinaryOp::Add.into(), offset));
|
instrs.push(IRInstr::Binary(dest.clone(), base, AstBinaryOp::Add.into(), offset));
|
||||||
Some((instrs, dest))
|
Some((instrs, dest))
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -124,10 +124,11 @@ impl IRType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_elevate_result(lhs: &IRType, rhs: &IRType) -> Option<IRType> {
|
pub fn get_elevate_result(lhs: &IRType, rhs: &IRType) -> Option<IRType> {
|
||||||
|
if matches!((lhs, rhs), (IRType::I32 | IRType::I1, IRType::I32 | IRType::I1)) {
|
||||||
|
return Some(IRType::I32);
|
||||||
|
}
|
||||||
if lhs == rhs {
|
if lhs == rhs {
|
||||||
Some(lhs.clone())
|
Some(lhs.clone())
|
||||||
} else if (*lhs == IRType::I32 && *rhs == IRType::I1) || (*lhs == IRType::I1 && *rhs == IRType::I32) {
|
|
||||||
Some(IRType::I32)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -34,8 +34,8 @@ pub enum SemaError {
|
|||||||
ReturnExpressionOnVoidFunction,
|
ReturnExpressionOnVoidFunction,
|
||||||
#[error("array dimension must be a positive integer literal")]
|
#[error("array dimension must be a positive integer literal")]
|
||||||
InvalidArrayDimension,
|
InvalidArrayDimension,
|
||||||
#[error("subscripted value is not an array or pointer")]
|
#[error("subscripted value of type `{0}` is not an array or pointer")]
|
||||||
NotSubscriptable,
|
NotSubscriptable(SemaType),
|
||||||
#[error("initializer element is not constant")]
|
#[error("initializer element is not constant")]
|
||||||
InitializerNotConstant,
|
InitializerNotConstant,
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -13,10 +13,11 @@ pub enum SemaType {
|
|||||||
|
|
||||||
impl SemaType {
|
impl SemaType {
|
||||||
pub fn get_elevate_result(lhs: &SemaType, rhs: &SemaType) -> Option<SemaType> {
|
pub fn get_elevate_result(lhs: &SemaType, rhs: &SemaType) -> Option<SemaType> {
|
||||||
|
if matches!((lhs, rhs), (SemaType::I32 | SemaType::I1, SemaType::I32 | SemaType::I1)) {
|
||||||
|
return Some(SemaType::I32);
|
||||||
|
}
|
||||||
if lhs == rhs {
|
if lhs == rhs {
|
||||||
Some(lhs.clone())
|
Some(lhs.clone())
|
||||||
} else if (*lhs == SemaType::I32 && *rhs == SemaType::I1) || (*lhs == SemaType::I1 && *rhs == SemaType::I32) {
|
|
||||||
Some(SemaType::I32)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user