WIP type analysis.
This commit is contained in:
parent
dae482ef78
commit
3535fed61d
@ -64,7 +64,7 @@ pub fn lower_to_ir_synthetic_function(
|
||||
lower_to_ir_statement(statement, &session.ctx, &mut fn_ctx, true);
|
||||
fn_ctx.finish_block();
|
||||
|
||||
// infer return type from statement
|
||||
// check return type from statement
|
||||
let maybe_return_ir_type_info = match statement {
|
||||
Statement::Let(_) | Statement::Assign(_) => None,
|
||||
Statement::Expression(expression_statement) => {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
pub mod helpers;
|
||||
|
||||
use crate::ast::assign_statement::AssignStatement;
|
||||
use crate::ast::binary_expression::{BinaryExpression, BinaryOperation};
|
||||
use crate::ast::call::Call;
|
||||
use crate::ast::class::Class;
|
||||
@ -13,26 +14,29 @@ use crate::diagnostic::{Diagnostic, Diagnostics};
|
||||
use crate::error_codes::BINARY_INCOMPATIBLE_TYPES;
|
||||
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
||||
use crate::semantic_analysis::analysis_context::helpers::get_name_for_type;
|
||||
use crate::semantic_analysis::type_analysis::infer::helpers::{
|
||||
use crate::semantic_analysis::type_analysis::check::helpers::{
|
||||
are_binary_op_compatible, binary_op_result, is_negative_op_compatible, negative_op_result,
|
||||
};
|
||||
use crate::semantic_analysis::type_info::{TypeInfo, TypeInfoId};
|
||||
|
||||
pub fn infer_types(compilation_unit: &CompilationUnit, ctx: &mut AnalysisContext) -> Diagnostics {
|
||||
pub fn check_types(compilation_unit: &CompilationUnit, ctx: &mut AnalysisContext) -> Diagnostics {
|
||||
let mut diagnostics = Diagnostics::new();
|
||||
for function in compilation_unit.functions() {
|
||||
check_types_function(function, ctx, &mut diagnostics);
|
||||
}
|
||||
for class in compilation_unit.classes() {
|
||||
infer_types_class(class, ctx, &mut diagnostics);
|
||||
check_types_class(class, ctx, &mut diagnostics);
|
||||
}
|
||||
diagnostics
|
||||
}
|
||||
|
||||
fn infer_types_class(class: &Class, ctx: &mut AnalysisContext, diagnostics: &mut Diagnostics) {
|
||||
fn check_types_class(class: &Class, ctx: &mut AnalysisContext, diagnostics: &mut Diagnostics) {
|
||||
for function in class.functions() {
|
||||
infer_types_function(function, ctx, diagnostics);
|
||||
check_types_function(function, ctx, diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
fn infer_types_function(
|
||||
fn check_types_function(
|
||||
function: &Function,
|
||||
ctx: &mut AnalysisContext,
|
||||
diagnostics: &mut Diagnostics,
|
||||
@ -40,31 +44,117 @@ fn infer_types_function(
|
||||
for statement in function.statements() {
|
||||
match statement {
|
||||
Statement::Let(let_statement) => {
|
||||
infer_types_let_statement(let_statement, ctx, diagnostics);
|
||||
check_types_let_statement(let_statement, ctx, diagnostics);
|
||||
}
|
||||
Statement::Expression(expression_statement) => {
|
||||
resolve_types_expression(expression_statement.expression(), ctx, diagnostics);
|
||||
}
|
||||
Statement::Assign(assign_statement) => {
|
||||
check_types_assign_statement(assign_statement, ctx, diagnostics);
|
||||
}
|
||||
Statement::Expression(expression_statement) => {}
|
||||
Statement::Assign(assign_statement) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn infer_types_let_statement(
|
||||
fn check_types_let_statement(
|
||||
let_statement: &LetStatement,
|
||||
ctx: &mut AnalysisContext,
|
||||
diagnostics: &mut Diagnostics,
|
||||
) {
|
||||
let initializer_type = infer_types_expression(let_statement.initializer(), ctx, diagnostics);
|
||||
// todo set symbol's type to the initializer type
|
||||
let initializer_type = resolve_types_expression(let_statement.initializer(), ctx, diagnostics);
|
||||
let symbol_id = ctx
|
||||
.get_symbol_id(let_statement.node_id())
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"LetStatement {} has no associated symbol",
|
||||
let_statement.node_id()
|
||||
)
|
||||
});
|
||||
ctx.associate_symbol_to_type(symbol_id, initializer_type);
|
||||
}
|
||||
|
||||
fn infer_types_expression(
|
||||
fn check_types_assign_statement(
|
||||
assign_statement: &AssignStatement,
|
||||
ctx: &mut AnalysisContext,
|
||||
diagnostics: &mut Diagnostics,
|
||||
) {
|
||||
let destination_type_info_id =
|
||||
resolve_types_expression(assign_statement.destination(), ctx, diagnostics);
|
||||
let value_type_info_id = resolve_types_expression(assign_statement.value(), ctx, diagnostics);
|
||||
|
||||
let destination_type_info = ctx.get_type_info_by_id(destination_type_info_id);
|
||||
let value_type_info = ctx.get_type_info_by_id(value_type_info_id);
|
||||
|
||||
match destination_type_info {
|
||||
TypeInfo::Any
|
||||
| TypeInfo::Class(_)
|
||||
| TypeInfo::Constructor(_)
|
||||
| TypeInfo::Function(_)
|
||||
| TypeInfo::Void => {
|
||||
let diagnostic = Diagnostic::new(
|
||||
&format!(
|
||||
"Unassignable destination type: cannot assign {} to {}",
|
||||
get_name_for_type(value_type_info, ctx),
|
||||
get_name_for_type(destination_type_info, ctx)
|
||||
),
|
||||
assign_statement.destination().source_range().start(),
|
||||
assign_statement.value().source_range().end(),
|
||||
);
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
TypeInfo::Instance(destination_instance_type_info) => {
|
||||
match value_type_info {
|
||||
TypeInfo::Any
|
||||
| TypeInfo::Class(_)
|
||||
| TypeInfo::Constructor(_)
|
||||
| TypeInfo::Function(_)
|
||||
| TypeInfo::Void => {
|
||||
let diagnostic = Diagnostic::new(
|
||||
&format!(
|
||||
"Unassignable source type: cannot assign {} to {}",
|
||||
get_name_for_type(value_type_info, ctx),
|
||||
get_name_for_type(destination_type_info, ctx),
|
||||
),
|
||||
assign_statement.destination().source_range().start(),
|
||||
assign_statement.value().source_range().end(),
|
||||
);
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
TypeInfo::Instance(value_instance_type_info) => {
|
||||
if !destination_instance_type_info
|
||||
.can_assign_from(value_instance_type_info, ctx)
|
||||
{
|
||||
let diagnostic = Diagnostic::new(
|
||||
&format!(
|
||||
"Incompatible types: cannot assign {} to {}",
|
||||
get_name_for_type(value_type_info, ctx),
|
||||
get_name_for_type(destination_type_info, ctx)
|
||||
),
|
||||
assign_statement.destination().source_range().start(),
|
||||
assign_statement.value().source_range().end(),
|
||||
);
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
TypeInfo::__Error => {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
}
|
||||
TypeInfo::__Error => {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_types_expression(
|
||||
expression: &Expression,
|
||||
ctx: &mut AnalysisContext,
|
||||
diagnostics: &mut Diagnostics,
|
||||
) -> TypeInfoId {
|
||||
match expression {
|
||||
Expression::Binary(binary_expression) => {
|
||||
infer_types_binary_expression(binary_expression, ctx, diagnostics)
|
||||
resolve_types_binary_expression(binary_expression, ctx, diagnostics)
|
||||
}
|
||||
Expression::Negative(negative_expression) => {
|
||||
resolve_types_negative_expression(negative_expression, ctx, diagnostics)
|
||||
@ -93,13 +183,13 @@ fn infer_types_expression(
|
||||
}
|
||||
}
|
||||
|
||||
fn infer_types_binary_expression(
|
||||
fn resolve_types_binary_expression(
|
||||
binary_expression: &BinaryExpression,
|
||||
ctx: &mut AnalysisContext,
|
||||
diagnostics: &mut Diagnostics,
|
||||
) -> TypeInfoId {
|
||||
let lhs_type_info_id = infer_types_expression(binary_expression.lhs(), ctx, diagnostics);
|
||||
let rhs_type_info_id = infer_types_expression(binary_expression.rhs(), ctx, diagnostics);
|
||||
let lhs_type_info_id = resolve_types_expression(binary_expression.lhs(), ctx, diagnostics);
|
||||
let rhs_type_info_id = resolve_types_expression(binary_expression.rhs(), ctx, diagnostics);
|
||||
|
||||
let lhs_type_info = ctx.get_type_info_by_id(lhs_type_info_id);
|
||||
let rhs_type_info = ctx.get_type_info_by_id(rhs_type_info_id);
|
||||
@ -148,7 +238,7 @@ fn resolve_types_negative_expression(
|
||||
diagnostics: &mut Diagnostics,
|
||||
) -> TypeInfoId {
|
||||
let operand_type_info_id =
|
||||
infer_types_expression(negative_expression.operand(), ctx, diagnostics);
|
||||
resolve_types_expression(negative_expression.operand(), ctx, diagnostics);
|
||||
let operand_type_info = ctx.get_type_info_by_id(operand_type_info_id);
|
||||
let result_type_info_id = if is_negative_op_compatible(operand_type_info, ctx) {
|
||||
negative_op_result(operand_type_info, ctx)
|
||||
@ -175,7 +265,7 @@ fn resolve_types_call(
|
||||
ctx: &mut AnalysisContext,
|
||||
diagnostics: &mut Diagnostics,
|
||||
) -> TypeInfoId {
|
||||
let receiver_type_info_id = infer_types_expression(call.callee(), ctx, diagnostics);
|
||||
let receiver_type_info_id = resolve_types_expression(call.callee(), ctx, diagnostics);
|
||||
let receiver_type_info = ctx.get_type_info_by_id(receiver_type_info_id);
|
||||
match receiver_type_info {
|
||||
TypeInfo::Any | TypeInfo::Void => {
|
||||
@ -199,7 +289,7 @@ fn resolve_types_call(
|
||||
ctx.instance_type(symbol)
|
||||
}
|
||||
TypeInfo::Constructor(_) => {
|
||||
panic!("Cannot infer expression type directly on ConstructorTypeInfo");
|
||||
panic!("Cannot check expression type directly on ConstructorTypeInfo");
|
||||
}
|
||||
TypeInfo::Function(function_type_info) => function_type_info.return_type_id(),
|
||||
TypeInfo::Instance(_) => {
|
||||
@ -1,12 +1,12 @@
|
||||
use crate::ast::compilation_unit::CompilationUnit;
|
||||
use crate::diagnostic::Diagnostics;
|
||||
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
||||
use crate::semantic_analysis::type_analysis::check::check_types;
|
||||
use crate::semantic_analysis::type_analysis::collect::collect_types;
|
||||
use crate::semantic_analysis::type_analysis::infer::infer_types;
|
||||
use crate::semantic_analysis::type_analysis::resolve::resolve_types;
|
||||
|
||||
mod check;
|
||||
mod collect;
|
||||
mod infer;
|
||||
mod resolve;
|
||||
|
||||
pub fn analyze_types(
|
||||
@ -15,5 +15,5 @@ pub fn analyze_types(
|
||||
) -> Diagnostics {
|
||||
collect_types(compilation_unit, analysis_context);
|
||||
resolve_types(compilation_unit, analysis_context);
|
||||
infer_types(compilation_unit, analysis_context)
|
||||
check_types(compilation_unit, analysis_context)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user