Move type checking properly to the typecheck-stage
This commit is contained in:
		
							parent
							
								
									92736e392e
								
							
						
					
					
						commit
						a8ed7577a8
					
				@ -8,8 +8,8 @@ use VagueType::*;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use super::{
 | 
					use super::{
 | 
				
			||||||
    pass::{Pass, PassState, ScopeFunction, ScopeVariable},
 | 
					    pass::{Pass, PassState, ScopeFunction, ScopeVariable},
 | 
				
			||||||
    typerefs::{ScopeTypeRefs, TypeRef, TypeRefs},
 | 
					    typerefs::TypeRefs,
 | 
				
			||||||
    types::{pick_return, ReturnType},
 | 
					    types::ReturnType,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(thiserror::Error, Debug, Clone)]
 | 
					#[derive(thiserror::Error, Debug, Clone)]
 | 
				
			||||||
@ -129,10 +129,6 @@ impl Block {
 | 
				
			|||||||
                    );
 | 
					                    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    let res_t = if res_t.known().is_err() {
 | 
					                    let res_t = if res_t.known().is_err() {
 | 
				
			||||||
                        // state.ok::<_, Infallible>(
 | 
					 | 
				
			||||||
                        //     Err(ErrorKind::TypeNotInferrable(res_t)),
 | 
					 | 
				
			||||||
                        //     variable_reference.2 + expression.1,
 | 
					 | 
				
			||||||
                        // );
 | 
					 | 
				
			||||||
                        // Unable to infer variable type even from expression! Default it
 | 
					                        // Unable to infer variable type even from expression! Default it
 | 
				
			||||||
                        let res_t =
 | 
					                        let res_t =
 | 
				
			||||||
                            state.or_else(res_t.or_default(), Vague(Unknown), variable_reference.2);
 | 
					                            state.or_else(res_t.or_default(), Vague(Unknown), variable_reference.2);
 | 
				
			||||||
@ -146,7 +142,7 @@ impl Block {
 | 
				
			|||||||
                        res_t
 | 
					                        res_t
 | 
				
			||||||
                    };
 | 
					                    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    // Update typing to be more accurate
 | 
					                    // Update typing
 | 
				
			||||||
                    variable_reference.0 = res_t;
 | 
					                    variable_reference.0 = res_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    // Variable might already be defined, note error
 | 
					                    // Variable might already be defined, note error
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,15 @@
 | 
				
			|||||||
use std::iter;
 | 
					//! Type Inference is a pass where all of the potentially vague types are went
 | 
				
			||||||
 | 
					//! through, stored in an intermediary storage [`TypeRefs`], and then the types
 | 
				
			||||||
 | 
					//! in MIR are changed to [`TypeKind::TypeRef`]s with the correct ID. This MIR
 | 
				
			||||||
 | 
					//! must then be passed through TypeCheck with the same [`TypeRefs`] in order to
 | 
				
			||||||
 | 
					//! place the correct types from the IDs and check that there are no issues.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use reid_lib::Function;
 | 
					use std::iter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::{
 | 
					use super::{
 | 
				
			||||||
    pass::{Pass, PassState, ScopeVariable},
 | 
					    pass::{Pass, PassState, ScopeVariable},
 | 
				
			||||||
    typecheck::ErrorKind,
 | 
					    typecheck::ErrorKind,
 | 
				
			||||||
    typerefs::{self, ScopeTypeRefs, TypeRef, TypeRefs},
 | 
					    typerefs::{ScopeTypeRefs, TypeRef, TypeRefs},
 | 
				
			||||||
    types::{pick_return, ReturnType},
 | 
					    types::{pick_return, ReturnType},
 | 
				
			||||||
    Block, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind, IfExpression, Module,
 | 
					    Block, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind, IfExpression, Module,
 | 
				
			||||||
    ReturnKind, StmtKind,
 | 
					    ReturnKind, StmtKind,
 | 
				
			||||||
@ -13,8 +17,9 @@ use super::{
 | 
				
			|||||||
    VagueType::*,
 | 
					    VagueType::*,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Struct used to implement a type-checking pass that can be performed on the
 | 
					/// Struct used to implement Type Inference, where an intermediary
 | 
				
			||||||
/// MIR.
 | 
					/// TypeRefs-struct is used as a helper to go through the modules and change
 | 
				
			||||||
 | 
					/// types while inferring.
 | 
				
			||||||
pub struct TypeInference<'t> {
 | 
					pub struct TypeInference<'t> {
 | 
				
			||||||
    pub refs: &'t TypeRefs,
 | 
					    pub refs: &'t TypeRefs,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -24,14 +29,14 @@ impl<'t> Pass for TypeInference<'t> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    fn module(&mut self, module: &mut Module, mut state: PassState<ErrorKind>) {
 | 
					    fn module(&mut self, module: &mut Module, mut state: PassState<ErrorKind>) {
 | 
				
			||||||
        for function in &mut module.functions {
 | 
					        for function in &mut module.functions {
 | 
				
			||||||
            let res = function.infer_hints(&self.refs, &mut state);
 | 
					            let res = function.infer_types(&self.refs, &mut state);
 | 
				
			||||||
            state.ok(res, function.block_meta());
 | 
					            state.ok(res, function.block_meta());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl FunctionDefinition {
 | 
					impl FunctionDefinition {
 | 
				
			||||||
    fn infer_hints(
 | 
					    fn infer_types(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        type_refs: &TypeRefs,
 | 
					        type_refs: &TypeRefs,
 | 
				
			||||||
        state: &mut PassState<ErrorKind>,
 | 
					        state: &mut PassState<ErrorKind>,
 | 
				
			||||||
@ -51,29 +56,29 @@ impl FunctionDefinition {
 | 
				
			|||||||
                .or(Err(ErrorKind::VariableAlreadyDefined(param.0.clone())));
 | 
					                .or(Err(ErrorKind::VariableAlreadyDefined(param.0.clone())));
 | 
				
			||||||
            state.ok(res, self.signature());
 | 
					            state.ok(res, self.signature());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        let scope_hints = ScopeTypeRefs::from(type_refs);
 | 
					 | 
				
			||||||
        let return_type = self.return_type.clone();
 | 
					 | 
				
			||||||
        let return_type_hint = scope_hints.from_type(&return_type).unwrap();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut ret = match &mut self.kind {
 | 
					        match &mut self.kind {
 | 
				
			||||||
            FunctionDefinitionKind::Local(block, _) => {
 | 
					            FunctionDefinitionKind::Local(block, _) => {
 | 
				
			||||||
                state.scope.return_type_hint = Some(self.return_type);
 | 
					                state.scope.return_type_hint = Some(self.return_type);
 | 
				
			||||||
                let block_res = block.infer_hints(state, &scope_hints);
 | 
					                let scope_hints = ScopeTypeRefs::from(type_refs);
 | 
				
			||||||
                state.ok(block_res.map(|(_, ty)| ty), self.block_meta())
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            FunctionDefinitionKind::Extern => Some(scope_hints.from_type(&Vague(Unknown)).unwrap()),
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if let Some(ret) = &mut ret {
 | 
					                // Infer block return type
 | 
				
			||||||
            state.ok(ret.narrow(&return_type_hint), self.signature());
 | 
					                let ret_res = block.infer_types(state, &scope_hints);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // 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());
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            FunctionDefinitionKind::Extern => {}
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Block {
 | 
					impl Block {
 | 
				
			||||||
    fn infer_hints<'s>(
 | 
					    fn infer_types<'s>(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        state: &mut PassState<ErrorKind>,
 | 
					        state: &mut PassState<ErrorKind>,
 | 
				
			||||||
        outer_hints: &'s ScopeTypeRefs,
 | 
					        outer_hints: &'s ScopeTypeRefs,
 | 
				
			||||||
@ -84,82 +89,110 @@ impl Block {
 | 
				
			|||||||
        for statement in &mut self.statements {
 | 
					        for statement in &mut self.statements {
 | 
				
			||||||
            match &mut statement.0 {
 | 
					            match &mut statement.0 {
 | 
				
			||||||
                StmtKind::Let(var, mutable, expr) => {
 | 
					                StmtKind::Let(var, mutable, expr) => {
 | 
				
			||||||
 | 
					                    // Get the TypeRef for this variable declaration
 | 
				
			||||||
                    let mut var_ref =
 | 
					                    let mut var_ref =
 | 
				
			||||||
                        state.ok(inner_hints.new_var(var.1.clone(), *mutable, var.0), var.2);
 | 
					                        state.ok(inner_hints.new_var(var.1.clone(), *mutable, var.0), var.2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    // If ok, update the MIR type to this TypeRef
 | 
				
			||||||
                    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();
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    let inferred = expr.infer_hints(&mut state, &inner_hints);
 | 
					
 | 
				
			||||||
 | 
					                    // Infer hints for the expression itself
 | 
				
			||||||
 | 
					                    let inferred = expr.infer_types(&mut state, &inner_hints);
 | 
				
			||||||
                    let mut expr_ty_ref = state.ok(inferred, expr.1);
 | 
					                    let mut expr_ty_ref = state.ok(inferred, expr.1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    // Try to narrow the variable type declaration with the
 | 
				
			||||||
 | 
					                    // expression
 | 
				
			||||||
                    if let (Some(var_ref), Some(expr_ty_ref)) =
 | 
					                    if let (Some(var_ref), Some(expr_ty_ref)) =
 | 
				
			||||||
                        (var_ref.as_mut(), expr_ty_ref.as_mut())
 | 
					                        (var_ref.as_mut(), expr_ty_ref.as_mut())
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        state.ok(var_ref.narrow(&expr_ty_ref), var.2 + expr.1);
 | 
					                        var_ref.narrow(&expr_ty_ref);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                StmtKind::Set(var, expr) => {
 | 
					                StmtKind::Set(var, expr) => {
 | 
				
			||||||
 | 
					                    // Get the TypeRef for this variable declaration
 | 
				
			||||||
                    let var_ref = inner_hints.find_hint(&var.1);
 | 
					                    let var_ref = inner_hints.find_hint(&var.1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    // If ok, update the MIR type to this TypeRef
 | 
				
			||||||
                    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()
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    let inferred = expr.infer_hints(&mut state, &inner_hints);
 | 
					
 | 
				
			||||||
 | 
					                    // Infer hints for the expression itself
 | 
				
			||||||
 | 
					                    let inferred = expr.infer_types(&mut state, &inner_hints);
 | 
				
			||||||
                    let expr_ty_ref = state.ok(inferred, expr.1);
 | 
					                    let expr_ty_ref = state.ok(inferred, expr.1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    // Try to narrow the variable type declaration with the
 | 
				
			||||||
 | 
					                    // expression
 | 
				
			||||||
                    if let (Some((_, mut var_ref)), Some(expr_ty_ref)) = (var_ref, expr_ty_ref) {
 | 
					                    if let (Some((_, mut var_ref)), Some(expr_ty_ref)) = (var_ref, expr_ty_ref) {
 | 
				
			||||||
                        state.ok(var_ref.narrow(&expr_ty_ref), var.2 + expr.1);
 | 
					                        var_ref.narrow(&expr_ty_ref);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                StmtKind::Import(_) => todo!(),
 | 
					                StmtKind::Import(_) => todo!(),
 | 
				
			||||||
                StmtKind::Expression(expr) => {
 | 
					                StmtKind::Expression(expr) => {
 | 
				
			||||||
                    let expr_res = expr.infer_hints(&mut state, &inner_hints);
 | 
					                    let expr_res = expr.infer_types(&mut state, &inner_hints);
 | 
				
			||||||
                    state.ok(expr_res, expr.1);
 | 
					                    state.ok(expr_res, expr.1);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // If there is a return expression, infer it's type
 | 
				
			||||||
        if let Some(ret_expr) = &mut self.return_expression {
 | 
					        if let Some(ret_expr) = &mut self.return_expression {
 | 
				
			||||||
            let ret_res = ret_expr.1.infer_hints(&mut state, &inner_hints);
 | 
					            let ret_res = ret_expr.1.infer_types(&mut state, &inner_hints);
 | 
				
			||||||
            state.ok(ret_res, ret_expr.1 .1);
 | 
					            state.ok(ret_res, ret_expr.1 .1);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Fetch the declared return type
 | 
				
			||||||
        let (kind, ty) = self.return_type().ok().unwrap_or((ReturnKind::Soft, Void));
 | 
					        let (kind, ty) = self.return_type().ok().unwrap_or((ReturnKind::Soft, Void));
 | 
				
			||||||
        let mut ret_type_ref = outer_hints.from_type(&ty).unwrap();
 | 
					        let mut ret_type_ref = outer_hints.from_type(&ty).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Narow return type to declared type if hard return
 | 
				
			||||||
        if kind == ReturnKind::Hard {
 | 
					        if kind == ReturnKind::Hard {
 | 
				
			||||||
            if let Some(hint) = state.scope.return_type_hint {
 | 
					            if let Some(hint) = state.scope.return_type_hint {
 | 
				
			||||||
                state.ok(
 | 
					                ret_type_ref.narrow(&mut outer_hints.from_type(&hint).unwrap());
 | 
				
			||||||
                    ret_type_ref.narrow(&mut outer_hints.from_type(&hint).unwrap()),
 | 
					 | 
				
			||||||
                    self.meta,
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Ok((kind, ret_type_ref))
 | 
					        Ok((kind, ret_type_ref))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Expression {
 | 
					impl Expression {
 | 
				
			||||||
    fn infer_hints<'s>(
 | 
					    fn infer_types<'s>(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        state: &mut PassState<ErrorKind>,
 | 
					        state: &mut PassState<ErrorKind>,
 | 
				
			||||||
        type_refs: &'s ScopeTypeRefs<'s>,
 | 
					        type_refs: &'s ScopeTypeRefs<'s>,
 | 
				
			||||||
    ) -> Result<TypeRef<'s>, ErrorKind> {
 | 
					    ) -> Result<TypeRef<'s>, ErrorKind> {
 | 
				
			||||||
        match &mut self.0 {
 | 
					        match &mut self.0 {
 | 
				
			||||||
            ExprKind::Variable(var) => {
 | 
					            ExprKind::Variable(var) => {
 | 
				
			||||||
                let hint = type_refs
 | 
					                // Find variable type
 | 
				
			||||||
 | 
					                let type_ref = type_refs
 | 
				
			||||||
                    .find_hint(&var.1)
 | 
					                    .find_hint(&var.1)
 | 
				
			||||||
                    .map(|(_, hint)| hint)
 | 
					                    .map(|(_, hint)| hint)
 | 
				
			||||||
                    .ok_or(ErrorKind::VariableNotDefined(var.1.clone()));
 | 
					                    .ok_or(ErrorKind::VariableNotDefined(var.1.clone()));
 | 
				
			||||||
                if let Ok(hint) = &hint {
 | 
					
 | 
				
			||||||
 | 
					                // Update MIR type to TypeRef if found
 | 
				
			||||||
 | 
					                if let Ok(hint) = &type_ref {
 | 
				
			||||||
                    var.0 = hint.as_type()
 | 
					                    var.0 = hint.as_type()
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                hint
 | 
					
 | 
				
			||||||
 | 
					                type_ref
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            ExprKind::Literal(literal) => Ok(type_refs.from_type(&literal.as_type()).unwrap()),
 | 
					            ExprKind::Literal(literal) => Ok(type_refs.from_type(&literal.as_type()).unwrap()),
 | 
				
			||||||
            ExprKind::BinOp(op, lhs, rhs) => {
 | 
					            ExprKind::BinOp(op, lhs, rhs) => {
 | 
				
			||||||
                let mut lhs_ref = lhs.infer_hints(state, type_refs)?;
 | 
					                // Infer LHS and RHS, and return binop type
 | 
				
			||||||
                let mut rhs_ref = rhs.infer_hints(state, type_refs)?;
 | 
					                let mut lhs_ref = lhs.infer_types(state, type_refs)?;
 | 
				
			||||||
                type_refs.binop(op, &mut lhs_ref, &mut rhs_ref)
 | 
					                let mut rhs_ref = rhs.infer_types(state, type_refs)?;
 | 
				
			||||||
 | 
					                type_refs
 | 
				
			||||||
 | 
					                    .binop(op, &mut lhs_ref, &mut rhs_ref)
 | 
				
			||||||
 | 
					                    .ok_or(ErrorKind::TypesIncompatible(
 | 
				
			||||||
 | 
					                        lhs_ref.as_type(),
 | 
				
			||||||
 | 
					                        rhs_ref.as_type(),
 | 
				
			||||||
 | 
					                    ))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            ExprKind::FunctionCall(function_call) => {
 | 
					            ExprKind::FunctionCall(function_call) => {
 | 
				
			||||||
 | 
					                // Get function definition and types
 | 
				
			||||||
                let fn_call = state
 | 
					                let fn_call = state
 | 
				
			||||||
                    .scope
 | 
					                    .scope
 | 
				
			||||||
                    .function_returns
 | 
					                    .function_returns
 | 
				
			||||||
@ -167,48 +200,52 @@ impl Expression {
 | 
				
			|||||||
                    .ok_or(ErrorKind::FunctionNotDefined(function_call.name.clone()))?
 | 
					                    .ok_or(ErrorKind::FunctionNotDefined(function_call.name.clone()))?
 | 
				
			||||||
                    .clone();
 | 
					                    .clone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // Infer param expression types and narrow them to the
 | 
				
			||||||
 | 
					                // expected function parameters (or Unknown types if too
 | 
				
			||||||
 | 
					                // many were provided)
 | 
				
			||||||
                let true_params_iter = fn_call.params.iter().chain(iter::repeat(&Vague(Unknown)));
 | 
					                let true_params_iter = fn_call.params.iter().chain(iter::repeat(&Vague(Unknown)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                for (param_expr, param_t) in
 | 
					                for (param_expr, param_t) in
 | 
				
			||||||
                    function_call.parameters.iter_mut().zip(true_params_iter)
 | 
					                    function_call.parameters.iter_mut().zip(true_params_iter)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    let expr_res = param_expr.infer_hints(state, type_refs);
 | 
					                    let expr_res = param_expr.infer_types(state, type_refs);
 | 
				
			||||||
                    if let Some(mut param_ref) = state.ok(expr_res, param_expr.1) {
 | 
					                    if let Some(mut param_ref) = state.ok(expr_res, param_expr.1) {
 | 
				
			||||||
                        state.ok(
 | 
					                        param_ref.narrow(&mut type_refs.from_type(param_t).unwrap());
 | 
				
			||||||
                            param_ref.narrow(&mut type_refs.from_type(param_t).unwrap()),
 | 
					 | 
				
			||||||
                            param_expr.1,
 | 
					 | 
				
			||||||
                        );
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // Provide function return type
 | 
				
			||||||
                Ok(type_refs.from_type(&fn_call.ret).unwrap())
 | 
					                Ok(type_refs.from_type(&fn_call.ret).unwrap())
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            ExprKind::If(IfExpression(cond, lhs, rhs)) => {
 | 
					            ExprKind::If(IfExpression(cond, lhs, rhs)) => {
 | 
				
			||||||
                let cond_res = cond.infer_hints(state, type_refs);
 | 
					                // Infer condition type
 | 
				
			||||||
 | 
					                let cond_res = cond.infer_types(state, type_refs);
 | 
				
			||||||
                let cond_hints = state.ok(cond_res, cond.1);
 | 
					                let cond_hints = state.ok(cond_res, cond.1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // Try to narrow condition type to boolean
 | 
				
			||||||
                if let Some(mut cond_hints) = cond_hints {
 | 
					                if let Some(mut cond_hints) = cond_hints {
 | 
				
			||||||
                    state.ok(
 | 
					                    cond_hints.narrow(&mut type_refs.from_type(&Bool).unwrap());
 | 
				
			||||||
                        cond_hints.narrow(&mut type_refs.from_type(&Bool).unwrap()),
 | 
					 | 
				
			||||||
                        cond.1,
 | 
					 | 
				
			||||||
                    );
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                let lhs_res = lhs.infer_hints(state, type_refs);
 | 
					                // Infer LHS return type
 | 
				
			||||||
 | 
					                let lhs_res = lhs.infer_types(state, type_refs);
 | 
				
			||||||
                let lhs_hints = state.ok(lhs_res, cond.1);
 | 
					                let lhs_hints = state.ok(lhs_res, cond.1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if let Some(rhs) = rhs {
 | 
					                if let Some(rhs) = rhs {
 | 
				
			||||||
                    let rhs_res = rhs.infer_hints(state, type_refs);
 | 
					                    // Infer RHS return type
 | 
				
			||||||
 | 
					                    let rhs_res = rhs.infer_types(state, type_refs);
 | 
				
			||||||
                    let rhs_hints = state.ok(rhs_res, cond.1);
 | 
					                    let rhs_hints = state.ok(rhs_res, cond.1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    // Narrow LHS to the same type as RHS and return it's return type
 | 
				
			||||||
                    if let (Some(mut lhs_hints), Some(mut rhs_hints)) = (lhs_hints, rhs_hints) {
 | 
					                    if let (Some(mut lhs_hints), Some(mut rhs_hints)) = (lhs_hints, rhs_hints) {
 | 
				
			||||||
                        state.ok(lhs_hints.1.narrow(&mut rhs_hints.1), self.1);
 | 
					                        lhs_hints.1.narrow(&mut rhs_hints.1);
 | 
				
			||||||
                        Ok(pick_return(lhs_hints, rhs_hints).1)
 | 
					                        Ok(pick_return(lhs_hints, rhs_hints).1)
 | 
				
			||||||
                    } else {
 | 
					                    } else {
 | 
				
			||||||
                        // Failed to retrieve types from either
 | 
					                        // Failed to retrieve types from either
 | 
				
			||||||
                        Ok(type_refs.from_type(&Vague(Unknown)).unwrap())
 | 
					                        Ok(type_refs.from_type(&Vague(Unknown)).unwrap())
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
 | 
					                    // Return LHS return type
 | 
				
			||||||
                    if let Some((_, type_ref)) = lhs_hints {
 | 
					                    if let Some((_, type_ref)) = lhs_hints {
 | 
				
			||||||
                        Ok(type_ref)
 | 
					                        Ok(type_ref)
 | 
				
			||||||
                    } else {
 | 
					                    } else {
 | 
				
			||||||
@ -217,7 +254,7 @@ impl Expression {
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            ExprKind::Block(block) => {
 | 
					            ExprKind::Block(block) => {
 | 
				
			||||||
                let block_ref = block.infer_hints(state, type_refs)?;
 | 
					                let block_ref = block.infer_types(state, type_refs)?;
 | 
				
			||||||
                match block_ref.0 {
 | 
					                match block_ref.0 {
 | 
				
			||||||
                    ReturnKind::Hard => Ok(type_refs.from_type(&Void).unwrap()),
 | 
					                    ReturnKind::Hard => Ok(type_refs.from_type(&Void).unwrap()),
 | 
				
			||||||
                    ReturnKind::Soft => Ok(block_ref.1),
 | 
					                    ReturnKind::Soft => Ok(block_ref.1),
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,7 @@ impl<'scope> TypeRef<'scope> {
 | 
				
			|||||||
        unsafe { *self.1.types.hints.borrow().get_unchecked(*self.0.borrow()) }
 | 
					        unsafe { *self.1.types.hints.borrow().get_unchecked(*self.0.borrow()) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn narrow(&mut self, other: &TypeRef) -> Result<TypeRef<'scope>, ErrorKind> {
 | 
					    pub fn narrow(&mut self, other: &TypeRef) -> Option<TypeRef<'scope>> {
 | 
				
			||||||
        self.1.combine_vars(self, other)
 | 
					        self.1.combine_vars(self, other)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -119,11 +119,11 @@ impl<'outer> ScopeTypeRefs<'outer> {
 | 
				
			|||||||
        if self.variables.borrow().contains_key(&name) {
 | 
					        if self.variables.borrow().contains_key(&name) {
 | 
				
			||||||
            return Err(ErrorKind::VariableAlreadyDefined(name));
 | 
					            return Err(ErrorKind::VariableAlreadyDefined(name));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        let idx = self.types.new(initial_ty);
 | 
					        let type_ref = self.from_type(&initial_ty).unwrap();
 | 
				
			||||||
        self.variables
 | 
					        self.variables
 | 
				
			||||||
            .borrow_mut()
 | 
					            .borrow_mut()
 | 
				
			||||||
            .insert(name, (mutable, idx.clone()));
 | 
					            .insert(name, (mutable, type_ref.0.clone()));
 | 
				
			||||||
        Ok(TypeRef(idx, self))
 | 
					        Ok(type_ref)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn from_type(&'outer self, ty: &TypeKind) -> Option<TypeRef<'outer>> {
 | 
					    pub fn from_type(&'outer self, ty: &TypeKind) -> Option<TypeRef<'outer>> {
 | 
				
			||||||
@ -144,24 +144,16 @@ impl<'outer> ScopeTypeRefs<'outer> {
 | 
				
			|||||||
        Some(TypeRef(idx, self))
 | 
					        Some(TypeRef(idx, self))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn narrow_to_type(
 | 
					    fn narrow_to_type(&'outer self, hint: &TypeRef, ty: &TypeKind) -> Option<TypeRef<'outer>> {
 | 
				
			||||||
        &'outer self,
 | 
					 | 
				
			||||||
        hint: &TypeRef,
 | 
					 | 
				
			||||||
        ty: &TypeKind,
 | 
					 | 
				
			||||||
    ) -> Result<TypeRef<'outer>, ErrorKind> {
 | 
					 | 
				
			||||||
        unsafe {
 | 
					        unsafe {
 | 
				
			||||||
            let mut hints = self.types.hints.borrow_mut();
 | 
					            let mut hints = self.types.hints.borrow_mut();
 | 
				
			||||||
            let existing = hints.get_unchecked_mut(*hint.0.borrow());
 | 
					            let existing = hints.get_unchecked_mut(*hint.0.borrow());
 | 
				
			||||||
            *existing = existing.collapse_into(&ty)?;
 | 
					            *existing = existing.collapse_into(&ty).ok()?;
 | 
				
			||||||
            Ok(TypeRef(hint.0.clone(), self))
 | 
					            Some(TypeRef(hint.0.clone(), self))
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn combine_vars(
 | 
					    fn combine_vars(&'outer self, hint1: &TypeRef, hint2: &TypeRef) -> Option<TypeRef<'outer>> {
 | 
				
			||||||
        &'outer self,
 | 
					 | 
				
			||||||
        hint1: &TypeRef,
 | 
					 | 
				
			||||||
        hint2: &TypeRef,
 | 
					 | 
				
			||||||
    ) -> Result<TypeRef<'outer>, ErrorKind> {
 | 
					 | 
				
			||||||
        unsafe {
 | 
					        unsafe {
 | 
				
			||||||
            let ty = self
 | 
					            let ty = self
 | 
				
			||||||
                .types
 | 
					                .types
 | 
				
			||||||
@ -175,7 +167,7 @@ impl<'outer> ScopeTypeRefs<'outer> {
 | 
				
			|||||||
                    *idx.borrow_mut() = *hint1.0.borrow();
 | 
					                    *idx.borrow_mut() = *hint1.0.borrow();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Ok(TypeRef(hint1.0.clone(), self))
 | 
					            Some(TypeRef(hint1.0.clone(), self))
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -200,9 +192,9 @@ impl<'outer> ScopeTypeRefs<'outer> {
 | 
				
			|||||||
        op: &BinaryOperator,
 | 
					        op: &BinaryOperator,
 | 
				
			||||||
        lhs: &mut TypeRef<'outer>,
 | 
					        lhs: &mut TypeRef<'outer>,
 | 
				
			||||||
        rhs: &mut TypeRef<'outer>,
 | 
					        rhs: &mut TypeRef<'outer>,
 | 
				
			||||||
    ) -> Result<TypeRef<'outer>, ErrorKind> {
 | 
					    ) -> Option<TypeRef<'outer>> {
 | 
				
			||||||
        let ty = lhs.narrow(rhs)?;
 | 
					        let ty = lhs.narrow(rhs)?;
 | 
				
			||||||
        Ok(match op {
 | 
					        Some(match op {
 | 
				
			||||||
            BinaryOperator::Add => ty,
 | 
					            BinaryOperator::Add => ty,
 | 
				
			||||||
            BinaryOperator::Minus => ty,
 | 
					            BinaryOperator::Minus => ty,
 | 
				
			||||||
            BinaryOperator::Mult => ty,
 | 
					            BinaryOperator::Mult => ty,
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user