Added fairly limited type inference

This commit is contained in:
Mia
2026-03-07 19:16:29 +01:00
parent 168a12b4fc
commit 2aababbbe1
5 changed files with 102 additions and 18 deletions
+3
View File
@@ -492,6 +492,9 @@ impl<'l> CompilationContext<'l> {
AnyConst::Int(Int::USize(v)) => { AnyConst::Int(Int::USize(v)) => {
Some(self.native_int_ty.const_int(*v as u64, false).into()) Some(self.native_int_ty.const_int(*v as u64, false).into())
} }
AnyConst::Int(Int::ISize(v)) => {
Some(self.native_int_ty.const_int(*v as u64, true).into())
}
AnyConst::Array([]) => todo!("{val:?}"), AnyConst::Array([]) => todo!("{val:?}"),
AnyConst::Array(array) => { AnyConst::Array(array) => {
+1
View File
@@ -21,6 +21,7 @@ pub enum Kind {
FieldNotFound = 0x0206, FieldNotFound = 0x0206,
InvalidCast = 0x0207, InvalidCast = 0x0207,
CannotDereference = 0x0209, CannotDereference = 0x0209,
CannotInferType = 0x020A,
UninitializedField = 0x0300, UninitializedField = 0x0300,
+74 -10
View File
@@ -27,10 +27,22 @@ use std::{
struct ExpressionContext<'l, 'r> { struct ExpressionContext<'l, 'r> {
decl_names: Option<&'r NamePattern>, decl_names: Option<&'r NamePattern>,
type_hint: Option<Type<'l>>,
builder: Option<&'r mut FunctionBodyBuilder<'l>>, builder: Option<&'r mut FunctionBodyBuilder<'l>>,
fn_queue: &'r mut FuncQueue<'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)] #[derive(Clone)]
struct Variable<'l> { struct Variable<'l> {
value: Arc<OnceLock<AnyValue<'l>>>, value: Arc<OnceLock<AnyValue<'l>>>,
@@ -88,6 +100,7 @@ impl<'l> Scope<'l> {
&mut ExpressionContext { &mut ExpressionContext {
decl_names: Some(&val.names), decl_names: Some(&val.names),
builder: None, builder: None,
type_hint: None,
fn_queue, fn_queue,
}, },
)?; )?;
@@ -118,6 +131,7 @@ impl<'l> Scope<'l> {
&mut ExpressionContext { &mut ExpressionContext {
builder: Some(&mut builder), builder: Some(&mut builder),
decl_names: None, decl_names: None,
type_hint: Some(func.ty.ret_t),
fn_queue: fn_queue, fn_queue: fn_queue,
}, },
)?; )?;
@@ -208,7 +222,20 @@ impl<'l> Scope<'l> {
}; };
} }
match n.r#type.as_ref().map(|v| v.as_str()) { 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), None => parse_number!(i64, ISize),
Some("i8") => parse_number!(i8, I8), Some("i8") => parse_number!(i8, I8),
Some("i16") => parse_number!(i16, I16), Some("i16") => parse_number!(i16, I16),
Some("i32") => parse_number!(i32, I32), Some("i32") => parse_number!(i32, I32),
@@ -297,11 +324,20 @@ impl<'l> Scope<'l> {
} = &**bin_expr; } = &**bin_expr;
let mut lhs = self.compile_expression(lhs_expr, ctx)?; let mut lhs = self.compile_expression(lhs_expr, ctx)?;
if lhs.is_lvalue() && !matches!(op, BinaryOp::Assign(_)) { 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(); 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() { if rhs.is_lvalue() {
rhs = ctx.builder.as_mut().unwrap().load(rhs).unwrap(); 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()); let mut args = Vec::with_capacity(args_exprs.len());
for expr in args_exprs { 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() { if arg.is_lvalue() {
arg = ctx.builder.as_mut().unwrap().load(arg).unwrap(); arg = ctx.builder.as_mut().unwrap().load(arg).unwrap();
} }
@@ -531,6 +569,7 @@ impl<'l> Scope<'l> {
let mut expr_ctx = ExpressionContext { let mut expr_ctx = ExpressionContext {
builder: None, builder: None,
decl_names: None, decl_names: None,
type_hint: Some(Type::Type),
fn_queue: ctx.fn_queue, fn_queue: ctx.fn_queue,
}; };
let ctx = self.assembly.ctx(); let ctx = self.assembly.ctx();
@@ -731,7 +770,23 @@ impl<'l> Scope<'l> {
} }
Expr::Struct(ctor) => { 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( let AnyValue::Constant(AnyConst::Type(Type::Struct(
struct_ty @ StructT { fields, .. }, struct_ty @ StructT { fields, .. },
))) = ty ))) = ty
@@ -741,7 +796,10 @@ impl<'l> Scope<'l> {
message: format!("Expected struct type, got value of type `{}`.", ty.ty()), message: format!("Expected struct type, got value of type `{}`.", ty.ty()),
location: Location::Range { location: Location::Range {
file: self.source.clone(), file: self.source.clone(),
range: ctor.r#type.range(), range: match &ctor.r#type {
None => ctor.range(),
Some(ty) => ty.range(),
},
}, },
cause: None, cause: None,
}); });
@@ -765,7 +823,8 @@ impl<'l> Scope<'l> {
cause: None, 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)?; self.assert_ty_eq(&value, &name_value_pair.value, ty)?;
non_const |= !value.flags().contains(ValueFlags::Const); non_const |= !value.flags().contains(ValueFlags::Const);
values.push(value); values.push(value);
@@ -844,6 +903,7 @@ impl<'l> Scope<'l> {
let mut sub_ctx = ExpressionContext { let mut sub_ctx = ExpressionContext {
decl_names: Some(names), decl_names: Some(names),
builder: ctx.builder.as_deref_mut(), builder: ctx.builder.as_deref_mut(),
type_hint: None, //TODO
fn_queue: ctx.fn_queue, fn_queue: ctx.fn_queue,
}; };
let mut value = self.compile_expression(value, &mut sub_ctx)?; let mut value = self.compile_expression(value, &mut sub_ctx)?;
@@ -874,19 +934,23 @@ impl<'l> Scope<'l> {
fn compile_block( fn compile_block(
&mut self, &mut self,
expr: &Block, block: &Block,
ctx: &mut ExpressionContext<'l, '_>, ctx: &mut ExpressionContext<'l, '_>,
) -> Result<AnyValue<'l>, CompilationError> { ) -> Result<AnyValue<'l>, CompilationError> {
let mut scope = self.clone(); let mut scope = self.clone();
let builder = ctx.builder.as_mut().unwrap(); let builder = ctx.builder.as_mut().unwrap();
let mut last_expr = None;
for (i, expr) in block.0.iter().enumerate() {
let mut ctx = ExpressionContext { let mut ctx = ExpressionContext {
builder: Some(builder), builder: Some(builder),
decl_names: None, decl_names: None,
type_hint: match i == block.0.len() - 1 {
true => ctx.type_hint,
false => None,
},
fn_queue: ctx.fn_queue, fn_queue: ctx.fn_queue,
}; };
let mut last_expr = None;
for expr in &expr.0 {
last_expr = Some(scope.compile_expression(expr, &mut ctx)?); last_expr = Some(scope.compile_expression(expr, &mut ctx)?);
} }
Ok(last_expr.unwrap_or(AnyValue::Constant(AnyConst::Void))) Ok(last_expr.unwrap_or(AnyValue::Constant(AnyConst::Void)))
+8 -1
View File
@@ -178,8 +178,15 @@ pub struct Field {
#[derive(Debug)] #[derive(Debug)]
pub struct StructCtor { pub struct StructCtor {
pub r#type: Expr, pub r#type: Option<Expr>,
pub r#values: IndexMap<Substr, NameValuePair>, pub r#values: IndexMap<Substr, NameValuePair>,
pub(crate) range: Range<usize>,
}
impl StructCtor {
pub fn range(&self) -> Range<usize> {
self.range.clone()
}
} }
#[derive(Debug)] #[derive(Debug)]
+11 -2
View File
@@ -81,9 +81,18 @@ peg::parser! {
lhs:@ "(" __ args:(expr() ** list_separator()) __ ")" { Expr::Call { func: lhs.into(), args } } lhs:@ "(" __ args:(expr() ** list_separator()) __ ")" { Expr::Call { func: lhs.into(), args } }
value:@ "[" __ index:expr() __ "]" { Expr::Index(IndexingExpr { value, index }.into()) } value:@ "[" __ index:expr() __ "]" { Expr::Index(IndexingExpr { value, index }.into()) }
r#type:@ __ "#{" __ values:name_value_pairs() __ "}" { Expr::Struct( ty:@ __ "#{" __ values:name_value_pairs() __ "}" e:position!() { Expr::Struct(
StructCtor { StructCtor {
r#type, values: values.into_iter().map(|v| (v.name.0.clone(), v)).collect() range: ty.range().start..e,
r#type: Some(ty),
values: values.into_iter().map(|v| (v.name.0.clone(), v)).collect(),
}.into()
) }
s:position!() "#{" __ values:name_value_pairs() __ "}" e:position!() { Expr::Struct(
StructCtor {
r#type: None,
values: values.into_iter().map(|v| (v.name.0.clone(), v)).collect(),
range: s..e,
}.into() }.into()
) } ) }
-- --