wat_service 0.7.0

WebAssembly Text Format language service.
Documentation
use crate::{LanguageService, binder::SymbolTable, document::Document, helpers, types_analyzer};
use line_index::LineIndex;
use lspt::{Diagnostic, DiagnosticSeverity, Union2};
use rowan::ast::AstNode;
use wat_syntax::{SyntaxNode, ast::TypeDef};

const DIAGNOSTIC_CODE: &str = "subtyping";

pub fn check(
    diagnostics: &mut Vec<Diagnostic>,
    service: &LanguageService,
    document: Document,
    line_index: &LineIndex,
    root: &SyntaxNode,
    symbol_table: &SymbolTable,
) {
    let def_types = types_analyzer::get_def_types(service, document);
    diagnostics.extend(
        def_types
            .iter()
            .filter_map(|(key, sub_type)| {
                let inherits = sub_type.inherits.as_ref()?;
                let super_type = def_types.get(&inherits.symbol)?;
                let module_key = symbol_table.symbols.get(key)?.region;
                let module_id = symbol_table.symbols.get(&module_key)?.idx.num?;

                if super_type
                    .idx
                    .num
                    .zip(sub_type.idx.num)
                    .is_some_and(|(sup, sub)| sup >= sub)
                {
                    Some((
                        key,
                        format!(
                            "typeidx of super type `{}` must be smaller than type `{}`",
                            super_type.idx.render(service),
                            sub_type.idx.render(service),
                        ),
                    ))
                } else if super_type.is_final {
                    Some((
                        key,
                        format!("type `{}` is final", super_type.idx.render(service)),
                    ))
                } else if !sub_type
                    .comp
                    .matches(&super_type.comp, service, document, module_id)
                {
                    Some((
                        key,
                        format!(
                            "type of `{}` doesn't match its super type `{}`",
                            sub_type.idx.render(service),
                            super_type.idx.render(service),
                        ),
                    ))
                } else {
                    None
                }
            })
            .filter_map(|(key, message)| {
                let index = TypeDef::cast(key.to_node(root))?
                    .sub_type()?
                    .indexes()
                    .next()?;
                Some(Diagnostic {
                    range: helpers::rowan_range_to_lsp_range(
                        line_index,
                        index.syntax().text_range(),
                    ),
                    severity: Some(DiagnosticSeverity::Error),
                    source: Some("wat".into()),
                    code: Some(Union2::B(DIAGNOSTIC_CODE.into())),
                    message,
                    ..Default::default()
                })
            }),
    );
}