Use FunctionDefinitionKind for binops

This commit is contained in:
Sofia 2025-07-24 13:40:06 +03:00
parent 7c6de93b31
commit a7795f83db
5 changed files with 85 additions and 37 deletions

View File

@ -111,7 +111,10 @@ impl ast::Module {
op: op.mir(),
rhs: (rhs.0.clone(), rhs.1 .0.into_mir(module_id)),
return_ty: return_ty.0.into_mir(module_id),
block: block.into_mir(module_id),
fn_kind: mir::FunctionDefinitionKind::Local(
block.into_mir(module_id),
block.2.as_meta(module_id),
),
meta: signature_range.as_meta(module_id),
});
}

View File

@ -66,7 +66,7 @@ impl Display for BinopDefinition {
"impl binop ({}: {:#}) {} ({}: {:#}) -> {:#} ",
self.lhs.0, self.lhs.1, self.op, self.rhs.0, self.rhs.1, self.return_ty
)?;
Display::fmt(&self.block, f)
Display::fmt(&self.fn_kind, f)
}
}

View File

@ -371,13 +371,17 @@ pub struct BinopDefinition {
pub op: BinaryOperator,
pub rhs: (String, TypeKind),
pub return_ty: TypeKind,
pub block: Block,
pub fn_kind: FunctionDefinitionKind,
pub meta: Metadata,
}
impl BinopDefinition {
pub fn block_meta(&self) -> Metadata {
self.block.meta
pub fn block_meta(&self) -> Option<Metadata> {
match &self.fn_kind {
FunctionDefinitionKind::Local(block, _) => Some(block.meta),
FunctionDefinitionKind::Extern(_) => None,
FunctionDefinitionKind::Intrinsic(_) => None,
}
}
pub fn signature(&self) -> Metadata {

View File

@ -136,7 +136,7 @@ impl<'t> Pass for TypeCheck<'t> {
for binop in &mut module.binop_defs {
let res = binop.typecheck(&self.refs, &mut state.inner());
state.ok(res, binop.block_meta());
state.ok(res, binop.block_meta().unwrap_or(binop.signature()));
}
for function in &mut module.functions {
@ -206,15 +206,19 @@ impl BinopDefinition {
let return_type = self.return_ty.clone().assert_known(typerefs, state)?;
state.scope.return_type_hint = Some(self.return_ty.clone());
let inferred = self
.block
.typecheck(&mut state.inner(), &typerefs, Some(&return_type));
let inferred =
self.fn_kind
.typecheck(&typerefs, &mut state.inner(), Some(return_type.clone()));
match inferred {
Ok(t) => return_type
.collapse_into(&t.1)
.or(Err(ErrorKind::ReturnTypeMismatch(return_type, t.1))),
Err(e) => Ok(state.or_else(Err(e), return_type, self.block_meta())),
Err(e) => Ok(state.or_else(
Err(e),
return_type,
self.block_meta().unwrap_or(self.signature()),
)),
}
}
}
@ -246,10 +250,30 @@ impl FunctionDefinition {
}
let return_type = self.return_type.clone().assert_known(typerefs, state)?;
let inferred = match &mut self.kind {
let inferred = self
.kind
.typecheck(typerefs, state, Some(self.return_type.clone()));
match inferred {
Ok(t) => return_type
.collapse_into(&t.1)
.or(Err(ErrorKind::ReturnTypeMismatch(return_type, t.1))),
Err(e) => Ok(state.or_else(Err(e), return_type, self.block_meta())),
}
}
}
impl FunctionDefinitionKind {
fn typecheck(
&mut self,
typerefs: &TypeRefs,
state: &mut TypecheckPassState,
hint: Option<TypeKind>,
) -> Result<(ReturnKind, TypeKind), ErrorKind> {
match self {
FunctionDefinitionKind::Local(block, _) => {
state.scope.return_type_hint = Some(self.return_type.clone());
block.typecheck(&mut state.inner(), &typerefs, Some(&return_type))
state.scope.return_type_hint = hint.clone();
block.typecheck(&mut state.inner(), &typerefs, hint.as_ref())
}
FunctionDefinitionKind::Extern(_) => {
Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown)))
@ -257,13 +281,6 @@ impl FunctionDefinition {
FunctionDefinitionKind::Intrinsic(..) => {
Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown)))
}
};
match inferred {
Ok(t) => return_type
.collapse_into(&t.1)
.or(Err(ErrorKind::ReturnTypeMismatch(return_type, t.1))),
Err(e) => Ok(state.or_else(Err(e), return_type, self.block_meta())),
}
}
}

View File

@ -80,7 +80,7 @@ impl<'t> Pass for TypeInference<'t> {
for binop in &mut module.binop_defs {
let res = binop.infer_types(&self.refs, &mut state.inner());
state.ok(res, binop.block_meta());
state.ok(res, binop.block_meta().unwrap_or(binop.signature()));
}
for function in &mut module.functions {
@ -124,18 +124,12 @@ impl BinopDefinition {
self.signature(),
);
state.scope.return_type_hint = Some(self.return_ty.clone());
let ret_res = self.block.infer_types(state, &scope_hints);
let (_, mut ret_ty) = state.or_else(
ret_res,
(
ReturnKind::Soft,
scope_hints.from_type(&Vague(Unknown)).unwrap(),
),
self.block_meta(),
);
ret_ty.narrow(&scope_hints.from_type(&self.return_ty).unwrap());
let ret_ty = self
.fn_kind
.infer_types(state, &scope_hints, Some(self.return_ty.clone()))?;
if let Some(mut ret_ty) = ret_ty {
ret_ty.narrow(&scope_hints.from_type(&self.return_ty).unwrap());
}
Ok(())
}
@ -147,10 +141,10 @@ impl FunctionDefinition {
type_refs: &TypeRefs,
state: &mut TypeInferencePassState,
) -> Result<(), ErrorKind> {
let scope_hints = ScopeTypeRefs::from(type_refs);
let scope_refs = ScopeTypeRefs::from(type_refs);
for param in &self.parameters {
let param_t = state.or_else(param.1.assert_unvague(), Vague(Unknown), self.signature());
let res = scope_hints
let res = scope_refs
.new_var(param.0.clone(), false, &param_t)
.or(Err(ErrorKind::VariableAlreadyDefined(param.0.clone())));
state.ok(res, self.signature());
@ -161,21 +155,51 @@ impl FunctionDefinition {
state.scope.return_type_hint = Some(self.return_type.clone());
// Infer block return type
let ret_res = block.infer_types(state, &scope_hints);
let ret_res = block.infer_types(state, &scope_refs);
// Narrow block type to declared function type
if let Some(mut ret_ty) = state.ok(ret_res.map(|(_, ty)| ty), self.block_meta()) {
ret_ty.narrow(&scope_hints.from_type(&self.return_type).unwrap());
ret_ty.narrow(&scope_refs.from_type(&self.return_type).unwrap());
}
}
FunctionDefinitionKind::Extern(_) => {}
FunctionDefinitionKind::Intrinsic(_) => {}
};
let return_ty = self
.kind
.infer_types(state, &scope_refs, Some(self.return_type.clone()));
if let Some(Some(mut ret_ty)) = state.ok(return_ty, self.block_meta()) {
ret_ty.narrow(&scope_refs.from_type(&self.return_type).unwrap());
}
Ok(())
}
}
impl FunctionDefinitionKind {
fn infer_types<'s>(
&mut self,
state: &mut TypeInferencePassState,
scope_refs: &'s ScopeTypeRefs,
hint: Option<TypeKind>,
) -> Result<Option<TypeRef<'s>>, ErrorKind> {
Ok(match self {
FunctionDefinitionKind::Local(block, _) => {
state.scope.return_type_hint = hint;
// Infer block return type
let ret_res = block.infer_types(state, &scope_refs);
// Narrow block type to declared function type
Some(ret_res.map(|(_, ty)| ty)?)
}
FunctionDefinitionKind::Extern(_) => None,
FunctionDefinitionKind::Intrinsic(_) => None,
})
}
}
impl Block {
fn infer_types<'s>(
&mut self,