<commit_before>use ast::*;
use compileerror::{CompileResult, CompileError, ErrorCode, err, unknown_name};
use parser::{Operator};
use typechecker::{TypeCheckerContext, instantiate_generics, fill_in_generics, resolve_types, check_match_is_exhaustive};
use span::Span;

#[derive(Debug)]
enum TypeCheckAction
{
    Valid(Type),
    ReplaceBy(Expression)
}

impl TypeCheckAction
{
    pub fn unwrap(self) -> Type
    {
        match self
        {
            TypeCheckAction::Valid(t) => t,
            _ => panic!("Expecting a real type here, and not a replace by expression !"),
        }
    }
}

type TypeCheckResult = CompileResult<TypeCheckAction>;


fn valid(typ: Type) -> TypeCheckResult {
    Ok(TypeCheckAction::Valid(typ))
}

fn replace_by(e: Expression) -> TypeCheckResult
{
    Ok(TypeCheckAction::ReplaceBy(e))
}

fn invalid_unary_operator<T>(span: &Span, op: Operator) -> CompileResult<T>
{
    err(span, ErrorCode::InvalidUnaryOperator, format!("{} is not a valid unary operator", op))
}

fn convert_type(ctx: &mut TypeCheckerContext, dst_type: &Type, src_type: &Type, expr: &mut Expression) -> CompileResult<()>
{
    if *dst_type == *src_type {
        return Ok(());
    }

    if let Some(nex_expression) = dst_type.convert(src_type, expr) {
        *expr = nex_expression;
        assert!(type_check_expression(ctx, expr, &None)? == *dst_type);
        Ok(())
    } else {
        err(&expr.span(), ErrorCode::TypeError, format!("Expecting an expression of type {} or something convertible to, but found one of type {}", src_type, dst_type))
    }
}


fn type_check_unary_op(ctx: &mut TypeCheckerContext, u: &mut UnaryOp) -> TypeCheckResult
{
    let e_type = type_check_expression(ctx, &mut u.expression, &None)?;
    if e_type.is_generic() {
        u.typ = e_type.clone();
        return valid(e_type)
    }

    match u.operator
    {
        Operator::Sub => {
            if !e_type.is_numeric() {
                err(&u.span, ErrorCode::TypeError, format!("Unary operator {} expects a numeric expression", u.operator))
            } else {
                u.typ = e_type.clone();
                valid(e_type)
            }
        },

        Operator::Not => {
            if !e_type.is_bool() {<commit_msg>use assert_eq instead of assert<commit_after>use ast::*;
use compileerror::{CompileResult, CompileError, ErrorCode, err, unknown_name};
use parser::{Operator};
use typechecker::{TypeCheckerContext, instantiate_generics, fill_in_generics, resolve_types, check_match_is_exhaustive};
use span::Span;

#[derive(Debug)]
enum TypeCheckAction
{
    Valid(Type),
    ReplaceBy(Expression)
}

impl TypeCheckAction
{
    pub fn unwrap(self) -> Type
    {
        match self
        {
            TypeCheckAction::Valid(t) => t,
            _ => panic!("Expecting a real type here, and not a replace by expression !"),
        }
    }
}

type TypeCheckResult = CompileResult<TypeCheckAction>;


fn valid(typ: Type) -> TypeCheckResult {
    Ok(TypeCheckAction::Valid(typ))
}

fn replace_by(e: Expression) -> TypeCheckResult
{
    Ok(TypeCheckAction::ReplaceBy(e))
}

fn invalid_unary_operator<T>(span: &Span, op: Operator) -> CompileResult<T>
{
    err(span, ErrorCode::InvalidUnaryOperator, format!("{} is not a valid unary operator", op))
}

fn convert_type(ctx: &mut TypeCheckerContext, dst_type: &Type, src_type: &Type, expr: &mut Expression) -> CompileResult<()>
{
    if *dst_type == *src_type {
        return Ok(());
    }

    if let Some(nex_expression) = dst_type.convert(src_type, expr) {
        *expr = nex_expression;
        assert_eq!(type_check_expression(ctx, expr, &None)?, *dst_type);
        Ok(())
    } else {
        err(&expr.span(), ErrorCode::TypeError, format!("Expecting an expression of type {} or something convertible to, but found one of type {}", src_type, dst_type))
    }
}


fn type_check_unary_op(ctx: &mut TypeCheckerContext, u: &mut UnaryOp) -> TypeCheckResult
{
    let e_type = type_check_expression(ctx, &mut u.expression, &None)?;
    if e_type.is_generic() {
        u.typ = e_type.clone();
        return valid(e_type)
    }

    match u.operator
    {
        Operator::Sub => {
            if !e_type.is_numeric() {
                err(&u.span, ErrorCode::TypeError, format!("Unary operator {} expects a numeric expression", u.operator))
            } else {
                u.typ = e_type.clone();
                valid(e_type)
            }
        },

        Operator::Not => {
            if !e_type.is_bool() {
{'fraction_non_alphanumeric': 0.13349676844216626, 'fraction_numerical': 0.0, 'mean_word_length': 3.0948905109489053, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '793836', 'n_tokens_mistral': 1439, 'n_tokens_neox': 1434, 'n_words': 328}