Added fairly limited type inference
This commit is contained in:
@@ -21,6 +21,7 @@ pub enum Kind {
|
||||
FieldNotFound = 0x0206,
|
||||
InvalidCast = 0x0207,
|
||||
CannotDereference = 0x0209,
|
||||
CannotInferType = 0x020A,
|
||||
|
||||
UninitializedField = 0x0300,
|
||||
|
||||
|
||||
+79
-15
@@ -27,10 +27,22 @@ use std::{
|
||||
|
||||
struct ExpressionContext<'l, 'r> {
|
||||
decl_names: Option<&'r NamePattern>,
|
||||
type_hint: Option<Type<'l>>,
|
||||
builder: Option<&'r mut FunctionBodyBuilder<'l>>,
|
||||
fn_queue: &'r mut FuncQueue<'l>,
|
||||
}
|
||||
|
||||
impl<'l, 'r, 'a> ExpressionContext<'l, 'r> {
|
||||
pub fn with_type_hit(&'a mut self, type_hint: Option<Type<'l>>) -> ExpressionContext<'l, 'a> {
|
||||
ExpressionContext {
|
||||
decl_names: self.decl_names,
|
||||
type_hint,
|
||||
builder: self.builder.as_mut().map(|b| &mut **b),
|
||||
fn_queue: self.fn_queue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Variable<'l> {
|
||||
value: Arc<OnceLock<AnyValue<'l>>>,
|
||||
@@ -88,6 +100,7 @@ impl<'l> Scope<'l> {
|
||||
&mut ExpressionContext {
|
||||
decl_names: Some(&val.names),
|
||||
builder: None,
|
||||
type_hint: None,
|
||||
fn_queue,
|
||||
},
|
||||
)?;
|
||||
@@ -118,6 +131,7 @@ impl<'l> Scope<'l> {
|
||||
&mut ExpressionContext {
|
||||
builder: Some(&mut builder),
|
||||
decl_names: None,
|
||||
type_hint: Some(func.ty.ret_t),
|
||||
fn_queue: fn_queue,
|
||||
},
|
||||
)?;
|
||||
@@ -208,7 +222,20 @@ impl<'l> Scope<'l> {
|
||||
};
|
||||
}
|
||||
match n.r#type.as_ref().map(|v| v.as_str()) {
|
||||
None if ctx.type_hint == Some(Type::I8) => parse_number!(i8, I8),
|
||||
None if ctx.type_hint == Some(Type::I16) => parse_number!(i16, I16),
|
||||
None if ctx.type_hint == Some(Type::I32) => parse_number!(i32, I32),
|
||||
None if ctx.type_hint == Some(Type::I64) => parse_number!(i64, I64),
|
||||
None if ctx.type_hint == Some(Type::I128) => parse_number!(i128, I128),
|
||||
None if ctx.type_hint == Some(Type::ISIZE) => parse_number!(i64, ISize),
|
||||
None if ctx.type_hint == Some(Type::U8) => parse_number!(u8, U8),
|
||||
None if ctx.type_hint == Some(Type::U16) => parse_number!(u16, U16),
|
||||
None if ctx.type_hint == Some(Type::U32) => parse_number!(u32, U32),
|
||||
None if ctx.type_hint == Some(Type::U64) => parse_number!(u64, U64),
|
||||
None if ctx.type_hint == Some(Type::U128) => parse_number!(u128, U128),
|
||||
None if ctx.type_hint == Some(Type::USIZE) => parse_number!(u64, USize),
|
||||
None => parse_number!(i64, ISize),
|
||||
|
||||
Some("i8") => parse_number!(i8, I8),
|
||||
Some("i16") => parse_number!(i16, I16),
|
||||
Some("i32") => parse_number!(i32, I32),
|
||||
@@ -297,11 +324,20 @@ impl<'l> Scope<'l> {
|
||||
} = &**bin_expr;
|
||||
|
||||
let mut lhs = self.compile_expression(lhs_expr, ctx)?;
|
||||
if lhs.is_lvalue() && !matches!(op, BinaryOp::Assign(_)) {
|
||||
lhs = ctx.builder.as_mut().unwrap().load(lhs).unwrap();
|
||||
}
|
||||
let type_hint = if lhs.is_lvalue() {
|
||||
let Type::Ptr(PtrT { base, .. }) = lhs.ty() else {
|
||||
unreachable!();
|
||||
};
|
||||
if !matches!(op, BinaryOp::Assign(_)) {
|
||||
lhs = ctx.builder.as_mut().unwrap().load(lhs).unwrap();
|
||||
}
|
||||
*base
|
||||
} else {
|
||||
lhs.ty()
|
||||
};
|
||||
|
||||
let mut rhs = self.compile_expression(rhs_expr, ctx)?;
|
||||
let mut rhs =
|
||||
self.compile_expression(rhs_expr, &mut ctx.with_type_hit(Some(type_hint)))?;
|
||||
if rhs.is_lvalue() {
|
||||
rhs = ctx.builder.as_mut().unwrap().load(rhs).unwrap();
|
||||
}
|
||||
@@ -508,9 +544,11 @@ impl<'l> Scope<'l> {
|
||||
});
|
||||
}
|
||||
};
|
||||
let mut arg_ty = func.ty.par_t.iter().cloned();
|
||||
let mut args = Vec::with_capacity(args_exprs.len());
|
||||
for expr in args_exprs {
|
||||
let mut arg = self.compile_expression(expr, ctx)?;
|
||||
let mut arg =
|
||||
self.compile_expression(expr, &mut ctx.with_type_hit(arg_ty.next()))?;
|
||||
if arg.is_lvalue() {
|
||||
arg = ctx.builder.as_mut().unwrap().load(arg).unwrap();
|
||||
}
|
||||
@@ -531,6 +569,7 @@ impl<'l> Scope<'l> {
|
||||
let mut expr_ctx = ExpressionContext {
|
||||
builder: None,
|
||||
decl_names: None,
|
||||
type_hint: Some(Type::Type),
|
||||
fn_queue: ctx.fn_queue,
|
||||
};
|
||||
let ctx = self.assembly.ctx();
|
||||
@@ -731,7 +770,23 @@ impl<'l> Scope<'l> {
|
||||
}
|
||||
|
||||
Expr::Struct(ctor) => {
|
||||
let ty = self.compile_expression(&ctor.r#type, ctx)?;
|
||||
let ty = match &ctor.r#type {
|
||||
Some(ty) => self.compile_expression(ty, ctx)?,
|
||||
None => match ctx.type_hint {
|
||||
Some(ty) => AnyValue::Constant(AnyConst::Type(ty)),
|
||||
None => {
|
||||
return Err(CompilationError {
|
||||
kind: Kind::CannotInferType,
|
||||
message: "Type cannot be inferred.".into(),
|
||||
location: Location::Range {
|
||||
file: self.source.clone(),
|
||||
range: ctor.range(),
|
||||
},
|
||||
cause: None,
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
let AnyValue::Constant(AnyConst::Type(Type::Struct(
|
||||
struct_ty @ StructT { fields, .. },
|
||||
))) = ty
|
||||
@@ -741,7 +796,10 @@ impl<'l> Scope<'l> {
|
||||
message: format!("Expected struct type, got value of type `{}`.", ty.ty()),
|
||||
location: Location::Range {
|
||||
file: self.source.clone(),
|
||||
range: ctor.r#type.range(),
|
||||
range: match &ctor.r#type {
|
||||
None => ctor.range(),
|
||||
Some(ty) => ty.range(),
|
||||
},
|
||||
},
|
||||
cause: None,
|
||||
});
|
||||
@@ -765,7 +823,8 @@ impl<'l> Scope<'l> {
|
||||
cause: None,
|
||||
});
|
||||
};
|
||||
let value = self.compile_expression(&name_value_pair.value, ctx)?;
|
||||
let mut ctx = ctx.with_type_hit(Some(*ty));
|
||||
let value = self.compile_expression(&name_value_pair.value, &mut ctx)?;
|
||||
self.assert_ty_eq(&value, &name_value_pair.value, ty)?;
|
||||
non_const |= !value.flags().contains(ValueFlags::Const);
|
||||
values.push(value);
|
||||
@@ -844,6 +903,7 @@ impl<'l> Scope<'l> {
|
||||
let mut sub_ctx = ExpressionContext {
|
||||
decl_names: Some(names),
|
||||
builder: ctx.builder.as_deref_mut(),
|
||||
type_hint: None, //TODO
|
||||
fn_queue: ctx.fn_queue,
|
||||
};
|
||||
let mut value = self.compile_expression(value, &mut sub_ctx)?;
|
||||
@@ -874,19 +934,23 @@ impl<'l> Scope<'l> {
|
||||
|
||||
fn compile_block(
|
||||
&mut self,
|
||||
expr: &Block,
|
||||
block: &Block,
|
||||
ctx: &mut ExpressionContext<'l, '_>,
|
||||
) -> Result<AnyValue<'l>, CompilationError> {
|
||||
let mut scope = self.clone();
|
||||
let builder = ctx.builder.as_mut().unwrap();
|
||||
let mut ctx = ExpressionContext {
|
||||
builder: Some(builder),
|
||||
decl_names: None,
|
||||
fn_queue: ctx.fn_queue,
|
||||
};
|
||||
|
||||
let mut last_expr = None;
|
||||
for expr in &expr.0 {
|
||||
for (i, expr) in block.0.iter().enumerate() {
|
||||
let mut ctx = ExpressionContext {
|
||||
builder: Some(builder),
|
||||
decl_names: None,
|
||||
type_hint: match i == block.0.len() - 1 {
|
||||
true => ctx.type_hint,
|
||||
false => None,
|
||||
},
|
||||
fn_queue: ctx.fn_queue,
|
||||
};
|
||||
last_expr = Some(scope.compile_expression(expr, &mut ctx)?);
|
||||
}
|
||||
Ok(last_expr.unwrap_or(AnyValue::Constant(AnyConst::Void)))
|
||||
|
||||
Reference in New Issue
Block a user