Finish second phase of typechecking, resolve hinted values

This commit is contained in:
Sofia 2025-07-12 23:35:35 +03:00
parent 61ab5002e4
commit 557d5f9722
3 changed files with 40 additions and 18 deletions

View File

@ -1,4 +1,4 @@
use std::{cell::RefCell, collections::HashMap, fmt::Error, rc::Rc}; use std::{cell::RefCell, collections::HashMap, rc::Rc};
use super::{ use super::{
typecheck::{Collapsable, ErrorKind}, typecheck::{Collapsable, ErrorKind},
@ -9,12 +9,8 @@ use super::{
pub struct ScopeHint<'scope>(TypeIdRef, &'scope ScopeHints<'scope>); pub struct ScopeHint<'scope>(TypeIdRef, &'scope ScopeHints<'scope>);
impl<'scope> ScopeHint<'scope> { impl<'scope> ScopeHint<'scope> {
pub unsafe fn raw_type(&self) -> TypeKind { pub unsafe fn resolve_type(&self) -> TypeKind {
if let Some(ty) = self.1.types.hints.borrow().get(*self.0.borrow()) { unsafe { *self.1.types.hints.borrow().get_unchecked(*self.0.borrow()) }
*ty
} else {
panic!("TODO")
}
} }
pub fn narrow(&mut self, ty_ref: &TypeRef) -> Result<ScopeHint<'scope>, ErrorKind> { pub fn narrow(&mut self, ty_ref: &TypeRef) -> Result<ScopeHint<'scope>, ErrorKind> {
@ -33,7 +29,7 @@ impl<'scope> std::fmt::Debug for ScopeHint<'scope> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Hint") f.debug_tuple("Hint")
.field(&self.0) .field(&self.0)
.field(unsafe { &self.raw_type() }) .field(unsafe { &self.resolve_type() })
.finish() .finish()
} }
} }
@ -74,6 +70,22 @@ impl<'outer> ScopeHints<'outer> {
} }
} }
pub fn retrieve_type(&self, mut idx: usize) -> Option<TypeKind> {
// Just make sure we have the correct idx
let mut inner_idx = self.types.types.borrow().get(idx).map(|i| *i.borrow())?;
let mut limit = 50;
while inner_idx != idx {
idx = inner_idx;
inner_idx = self.types.types.borrow().get(idx).map(|i| *i.borrow())?;
limit -= 1;
if limit < 0 {
// Should never happen, but just to avoid infinite loops
panic!("Limit reached!");
}
}
self.types.hints.borrow().get(inner_idx).copied()
}
pub fn new_var( pub fn new_var(
&'outer self, &'outer self,
name: String, name: String,

View File

@ -84,9 +84,8 @@ impl FunctionDefinition {
let types = TypeHints::default(); let types = TypeHints::default();
let hints = ScopeHints::from(&types); let hints = ScopeHints::from(&types);
if let Ok(_) = block.infer_hints(state, &hints) { if let Ok(_) = block.infer_hints(state, &hints) {
dbg!(&block, &hints); print!("{}", block);
// block.typecheck(state, &hints, Some(return_type)) block.typecheck(state, &hints, Some(return_type))
Ok(Vague(Unknown))
} else { } else {
Ok(Vague(Unknown)) Ok(Vague(Unknown))
} }
@ -130,7 +129,6 @@ impl Block {
} }
StmtKind::Set(var, expr) => { StmtKind::Set(var, expr) => {
let var_ref = inner_hints.find_hint(&var.1); let var_ref = inner_hints.find_hint(&var.1);
dbg!(&var_ref);
if let Some((_, var_ref)) = &var_ref { if let Some((_, var_ref)) = &var_ref {
var.0 = var_ref.as_type() var.0 = var_ref.as_type()
} }
@ -181,7 +179,11 @@ impl Block {
for statement in &mut self.statements { for statement in &mut self.statements {
let ret = match &mut statement.0 { let ret = match &mut statement.0 {
StmtKind::Let(variable_reference, mutable, expression) => { StmtKind::Let(variable_reference, mutable, expression) => {
let res = expression.typecheck(&mut state, &hints, Some(variable_reference.0)); // Resolve possible hint in var reference
let var_t_resolved = variable_reference.0.resolve_hinted(&hints);
// Typecheck (and coerce) expression with said type
let res = expression.typecheck(&mut state, &hints, Some(var_t_resolved));
// If expression resolution itself was erronous, resolve as // If expression resolution itself was erronous, resolve as
// Unknown. // Unknown.
@ -189,7 +191,7 @@ impl Block {
// Make sure the expression and variable type really is the same // Make sure the expression and variable type really is the same
let res_t = state.or_else( let res_t = state.or_else(
res.collapse_into(&variable_reference.0), res.collapse_into(&var_t_resolved),
Vague(Unknown), Vague(Unknown),
variable_reference.2 + expression.1, variable_reference.2 + expression.1,
); );
@ -240,7 +242,7 @@ impl Block {
// Make sure the expression and variable type to really // Make sure the expression and variable type to really
// be the same // be the same
let res_t = state.or_else( let res_t = state.or_else(
expr_ty.collapse_into(&variable_reference.0), expr_ty.collapse_into(&variable_reference.0.resolve_hinted(&hints)),
Vague(Unknown), Vague(Unknown),
variable_reference.2 + expression.1, variable_reference.2 + expression.1,
); );
@ -413,7 +415,7 @@ impl Expression {
// Update typing to be more accurate // Update typing to be more accurate
var_ref.0 = state.or_else( var_ref.0 = state.or_else(
var_ref.0.collapse_into(&existing), var_ref.0.resolve_hinted(hints).collapse_into(&existing),
Vague(Unknown), Vague(Unknown),
var_ref.2, var_ref.2,
); );
@ -479,7 +481,9 @@ impl Expression {
// Make sure function return type is the same as the claimed // Make sure function return type is the same as the claimed
// return type // return type
let ret_t = f.ret.collapse_into(&function_call.return_type)?; let ret_t = f
.ret
.collapse_into(&function_call.return_type.resolve_hinted(hints))?;
// Update typing to be more accurate // Update typing to be more accurate
function_call.return_type = ret_t; function_call.return_type = ret_t;
Ok(ret_t) Ok(ret_t)
@ -592,6 +596,13 @@ impl TypeKind {
BinaryOperator::Cmp(_) => Bool, BinaryOperator::Cmp(_) => Bool,
}) })
} }
fn resolve_hinted(&self, hints: &ScopeHints) -> TypeKind {
match self {
Vague(Hinted(idx)) => hints.retrieve_type(*idx).unwrap(),
_ => *self,
}
}
} }
pub trait Collapsable: Sized + Clone { pub trait Collapsable: Sized + Clone {

View File

@ -82,7 +82,6 @@ impl ReturnType for IfExpression {
let then_r = self.1.return_type()?; let then_r = self.1.return_type()?;
if let Some(else_b) = &self.2 { if let Some(else_b) = &self.2 {
let else_r = else_b.return_type()?; let else_r = else_b.return_type()?;
dbg!(&then_r, &else_r);
let kind = if then_r.0 == ReturnKind::Hard && else_r.0 == ReturnKind::Hard { let kind = if then_r.0 == ReturnKind::Hard && else_r.0 == ReturnKind::Hard {
ReturnKind::Hard ReturnKind::Hard