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);
|
lower_to_ir_statement(statement, &session.ctx, &mut fn_ctx, true);
|
||||||
fn_ctx.finish_block();
|
fn_ctx.finish_block();
|
||||||
|
|
||||||
// infer return type from statement
|
// check return type from statement
|
||||||
let maybe_return_ir_type_info = match statement {
|
let maybe_return_ir_type_info = match statement {
|
||||||
Statement::Let(_) | Statement::Assign(_) => None,
|
Statement::Let(_) | Statement::Assign(_) => None,
|
||||||
Statement::Expression(expression_statement) => {
|
Statement::Expression(expression_statement) => {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
pub mod helpers;
|
pub mod helpers;
|
||||||
|
|
||||||
|
use crate::ast::assign_statement::AssignStatement;
|
||||||
use crate::ast::binary_expression::{BinaryExpression, BinaryOperation};
|
use crate::ast::binary_expression::{BinaryExpression, BinaryOperation};
|
||||||
use crate::ast::call::Call;
|
use crate::ast::call::Call;
|
||||||
use crate::ast::class::Class;
|
use crate::ast::class::Class;
|
||||||
@ -13,26 +14,29 @@ use crate::diagnostic::{Diagnostic, Diagnostics};
|
|||||||
use crate::error_codes::BINARY_INCOMPATIBLE_TYPES;
|
use crate::error_codes::BINARY_INCOMPATIBLE_TYPES;
|
||||||
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
||||||
use crate::semantic_analysis::analysis_context::helpers::get_name_for_type;
|
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,
|
are_binary_op_compatible, binary_op_result, is_negative_op_compatible, negative_op_result,
|
||||||
};
|
};
|
||||||
use crate::semantic_analysis::type_info::{TypeInfo, TypeInfoId};
|
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();
|
let mut diagnostics = Diagnostics::new();
|
||||||
|
for function in compilation_unit.functions() {
|
||||||
|
check_types_function(function, ctx, &mut diagnostics);
|
||||||
|
}
|
||||||
for class in compilation_unit.classes() {
|
for class in compilation_unit.classes() {
|
||||||
infer_types_class(class, ctx, &mut diagnostics);
|
check_types_class(class, ctx, &mut diagnostics);
|
||||||
}
|
}
|
||||||
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() {
|
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,
|
function: &Function,
|
||||||
ctx: &mut AnalysisContext,
|
ctx: &mut AnalysisContext,
|
||||||
diagnostics: &mut Diagnostics,
|
diagnostics: &mut Diagnostics,
|
||||||
@ -40,31 +44,117 @@ fn infer_types_function(
|
|||||||
for statement in function.statements() {
|
for statement in function.statements() {
|
||||||
match statement {
|
match statement {
|
||||||
Statement::Let(let_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,
|
let_statement: &LetStatement,
|
||||||
ctx: &mut AnalysisContext,
|
ctx: &mut AnalysisContext,
|
||||||
diagnostics: &mut Diagnostics,
|
diagnostics: &mut Diagnostics,
|
||||||
) {
|
) {
|
||||||
let initializer_type = infer_types_expression(let_statement.initializer(), ctx, diagnostics);
|
let initializer_type = resolve_types_expression(let_statement.initializer(), ctx, diagnostics);
|
||||||
// todo set symbol's type to the initializer type
|
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,
|
expression: &Expression,
|
||||||
ctx: &mut AnalysisContext,
|
ctx: &mut AnalysisContext,
|
||||||
diagnostics: &mut Diagnostics,
|
diagnostics: &mut Diagnostics,
|
||||||
) -> TypeInfoId {
|
) -> TypeInfoId {
|
||||||
match expression {
|
match expression {
|
||||||
Expression::Binary(binary_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) => {
|
Expression::Negative(negative_expression) => {
|
||||||
resolve_types_negative_expression(negative_expression, ctx, diagnostics)
|
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,
|
binary_expression: &BinaryExpression,
|
||||||
ctx: &mut AnalysisContext,
|
ctx: &mut AnalysisContext,
|
||||||
diagnostics: &mut Diagnostics,
|
diagnostics: &mut Diagnostics,
|
||||||
) -> TypeInfoId {
|
) -> TypeInfoId {
|
||||||
let lhs_type_info_id = infer_types_expression(binary_expression.lhs(), ctx, diagnostics);
|
let lhs_type_info_id = resolve_types_expression(binary_expression.lhs(), ctx, diagnostics);
|
||||||
let rhs_type_info_id = infer_types_expression(binary_expression.rhs(), 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 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);
|
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,
|
diagnostics: &mut Diagnostics,
|
||||||
) -> TypeInfoId {
|
) -> TypeInfoId {
|
||||||
let operand_type_info_id =
|
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 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) {
|
let result_type_info_id = if is_negative_op_compatible(operand_type_info, ctx) {
|
||||||
negative_op_result(operand_type_info, ctx)
|
negative_op_result(operand_type_info, ctx)
|
||||||
@ -175,7 +265,7 @@ fn resolve_types_call(
|
|||||||
ctx: &mut AnalysisContext,
|
ctx: &mut AnalysisContext,
|
||||||
diagnostics: &mut Diagnostics,
|
diagnostics: &mut Diagnostics,
|
||||||
) -> TypeInfoId {
|
) -> 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);
|
let receiver_type_info = ctx.get_type_info_by_id(receiver_type_info_id);
|
||||||
match receiver_type_info {
|
match receiver_type_info {
|
||||||
TypeInfo::Any | TypeInfo::Void => {
|
TypeInfo::Any | TypeInfo::Void => {
|
||||||
@ -199,7 +289,7 @@ fn resolve_types_call(
|
|||||||
ctx.instance_type(symbol)
|
ctx.instance_type(symbol)
|
||||||
}
|
}
|
||||||
TypeInfo::Constructor(_) => {
|
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::Function(function_type_info) => function_type_info.return_type_id(),
|
||||||
TypeInfo::Instance(_) => {
|
TypeInfo::Instance(_) => {
|
||||||
@ -1,12 +1,12 @@
|
|||||||
use crate::ast::compilation_unit::CompilationUnit;
|
use crate::ast::compilation_unit::CompilationUnit;
|
||||||
use crate::diagnostic::Diagnostics;
|
use crate::diagnostic::Diagnostics;
|
||||||
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
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::collect::collect_types;
|
||||||
use crate::semantic_analysis::type_analysis::infer::infer_types;
|
|
||||||
use crate::semantic_analysis::type_analysis::resolve::resolve_types;
|
use crate::semantic_analysis::type_analysis::resolve::resolve_types;
|
||||||
|
|
||||||
|
mod check;
|
||||||
mod collect;
|
mod collect;
|
||||||
mod infer;
|
|
||||||
mod resolve;
|
mod resolve;
|
||||||
|
|
||||||
pub fn analyze_types(
|
pub fn analyze_types(
|
||||||
@ -15,5 +15,5 @@ pub fn analyze_types(
|
|||||||
) -> Diagnostics {
|
) -> Diagnostics {
|
||||||
collect_types(compilation_unit, analysis_context);
|
collect_types(compilation_unit, analysis_context);
|
||||||
resolve_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