diff --git a/lib/hir-mir/src/built_in_call.rs b/lib/hir-mir/src/built_in_call.rs index 497a5f7cd9..f571479d0a 100644 --- a/lib/hir-mir/src/built_in_call.rs +++ b/lib/hir-mir/src/built_in_call.rs @@ -25,7 +25,12 @@ pub fn compile( .function_type() .ok_or_else(|| AnalysisError::TypeNotInferred(position.clone()))?; let function_type = type_canonicalizer::canonicalize_function(function_type, context.types())? - .ok_or_else(|| AnalysisError::FunctionExpected(function_type.clone()))?; + .ok_or_else(|| { + AnalysisError::FunctionExpected( + call.function().position().clone(), + function_type.clone(), + ) + })?; let arguments = call .arguments() .iter() @@ -49,7 +54,12 @@ pub fn compile( BuiltInFunctionName::Delete => { let map_type = type_canonicalizer::canonicalize_map(function_type.result(), context.types())? - .ok_or_else(|| AnalysisError::MapExpected(function_type.result().clone()))?; + .ok_or_else(|| { + AnalysisError::MapExpected( + call.position().clone(), + function_type.result().clone(), + ) + })?; let mir_map_type = type_::compile_map(context)?; mir::ir::Call::new( @@ -85,17 +95,23 @@ pub fn compile( BuiltInFunctionName::Error => error_type::compile_error(arguments[0].clone()), BuiltInFunctionName::Keys => { let argument_type = &function_type.arguments()[0]; + let argument = &call.arguments()[0]; compile_map_iteration( context, - &call.arguments()[0], + argument, &context .configuration()? .map_type .iteration .key_function_name, type_canonicalizer::canonicalize_map(argument_type, context.types())? - .ok_or_else(|| AnalysisError::MapExpected(argument_type.clone()))? + .ok_or_else(|| { + AnalysisError::MapExpected( + argument.position().clone(), + argument_type.clone(), + ) + })? .key(), position, )? @@ -105,7 +121,12 @@ pub fn compile( let list_type = type_canonicalizer::canonicalize_list(function_type.result(), context.types())? - .ok_or_else(|| AnalysisError::ListExpected(function_type.result().clone()))?; + .ok_or_else(|| { + AnalysisError::ListExpected( + call.position().clone(), + function_type.result().clone(), + ) + })?; let any_list_type = types::List::new(types::Any::new(position.clone()), position.clone()); @@ -168,7 +189,12 @@ pub fn compile( let function_type = &function_type.arguments()[0]; let function_type = type_canonicalizer::canonicalize_function(function_type, context.types())? - .ok_or_else(|| AnalysisError::FunctionExpected(function_type.clone()))?; + .ok_or_else(|| { + AnalysisError::FunctionExpected( + call.arguments()[0].position().clone(), + function_type.clone(), + ) + })?; let result_type = function_type.result(); let any_type = Type::from(types::Any::new(position.clone())); let thunk_type = @@ -236,17 +262,23 @@ pub fn compile( } BuiltInFunctionName::Values => { let argument_type = &function_type.arguments()[0]; + let argument = &call.arguments()[0]; compile_map_iteration( context, - &call.arguments()[0], + argument, &context .configuration()? .map_type .iteration .value_function_name, type_canonicalizer::canonicalize_map(argument_type, context.types())? - .ok_or_else(|| AnalysisError::MapExpected(argument_type.clone()))? + .ok_or_else(|| { + AnalysisError::MapExpected( + argument.position().clone(), + argument_type.clone(), + ) + })? .value(), position, )? diff --git a/lib/hir-mir/src/downcast.rs b/lib/hir-mir/src/downcast.rs index fca3315313..29d7492613 100644 --- a/lib/hir-mir/src/downcast.rs +++ b/lib/hir-mir/src/downcast.rs @@ -19,9 +19,13 @@ pub fn compile( let from = type_canonicalizer::canonicalize(from, context.types())?; if !from.is_variant() { - return Err(AnalysisError::VariantExpected(from).into()); + return Err(AnalysisError::VariantExpected(position.clone(), from).into()); } else if !type_subsumption_checker::check(to, &from, context.types())? { - return Err(AnalysisError::TypesNotMatched(to.clone(), from).into()); + return Err(AnalysisError::TypesNotMatched { + found: (expression.position().clone(), to.clone()), + expected: (from.position().clone(), from), + } + .into()); } Ok( @@ -137,15 +141,18 @@ mod tests { &types::Any::new(Position::fake()).into(), &Variable::new("x", Position::fake()).into(), ), - Err(AnalysisError::TypesNotMatched( - types::Any::new(Position::fake()).into(), - types::Union::new( - types::None::new(Position::fake()), - types::Number::new(Position::fake()), - Position::fake() - ) - .into(), - ) + Err(AnalysisError::TypesNotMatched { + found: (Position::fake(), types::Any::new(Position::fake()).into()), + expected: ( + Position::fake(), + types::Union::new( + types::None::new(Position::fake()), + types::Number::new(Position::fake()), + Position::fake() + ) + .into() + ), + } .into()) ); } @@ -158,7 +165,11 @@ mod tests { &types::None::new(Position::fake()).into(), &None::new(Position::fake()).into(), ), - Err(AnalysisError::VariantExpected(types::None::new(Position::fake()).into()).into()) + Err(AnalysisError::VariantExpected( + Position::fake(), + types::None::new(Position::fake()).into() + ) + .into()) ); } } diff --git a/lib/hir-mir/src/expression.rs b/lib/hir-mir/src/expression.rs index c1d1be67ca..3c08560af0 100644 --- a/lib/hir-mir/src/expression.rs +++ b/lib/hir-mir/src/expression.rs @@ -40,7 +40,12 @@ pub fn compile( mir::ir::Call::new( type_::compile(context, type_)? .into_function() - .ok_or_else(|| AnalysisError::FunctionExpected(type_.clone()))?, + .ok_or_else(|| { + AnalysisError::FunctionExpected( + call.function().position().clone(), + type_.clone(), + ) + })?, compile(call.function())?, call.arguments() .iter() @@ -125,6 +130,7 @@ pub fn compile( Expression::RecordConstruction(construction) => { let field_types = record_field_resolver::resolve( construction.type_(), + construction.type_().position(), context.types(), context.records(), )?; @@ -148,10 +154,15 @@ pub fn compile( mir::ir::RecordField::new( type_::compile(context, type_)?.into_record().unwrap(), - record_field_resolver::resolve(type_, context.types(), context.records())? - .iter() - .position(|field_type| field_type.name() == deconstruction.field_name()) - .unwrap(), + record_field_resolver::resolve( + type_, + deconstruction.record().position(), + context.types(), + context.records(), + )? + .iter() + .position(|field_type| field_type.name() == deconstruction.field_name()) + .unwrap(), compile(deconstruction.record())?, ) .into() @@ -168,6 +179,7 @@ pub fn compile( Ok(mir::ir::RecordUpdateField::new( record_field_resolver::resolve( update.type_(), + update.type_().position(), context.types(), context.records(), )? diff --git a/lib/hir-mir/src/module.rs b/lib/hir-mir/src/module.rs index f251316a95..09fd96b94f 100644 --- a/lib/hir-mir/src/module.rs +++ b/lib/hir-mir/src/module.rs @@ -26,7 +26,10 @@ pub fn compile(context: &Context, module: &Module) -> Result { - return Err(AnalysisError::TypeNotComparable(type_.clone()).into()) + return Err(AnalysisError::TypeNotComparable(position.clone(), type_.clone()).into()) } }) } @@ -364,7 +364,11 @@ mod tests { &Variable::new("y", Position::fake()).into(), &Position::fake() ), - Err(AnalysisError::TypeNotComparable(types::Any::new(Position::fake()).into()).into()) + Err(AnalysisError::TypeNotComparable( + Position::fake(), + types::Any::new(Position::fake()).into() + ) + .into()) ); } @@ -381,7 +385,7 @@ mod tests { &Variable::new("y", Position::fake()).into(), &Position::fake() ), - Err(AnalysisError::TypeNotComparable(function_type.into()).into()) + Err(AnalysisError::TypeNotComparable(Position::fake(), function_type.into()).into()) ); } } diff --git a/lib/hir-mir/src/transformation/hash_calculation/expression.rs b/lib/hir-mir/src/transformation/hash_calculation/expression.rs index b1b1289c06..03f1e9505d 100644 --- a/lib/hir-mir/src/transformation/hash_calculation/expression.rs +++ b/lib/hir-mir/src/transformation/hash_calculation/expression.rs @@ -137,7 +137,7 @@ pub fn transform( position, )?, Type::Any(_) | Type::Error(_) | Type::Function(_) => { - return Err(AnalysisError::TypeNotComparable(type_.clone()).into()) + return Err(AnalysisError::TypeNotComparable(position.clone(), type_.clone()).into()) } }) } @@ -287,7 +287,7 @@ mod tests { &any_type.clone().into(), &Position::fake(), ), - Err(AnalysisError::TypeNotComparable(any_type.into()).into()) + Err(AnalysisError::TypeNotComparable(Position::fake(), any_type.into()).into()) ); } @@ -303,7 +303,7 @@ mod tests { &function_type.clone().into(), &Position::fake(), ), - Err(AnalysisError::TypeNotComparable(function_type.into()).into()) + Err(AnalysisError::TypeNotComparable(Position::fake(), function_type.into()).into()) ); } } diff --git a/lib/hir/src/analysis/error.rs b/lib/hir/src/analysis/error.rs index 43fa8ade66..d1cede0f19 100644 --- a/lib/hir/src/analysis/error.rs +++ b/lib/hir/src/analysis/error.rs @@ -14,21 +14,21 @@ pub enum AnalysisError { AnyTypeBranch(Position), ArgumentCount(Position), BuiltInFunctionNotCalled(Position), - CollectionExpected(Type), + CollectionExpected(Position, Type), DuplicateFunctionNames(Position, Position), DuplicateTypeNames(Position, Position), ElementNameNotDefined(Position), ErrorTypeUndefined, - FunctionExpected(Type), + FunctionExpected(Position, Type), ImpossibleRecord(Position), InvalidAdditionOperand(Position), InvalidTryOperation(Position), KeyNameNotDefined(Position), ListComprehensionIterateeCount(Position), - ListExpected(Type), - MapExpected(Type), + ListExpected(Position, Type), + MapExpected(Position, Type), MissingElseBlock(Position), - RecordExpected(Type), + RecordExpected(Position, Type), RecordFieldNotFound(String, Position), RecordFieldPrivate(Position), RecordFieldUnknown(Position), @@ -38,15 +38,18 @@ pub enum AnalysisError { TryOperationInList(Position), TypeNotFound(Reference), TypeNotInferred(Position), - TypeNotComparable(Type), - TypesNotMatched(Type, Type), - UnionExpected(Type), + TypeNotComparable(Position, Type), + TypesNotMatched { + found: (Position, Type), + expected: (Position, Type), + }, + UnionExpected(Position, Type), UnknownRecordField(Position), UnreachableCode(Position), UnusedErrorValue(Position), ValueNameNotDefined(Position), VariableNotFound(Variable), - VariantExpected(Type), + VariantExpected(Position, Type), } impl AnalysisError { @@ -54,18 +57,12 @@ impl AnalysisError { format!("`{}`", type_formatter::format(type_)) } - fn format_found_type_message(type_: &Type) -> String { - position::format_message( - type_.position(), - &format!("found {}", Self::format_type(type_)), - ) + fn format_found_type_message(position: &Position, type_: &Type) -> String { + position::format_message(position, &format!("found {}", Self::format_type(type_))) } - fn format_expected_type_message(type_: &Type) -> String { - position::format_message( - type_.position(), - &format!("expected {}", Self::format_type(type_)), - ) + fn format_expected_type_message(position: &Position, type_: &Type) -> String { + position::format_message(position, &format!("expected {}", Self::format_type(type_))) } } @@ -93,11 +90,11 @@ impl Display for AnalysisError { position ) } - Self::CollectionExpected(type_) => { + Self::CollectionExpected(position, type_) => { write!( formatter, "list or map expected\n{}", - Self::format_found_type_message(type_) + Self::format_found_type_message(position, type_) ) } Self::DuplicateFunctionNames(one, other) => { @@ -112,11 +109,11 @@ impl Display for AnalysisError { Self::ErrorTypeUndefined => { write!(formatter, "error type undefined") } - Self::FunctionExpected(type_) => { + Self::FunctionExpected(position, type_) => { write!( formatter, "function expected\n{}", - Self::format_found_type_message(type_) + Self::format_found_type_message(position, type_) ) } Self::ImpossibleRecord(position) => { @@ -150,18 +147,18 @@ impl Display for AnalysisError { position ) } - Self::ListExpected(type_) => { + Self::ListExpected(position, type_) => { write!( formatter, "list expected\n{}", - Self::format_found_type_message(type_) + Self::format_found_type_message(position, type_) ) } - Self::MapExpected(type_) => { + Self::MapExpected(position, type_) => { write!( formatter, "map expected\n{}", - Self::format_found_type_message(type_) + Self::format_found_type_message(position, type_) ) } Self::MissingElseBlock(position) => { @@ -171,11 +168,11 @@ impl Display for AnalysisError { position ) } - Self::RecordExpected(type_) => { + Self::RecordExpected(position, type_) => { write!( formatter, "record expected\n{}", - Self::format_found_type_message(type_) + Self::format_found_type_message(position, type_) ) } Self::RecordFieldNotFound(name, position) => { @@ -210,17 +207,17 @@ impl Display for AnalysisError { position ) } - Self::TypeNotComparable(type_) => { + Self::TypeNotComparable(position, type_) => { write!( formatter, "type not comparable\n{}", position::format_message( - type_.position(), + position, &format!( "{} might include function, {}, or {} types", Self::format_type(type_), - Self::format_type(&types::Error::new(type_.position().clone()).into()), - Self::format_type(&types::Any::new(type_.position().clone()).into()), + Self::format_type(&types::Error::new(position.clone()).into()), + Self::format_type(&types::Any::new(position.clone()).into()), ), ) ) @@ -234,17 +231,20 @@ impl Display for AnalysisError { Self::TypeNotInferred(position) => { write!(formatter, "type not inferred\n{}", position) } - Self::TypesNotMatched(lower, upper) => write!( + Self::TypesNotMatched { + found: (found_position, found_type), + expected: (expected_position, expected_type), + } => write!( formatter, "types not matched\n{}\n{}", - Self::format_found_type_message(lower), - Self::format_expected_type_message(upper), + Self::format_found_type_message(found_position, found_type), + Self::format_expected_type_message(expected_position, expected_type), ), - Self::UnionExpected(type_) => { + Self::UnionExpected(position, type_) => { write!( formatter, "union type expected\n{}", - Self::format_found_type_message(type_) + Self::format_found_type_message(position, type_) ) } Self::UnknownRecordField(position) => { @@ -265,11 +265,11 @@ impl Display for AnalysisError { variable.name(), variable.position() ), - Self::VariantExpected(type_) => { + Self::VariantExpected(position, type_) => { write!( formatter, "union or any type expected\n{}", - Self::format_found_type_message(type_) + Self::format_found_type_message(position, type_) ) } } diff --git a/lib/hir/src/analysis/record_field_resolver.rs b/lib/hir/src/analysis/record_field_resolver.rs index e9fc487a16..03a2506e8a 100644 --- a/lib/hir/src/analysis/record_field_resolver.rs +++ b/lib/hir/src/analysis/record_field_resolver.rs @@ -1,15 +1,17 @@ use super::{type_canonicalizer, AnalysisError}; use crate::types::*; use fnv::FnvHashMap; +use position::Position; pub fn resolve<'a>( type_: &Type, + position: &Position, types: &FnvHashMap, records: &'a FnvHashMap>, ) -> Result<&'a [RecordField], AnalysisError> { resolve_record( &type_canonicalizer::canonicalize_record(type_, types)? - .ok_or_else(|| AnalysisError::RecordExpected(type_.clone()))?, + .ok_or_else(|| AnalysisError::RecordExpected(position.clone(), type_.clone()))?, records, ) } diff --git a/lib/hir/src/analysis/record_field_validator.rs b/lib/hir/src/analysis/record_field_validator.rs index 1ee2ab698b..7a281df069 100644 --- a/lib/hir/src/analysis/record_field_validator.rs +++ b/lib/hir/src/analysis/record_field_validator.rs @@ -14,7 +14,10 @@ pub fn validate(context: &AnalysisContext, module: &Module) -> Result<(), Analys let record_type = type_canonicalizer::canonicalize_record(construction.type_(), context.types())? .ok_or_else(|| { - AnalysisError::RecordExpected(construction.type_().clone()) + AnalysisError::RecordExpected( + construction.type_().position().clone(), + construction.type_().clone(), + ) })?; if !open_records.contains(record_type.name()) { @@ -30,7 +33,12 @@ pub fn validate(context: &AnalysisContext, module: &Module) -> Result<(), Analys AnalysisError::TypeNotInferred(deconstruction.position().clone()) })?; let record_type = type_canonicalizer::canonicalize_record(type_, context.types())? - .ok_or_else(|| AnalysisError::RecordExpected(type_.clone()))?; + .ok_or_else(|| { + AnalysisError::RecordExpected( + deconstruction.record().position().clone(), + type_.clone(), + ) + })?; if !open_records.contains(record_type.name()) { return Err(AnalysisError::RecordFieldPrivate( @@ -41,7 +49,12 @@ pub fn validate(context: &AnalysisContext, module: &Module) -> Result<(), Analys Expression::RecordUpdate(update) => { let record_type = type_canonicalizer::canonicalize_record(update.type_(), context.types())? - .ok_or_else(|| AnalysisError::RecordExpected(update.type_().clone()))?; + .ok_or_else(|| { + AnalysisError::RecordExpected( + update.type_().position().clone(), + update.type_().clone(), + ) + })?; if !open_records.contains(record_type.name()) { return Err(AnalysisError::RecordFieldPrivate( diff --git a/lib/hir/src/analysis/type_checker.rs b/lib/hir/src/analysis/type_checker.rs index 428e99f3b7..770c212634 100644 --- a/lib/hir/src/analysis/type_checker.rs +++ b/lib/hir/src/analysis/type_checker.rs @@ -8,6 +8,7 @@ use crate::{ types::{self, Type}, }; use fnv::{FnvHashMap, FnvHashSet}; +use position::Position; pub fn check_types(context: &AnalysisContext, module: &Module) -> Result<(), AnalysisError> { let variables = plist::FlailMap::new(module_environment::create(module)); @@ -36,6 +37,8 @@ fn check_lambda( ), )?, lambda.result_type(), + lambda.body().position(), + lambda.result_type().position(), context.types(), )?; @@ -49,7 +52,15 @@ fn check_expression( ) -> Result { let check_expression = |expression, variables: &_| check_expression(context, expression, variables); - let check_subsumption = |lower: &_, upper: &_| check_subsumption(lower, upper, context.types()); + let check_subsumption = |lower_type: &_, upper_type: &_, lower_position: &_, upper_position| { + check_subsumption( + lower_type, + upper_type, + lower_position, + upper_position, + context.types(), + ) + }; Ok(match expression { Expression::Boolean(boolean) => types::Boolean::new(boolean.position().clone()).into(), @@ -63,20 +74,35 @@ fn check_expression( .function_type() .ok_or_else(|| AnalysisError::TypeNotInferred(call.position().clone()))?; let function_type = type_canonicalizer::canonicalize_function(type_, context.types())? - .ok_or_else(|| AnalysisError::FunctionExpected(type_.clone()))?; + .ok_or_else(|| { + AnalysisError::FunctionExpected( + call.function().position().clone(), + type_.clone(), + ) + })?; if call.arguments().len() != function_type.arguments().len() { return Err(AnalysisError::ArgumentCount(call.position().clone())); } for (argument, type_) in call.arguments().iter().zip(function_type.arguments()) { - check_subsumption(&check_expression(argument, variables)?, type_)?; + check_subsumption( + &check_expression(argument, variables)?, + type_, + argument.position(), + type_.position(), + )?; } if let Expression::BuiltInFunction(function) = call.function() { check_built_in_call(context, call, function, &function_type)?; } else { - check_subsumption(&check_expression(call.function(), variables)?, type_)?; + check_subsumption( + &check_expression(call.function(), variables)?, + type_, + call.function().position(), + type_.position(), + )?; } function_type.result().clone() @@ -85,6 +111,8 @@ fn check_expression( check_subsumption( &check_expression(if_.condition(), variables)?, &types::Boolean::new(if_.position().clone()).into(), + if_.condition().position(), + if_.position(), )?; check_expression(if_.then(), variables)?; @@ -103,6 +131,8 @@ fn check_expression( check_subsumption( &check_expression(if_.list(), variables)?, &list_type.clone().into(), + if_.list().position(), + if_.position(), )?; check_expression( @@ -135,10 +165,17 @@ fn check_expression( if_.position().clone(), ); - check_subsumption(&check_expression(if_.key(), variables)?, map_type.key())?; + check_subsumption( + &check_expression(if_.key(), variables)?, + map_type.key(), + if_.key().position(), + map_type.key().position(), + )?; check_subsumption( &check_expression(if_.map(), variables)?, &map_type.clone().into(), + if_.map().position(), + map_type.position(), )?; check_expression( @@ -156,11 +193,19 @@ fn check_expression( )?; if !argument_type.is_variant() { - return Err(AnalysisError::VariantExpected(argument_type)); + return Err(AnalysisError::VariantExpected( + if_.argument().position().clone(), + argument_type, + )); } for branch in if_.branches() { - check_subsumption(branch.type_(), &argument_type)?; + check_subsumption( + branch.type_(), + &argument_type, + branch.type_().position(), + if_.argument().position(), + )?; check_expression( branch.expression(), @@ -206,11 +251,15 @@ fn check_expression( } Expression::Lambda(lambda) => check_lambda(context, lambda, variables)?.into(), Expression::Let(let_) => { + let bound_type = let_.type_().ok_or_else(|| { + AnalysisError::TypeNotInferred(let_.bound_expression().position().clone()) + })?; + check_subsumption( &check_expression(let_.bound_expression(), variables)?, - let_.type_().ok_or_else(|| { - AnalysisError::TypeNotInferred(let_.bound_expression().position().clone()) - })?, + bound_type, + let_.bound_expression().position(), + bound_type.position(), )?; check_expression( @@ -235,13 +284,25 @@ fn check_expression( check_subsumption( type_canonicalizer::canonicalize_list(&type_, context.types())? - .ok_or(AnalysisError::ListExpected(type_))? + .ok_or_else(|| { + AnalysisError::ListExpected( + expression.position().clone(), + type_, + ) + })? .element(), list.type_(), + expression.position(), + list.type_().position(), )?; } ListElement::Single(expression) => { - check_subsumption(&check_expression(expression, variables)?, list.type_())?; + check_subsumption( + &check_expression(expression, variables)?, + list.type_(), + expression.position(), + list.type_().position(), + )?; } } } @@ -270,6 +331,8 @@ fn check_expression( check_subsumption( &check_expression(iteratee.expression(), &variables)?, type_, + iteratee.expression().position(), + type_.position(), )?; variables = variables.insert( @@ -277,7 +340,12 @@ fn check_expression( types::Function::new( vec![], type_canonicalizer::canonicalize_list(type_, context.types())? - .ok_or_else(|| AnalysisError::ListExpected(type_.clone()))? + .ok_or_else(|| { + AnalysisError::ListExpected( + iteratee.expression().position().clone(), + type_.clone(), + ) + })? .element() .clone(), position.clone(), @@ -290,6 +358,8 @@ fn check_expression( check_subsumption( &check_expression(condition, &variables)?, &types::Boolean::new(position.clone()).into(), + condition.position(), + condition.position(), )?; } } @@ -297,6 +367,8 @@ fn check_expression( check_subsumption( &check_expression(comprehension.element(), &variables)?, comprehension.type_(), + comprehension.element().position(), + comprehension.type_().position(), )?; types::List::new(comprehension.type_().clone(), position.clone()).into() @@ -308,20 +380,36 @@ fn check_expression( check_subsumption( &check_expression(entry.key(), variables)?, map.key_type(), + entry.key().position(), + map.key_type().position(), )?; check_subsumption( &check_expression(entry.value(), variables)?, map.value_type(), + entry.value().position(), + map.value_type().position(), )?; } MapElement::Map(expression) => { let type_ = check_expression(expression, variables)?; let map_type = type_canonicalizer::canonicalize_map(&type_, context.types())? - .ok_or(AnalysisError::MapExpected(type_))?; + .ok_or_else(|| { + AnalysisError::MapExpected(expression.position().clone(), type_) + })?; - check_subsumption(map_type.key(), map.key_type())?; - check_subsumption(map_type.value(), map.value_type())?; + check_subsumption( + map_type.key(), + map.key_type(), + map_type.key().position(), + map.key_type().position(), + )?; + check_subsumption( + map_type.value(), + map.value_type(), + map_type.value().position(), + map.value_type().position(), + )?; } } } @@ -339,18 +427,23 @@ fn check_expression( Expression::RecordConstruction(construction) => { let field_types = record_field_resolver::resolve( construction.type_(), + construction.type_().position(), context.types(), context.records(), )?; for field in construction.fields() { + let field_type = field_types + .iter() + .find(|field_type| field_type.name() == field.name()) + .ok_or_else(|| AnalysisError::UnknownRecordField(field.position().clone()))? + .type_(); + check_subsumption( &check_expression(field.expression(), variables)?, - field_types - .iter() - .find(|field_type| field_type.name() == field.name()) - .ok_or_else(|| AnalysisError::UnknownRecordField(field.position().clone()))? - .type_(), + field_type, + field.expression().position(), + field_type.position(), )?; } @@ -379,10 +472,16 @@ fn check_expression( check_subsumption( &check_expression(deconstruction.record(), variables)?, type_, + deconstruction.record().position(), + type_.position(), )?; - let field_types = - record_field_resolver::resolve(type_, context.types(), context.records())?; + let field_types = record_field_resolver::resolve( + type_, + deconstruction.record().position(), + context.types(), + context.records(), + )?; field_types .iter() @@ -397,19 +496,29 @@ fn check_expression( check_subsumption( &check_expression(update.record(), variables)?, update.type_(), + update.record().position(), + update.type_().position(), )?; - let field_types = - record_field_resolver::resolve(update.type_(), context.types(), context.records())?; + let field_types = record_field_resolver::resolve( + update.type_(), + update.type_().position(), + context.types(), + context.records(), + )?; for field in update.fields() { + let field_type = field_types + .iter() + .find(|field_type| field_type.name() == field.name()) + .ok_or_else(|| AnalysisError::UnknownRecordField(field.position().clone()))? + .type_(); + check_subsumption( &check_expression(field.expression(), variables)?, - field_types - .iter() - .find(|field_type| field_type.name() == field.name()) - .ok_or_else(|| AnalysisError::UnknownRecordField(field.position().clone()))? - .type_(), + field_type, + field.expression().position(), + field_type.position(), )?; } @@ -421,7 +530,12 @@ fn check_expression( .type_() .ok_or_else(|| AnalysisError::TypeNotInferred(thunk.position().clone()))?; - check_subsumption(&check_expression(thunk.expression(), variables)?, type_)?; + check_subsumption( + &check_expression(thunk.expression(), variables)?, + type_, + thunk.expression().position(), + type_.position(), + )?; type_extractor::extract_from_expression(context, expression, variables)? } @@ -429,12 +543,19 @@ fn check_expression( check_subsumption( &check_expression(coercion.argument(), variables)?, coercion.from(), + coercion.argument().position(), + coercion.from().position(), )?; let to_type = type_canonicalizer::canonicalize(coercion.to(), context.types())?; if !to_type.is_list() && !to_type.is_map() { - check_subsumption(coercion.from(), coercion.to())?; + check_subsumption( + coercion.from(), + coercion.to(), + coercion.from().position(), + coercion.to().position(), + )?; } coercion.to().clone() @@ -459,43 +580,74 @@ fn check_built_in_call( let [map_type, key_type] = function_type.arguments() else { return Err(AnalysisError::ArgumentCount(position.clone())); }; + let [map_argument, key_argument] = call.arguments() else { + return Err(AnalysisError::ArgumentCount(position.clone())); + }; + + check_subsumption( + map_type, + function_type.result(), + map_argument.position(), + position, + context.types(), + )?; + + let map_type = type_canonicalizer::canonicalize_map(map_type, context.types())? + .ok_or_else(|| { + AnalysisError::MapExpected(map_argument.position().clone(), map_type.clone()) + })?; - check_subsumption(map_type, function_type.result(), context.types())?; check_subsumption( key_type, - type_canonicalizer::canonicalize_map(map_type, context.types())? - .ok_or_else(|| AnalysisError::MapExpected(map_type.clone()))? - .key(), + map_type.key(), + key_argument.position(), + map_type.key().position(), context.types(), )?; } BuiltInFunctionName::Race => { - let [argument_type] = function_type.arguments() else { + let ([argument], [argument_type]) = (call.arguments(), function_type.arguments()) else { return Err(AnalysisError::ArgumentCount(position.clone())); }; - let argument_type = - type_canonicalizer::canonicalize_list(argument_type, context.types())? - .ok_or_else(|| AnalysisError::ListExpected(argument_type.clone()))?; + let argument_type = type_canonicalizer::canonicalize_list( + argument_type, + context.types(), + )? + .ok_or_else(|| { + AnalysisError::ListExpected(argument.position().clone(), argument_type.clone()) + })?; if type_canonicalizer::canonicalize_list(argument_type.element(), context.types())? .is_none() { - return Err(AnalysisError::ListExpected(argument_type.element().clone())); + // TODO Show both outer and inner types. + return Err(AnalysisError::ListExpected( + argument.position().clone(), + argument_type.element().clone(), + )); } } BuiltInFunctionName::Size => { - if let [argument_type] = function_type.arguments() { + if let ([argument], [argument_type]) = (call.arguments(), function_type.arguments()) { if !matches!(argument_type, Type::List(_) | Type::Map(_)) { - return Err(AnalysisError::CollectionExpected(argument_type.clone())); + return Err(AnalysisError::CollectionExpected( + argument.position().clone(), + argument_type.clone(), + )); } } else { return Err(AnalysisError::ArgumentCount(position.clone())); } } BuiltInFunctionName::Spawn => { - if let [argument_type] = function_type.arguments() { + if let ([argument], [argument_type]) = (call.arguments(), function_type.arguments()) { if !type_canonicalizer::canonicalize_function(argument_type, context.types())? - .ok_or_else(|| AnalysisError::FunctionExpected(argument_type.clone()))? + .ok_or_else(|| { + AnalysisError::FunctionExpected( + argument.position().clone(), + argument_type.clone(), + ) + })? .arguments() .is_empty() { @@ -523,25 +675,54 @@ fn check_operation( variables: &plist::FlailMap, ) -> Result { let check_expression = |expression| check_expression(context, expression, variables); - let check_subsumption = |lower: &_, upper| check_subsumption(lower, upper, context.types()); + let check_subsumption = |lower_type: &_, upper_type, lower_position, upper_position| { + check_subsumption( + lower_type, + upper_type, + lower_position, + upper_position, + context.types(), + ) + }; + let position = operation.position(); Ok(match operation { Operation::Addition(operation) => { let type_ = operation .type_() - .ok_or_else(|| AnalysisError::TypeNotInferred(operation.position().clone()))?; - let number_type = types::Number::new(operation.position().clone()).into(); - let string_type = types::ByteString::new(operation.position().clone()).into(); + .ok_or_else(|| AnalysisError::TypeNotInferred(position.clone()))?; + let number_type = types::Number::new(position.clone()).into(); + let string_type = types::ByteString::new(position.clone()).into(); let lhs_type = check_expression(operation.lhs())?; let rhs_type = check_expression(operation.rhs())?; if type_equality_checker::check(type_, &number_type, context.types())? { - check_subsumption(&lhs_type, &number_type)?; - check_subsumption(&rhs_type, &number_type)?; + check_subsumption( + &lhs_type, + &number_type, + operation.lhs().position(), + position, + )?; + check_subsumption( + &rhs_type, + &number_type, + operation.rhs().position(), + position, + )?; } else if type_equality_checker::check(type_, &string_type, context.types())? { - check_subsumption(&lhs_type, &string_type)?; - check_subsumption(&rhs_type, &string_type)?; + check_subsumption( + &lhs_type, + &string_type, + operation.lhs().position(), + position, + )?; + check_subsumption( + &rhs_type, + &string_type, + operation.rhs().position(), + position, + )?; } else { return Err(AnalysisError::InvalidAdditionOperand( type_.position().clone(), @@ -553,16 +734,36 @@ fn check_operation( Operation::Arithmetic(operation) => { let number_type = types::Number::new(operation.position().clone()).into(); - check_subsumption(&check_expression(operation.lhs())?, &number_type)?; - check_subsumption(&check_expression(operation.rhs())?, &number_type)?; + check_subsumption( + &check_expression(operation.lhs())?, + &number_type, + operation.lhs().position(), + position, + )?; + check_subsumption( + &check_expression(operation.rhs())?, + &number_type, + operation.rhs().position(), + position, + )?; number_type } Operation::Boolean(operation) => { let boolean_type = types::Boolean::new(operation.position().clone()).into(); - check_subsumption(&check_expression(operation.lhs())?, &boolean_type)?; - check_subsumption(&check_expression(operation.rhs())?, &boolean_type)?; + check_subsumption( + &check_expression(operation.lhs())?, + &boolean_type, + operation.lhs().position(), + position, + )?; + check_subsumption( + &check_expression(operation.rhs())?, + &boolean_type, + operation.rhs().position(), + position, + )?; boolean_type } @@ -571,8 +772,18 @@ fn check_operation( .type_() .ok_or_else(|| AnalysisError::TypeNotInferred(operation.position().clone()))?; - check_subsumption(&check_expression(operation.lhs())?, operand_type)?; - check_subsumption(&check_expression(operation.rhs())?, operand_type)?; + check_subsumption( + &check_expression(operation.lhs())?, + operand_type, + operation.lhs().position(), + position, + )?; + check_subsumption( + &check_expression(operation.rhs())?, + operand_type, + operation.rhs().position(), + position, + )?; let lhs_type = type_extractor::extract_from_expression(context, operation.lhs(), variables)?; @@ -582,7 +793,10 @@ fn check_operation( if !type_subsumption_checker::check(&lhs_type, &rhs_type, context.types())? && !type_subsumption_checker::check(&rhs_type, &lhs_type, context.types())? { - return Err(AnalysisError::TypesNotMatched(lhs_type, rhs_type)); + return Err(AnalysisError::TypesNotMatched { + found: (operation.lhs().position().clone(), lhs_type), + expected: (operation.rhs().position().clone(), rhs_type), + }); } types::Boolean::new(operation.position().clone()).into() @@ -590,32 +804,59 @@ fn check_operation( Operation::Not(operation) => { let boolean_type = types::Boolean::new(operation.position().clone()).into(); - check_subsumption(&check_expression(operation.expression())?, &boolean_type)?; + check_subsumption( + &check_expression(operation.expression())?, + &boolean_type, + operation.expression().position(), + position, + )?; boolean_type } Operation::Order(operation) => { let number_type = types::Number::new(operation.position().clone()).into(); - check_subsumption(&check_expression(operation.lhs())?, &number_type)?; - check_subsumption(&check_expression(operation.rhs())?, &number_type)?; + check_subsumption( + &check_expression(operation.lhs())?, + &number_type, + operation.lhs().position(), + position, + )?; + check_subsumption( + &check_expression(operation.rhs())?, + &number_type, + operation.rhs().position(), + position, + )?; types::Boolean::new(operation.position().clone()).into() } Operation::Try(operation) => { - let position = operation.position(); let success_type = operation .type_() .ok_or_else(|| AnalysisError::TypeNotInferred(position.clone()))?; let error_type = types::Error::new(position.clone()).into(); let union_type = check_expression(operation.expression())?; - check_subsumption(&error_type, &union_type)?; - check_subsumption(success_type, &union_type)?; + check_subsumption( + &error_type, + &union_type, + position, + operation.expression().position(), + )?; + + check_subsumption( + success_type, + &union_type, + position, + operation.expression().position(), + )?; check_subsumption( &union_type, &types::Union::new(success_type.clone(), error_type, position.clone()).into(), + operation.expression().position(), + position, )?; success_type.clone() @@ -624,14 +865,19 @@ fn check_operation( } fn check_subsumption( - lower: &Type, - upper: &Type, + lower_type: &Type, + upper_type: &Type, + lower_position: &Position, + upper_position: &Position, types: &FnvHashMap, ) -> Result<(), AnalysisError> { - if type_subsumption_checker::check(lower, upper, types)? { + if type_subsumption_checker::check(lower_type, upper_type, types)? { Ok(()) } else { - Err(AnalysisError::TypesNotMatched(lower.clone(), upper.clone())) + Err(AnalysisError::TypesNotMatched { + found: (lower_position.clone(), lower_type.clone()), + expected: (upper_position.clone(), upper_type.clone()), + }) } } @@ -710,10 +956,13 @@ mod tests { function_type, )]) ), - Err(AnalysisError::TypesNotMatched( - types::Number::new(Position::fake()).into(), - types::None::new(Position::fake()).into(), - )) + Err(AnalysisError::TypesNotMatched { + found: ( + Position::fake(), + types::Number::new(Position::fake()).into() + ), + expected: (Position::fake(), types::None::new(Position::fake()).into(),) + }) ); } @@ -820,10 +1069,13 @@ mod tests { false, ) ])), - Err(AnalysisError::TypesNotMatched( - types::None::new(Position::fake()).into(), - types::Number::new(Position::fake()).into(), - )) + Err(AnalysisError::TypesNotMatched { + found: (Position::fake(), types::None::new(Position::fake()).into()), + expected: ( + Position::fake(), + types::Number::new(Position::fake()).into(), + ) + }) ); } } @@ -876,10 +1128,13 @@ mod tests { false, ) ])), - Err(AnalysisError::TypesNotMatched( - types::None::new(Position::fake()).into(), - types::Boolean::new(Position::fake()).into(), - )) + Err(AnalysisError::TypesNotMatched { + found: (Position::fake(), types::None::new(Position::fake()).into()), + expected: ( + Position::fake(), + types::Boolean::new(Position::fake()).into(), + ) + }) ); } } @@ -956,10 +1211,13 @@ mod tests { false, ) ]),), - Err(AnalysisError::TypesNotMatched( - types::None::new(Position::fake()).into(), - types::Boolean::new(Position::fake()).into(), - )) + Err(AnalysisError::TypesNotMatched { + found: (Position::fake(), types::None::new(Position::fake()).into()), + expected: ( + Position::fake(), + types::Boolean::new(Position::fake()).into(), + ) + }) ); } @@ -983,10 +1241,13 @@ mod tests { false, ) ]),), - Err(AnalysisError::TypesNotMatched( - types::None::new(Position::fake()).into(), - types::Boolean::new(Position::fake()).into(), - )) + Err(AnalysisError::TypesNotMatched { + found: (Position::fake(), types::None::new(Position::fake()).into()), + expected: ( + Position::fake(), + types::Boolean::new(Position::fake()).into(), + ) + }) ); } } @@ -1548,10 +1809,16 @@ mod tests { false, ) ],)), - Err(AnalysisError::TypesNotMatched( - types::Number::new(Position::fake()).into(), - types::Boolean::new(Position::fake()).into(), - )) + Err(AnalysisError::TypesNotMatched { + found: ( + Position::fake(), + types::Number::new(Position::fake()).into() + ), + expected: ( + Position::fake(), + types::Boolean::new(Position::fake()).into(), + ) + }) ); } @@ -1636,10 +1903,13 @@ mod tests { false, )] )), - Err(AnalysisError::TypesNotMatched( - types::Number::new(Position::fake()).into(), - types::None::new(Position::fake()).into() - )) + Err(AnalysisError::TypesNotMatched { + found: ( + Position::fake(), + types::Number::new(Position::fake()).into() + ), + expected: (Position::fake(), types::None::new(Position::fake()).into()) + }) ); } @@ -1789,10 +2059,13 @@ mod tests { false, ) ]),), - Err(AnalysisError::TypesNotMatched( - types::Number::new(Position::fake()).into(), - union_type.into() - )) + Err(AnalysisError::TypesNotMatched { + found: ( + Position::fake(), + types::Number::new(Position::fake()).into() + ), + expected: (Position::fake(), union_type.into()) + }) ); } @@ -1819,10 +2092,10 @@ mod tests { false, ) ]),), - Err(AnalysisError::TypesNotMatched( - types::Error::new(Position::fake()).into(), - types::None::new(Position::fake()).into(), - )) + Err(AnalysisError::TypesNotMatched { + found: (Position::fake(), types::Error::new(Position::fake()).into()), + expected: (Position::fake(), types::None::new(Position::fake()).into(),) + }) ); } } @@ -2073,10 +2346,16 @@ mod tests { false, )]) ), - Err(AnalysisError::TypesNotMatched( - types::Reference::new("r1", Position::fake()).into(), - types::Reference::new("r2", Position::fake()).into(), - )) + Err(AnalysisError::TypesNotMatched { + found: ( + Position::fake(), + types::Reference::new("r1", Position::fake()).into() + ), + expected: ( + Position::fake(), + types::Reference::new("r2", Position::fake()).into(), + ) + }) ); } } @@ -2152,10 +2431,13 @@ mod tests { false, ) ])), - Err(AnalysisError::TypesNotMatched( - types::Number::new(Position::fake()).into(), - types::None::new(Position::fake()).into(), - )) + Err(AnalysisError::TypesNotMatched { + found: ( + Position::fake(), + types::Number::new(Position::fake()).into() + ), + expected: (Position::fake(), types::None::new(Position::fake()).into(),) + }) ); } @@ -2186,10 +2468,13 @@ mod tests { false, ) ]),), - Err(AnalysisError::TypesNotMatched( - types::Number::new(Position::fake()).into(), - types::None::new(Position::fake()).into(), - )) + Err(AnalysisError::TypesNotMatched { + found: ( + Position::fake(), + types::Number::new(Position::fake()).into() + ), + expected: (Position::fake(), types::None::new(Position::fake()).into(),) + }) ); } @@ -2350,10 +2635,13 @@ mod tests { false, )] )), - Err(AnalysisError::TypesNotMatched( - types::Number::new(Position::fake()).into(), - types::None::new(Position::fake()).into(), - )) + Err(AnalysisError::TypesNotMatched { + found: ( + Position::fake(), + types::Number::new(Position::fake()).into() + ), + expected: (Position::fake(), types::None::new(Position::fake()).into(),) + }) ); } @@ -2388,10 +2676,13 @@ mod tests { false, ) ])), - Err(AnalysisError::TypesNotMatched( - types::None::new(Position::fake()).into(), - types::Boolean::new(Position::fake()).into(), - )) + Err(AnalysisError::TypesNotMatched { + found: (Position::fake(), types::None::new(Position::fake()).into()), + expected: ( + Position::fake(), + types::Boolean::new(Position::fake()).into(), + ) + }) ); } @@ -2454,10 +2745,13 @@ mod tests { false, )] )), - Err(AnalysisError::TypesNotMatched( - types::Number::new(Position::fake()).into(), - types::None::new(Position::fake()).into(), - )) + Err(AnalysisError::TypesNotMatched { + found: ( + Position::fake(), + types::Number::new(Position::fake()).into() + ), + expected: (Position::fake(), types::None::new(Position::fake()).into(),) + }) ); } @@ -2620,10 +2914,13 @@ mod tests { false, ) ])), - Err(AnalysisError::TypesNotMatched( - types::Number::new(Position::fake()).into(), - types::None::new(Position::fake()).into(), - )), + Err(AnalysisError::TypesNotMatched { + found: ( + Position::fake(), + types::Number::new(Position::fake()).into() + ), + expected: (Position::fake(), types::None::new(Position::fake()).into(),) + }), ); } @@ -2644,11 +2941,11 @@ mod tests { types::None::new(Position::fake()), types::None::new(Position::fake()), vec![MapEntry::new( - None::new(Position::fake()), - Number::new(42.0, Position::fake()), - Position::fake(), - ) - .into()], + None::new(Position::fake()), + Number::new(42.0, Position::fake()), + Position::fake(), + ) + .into()], Position::fake(), ), Position::fake(), @@ -2656,10 +2953,13 @@ mod tests { false, ) ])), - Err(AnalysisError::TypesNotMatched( - types::Number::new(Position::fake()).into(), - types::None::new(Position::fake()).into(), - )), + Err(AnalysisError::TypesNotMatched { + found: ( + Position::fake(), + types::Number::new(Position::fake()).into() + ), + expected: (Position::fake(), types::None::new(Position::fake()).into()), + }), ); } @@ -2724,10 +3024,13 @@ mod tests { false, ) ])), - Err(AnalysisError::TypesNotMatched( - types::Number::new(Position::fake()).into(), - types::None::new(Position::fake()).into(), - )), + Err(AnalysisError::TypesNotMatched { + found: ( + Position::fake(), + types::Number::new(Position::fake()).into() + ), + expected: (Position::fake(), types::None::new(Position::fake()).into()), + }), ); } @@ -2762,10 +3065,13 @@ mod tests { false, ) ])), - Err(AnalysisError::TypesNotMatched( - types::Number::new(Position::fake()).into(), - types::None::new(Position::fake()).into(), - )), + Err(AnalysisError::TypesNotMatched { + found: ( + Position::fake(), + types::Number::new(Position::fake()).into() + ), + expected: (Position::fake(), types::None::new(Position::fake()).into()), + }), ); } } @@ -2906,10 +3212,18 @@ mod tests { false, ) ]),), - Err(AnalysisError::TypesNotMatched( - types::List::new(types::Number::new(Position::fake()), Position::fake()).into(), - types::List::new(types::None::new(Position::fake()), Position::fake()).into(), - )) + Err(AnalysisError::TypesNotMatched { + found: ( + Position::fake(), + types::List::new(types::Number::new(Position::fake()), Position::fake()) + .into() + ), + expected: ( + Position::fake(), + types::List::new(types::None::new(Position::fake()), Position::fake()) + .into() + ), + }) ); } @@ -2938,19 +3252,22 @@ mod tests { false, ) ]),), - Err(AnalysisError::TypesNotMatched( - types::Union::new( - types::Function::new( - vec![], - types::None::new(Position::fake()), + Err(AnalysisError::TypesNotMatched { + found: ( + Position::fake(), + types::Union::new( + types::Function::new( + vec![], + types::None::new(Position::fake()), + Position::fake() + ), + types::Number::new(Position::fake()), Position::fake() - ), - types::Number::new(Position::fake()), - Position::fake() - ) - .into(), - types::None::new(Position::fake()).into(), - )) + ) + .into() + ), + expected: (Position::fake(), types::None::new(Position::fake()).into()), + }) ); } } @@ -3062,10 +3379,10 @@ mod tests { false, ) ]),), - Err(AnalysisError::TypesNotMatched( - wrong_map_type.into(), - map_type.into(), - )) + Err(AnalysisError::TypesNotMatched { + found: (Position::fake(), wrong_map_type.into()), + expected: (Position::fake(), map_type.into()), + }) ); } @@ -3099,10 +3416,16 @@ mod tests { false, ) ]),), - Err(AnalysisError::TypesNotMatched( - types::Number::new(Position::fake()).into(), - types::Boolean::new(Position::fake()).into(), - )) + Err(AnalysisError::TypesNotMatched { + found: ( + Position::fake(), + types::Number::new(Position::fake()).into() + ), + expected: ( + Position::fake(), + types::Boolean::new(Position::fake()).into() + ), + }) ); } @@ -3136,15 +3459,18 @@ mod tests { false, ) ])), - Err(AnalysisError::TypesNotMatched( - types::Union::new( - types::Number::new(Position::fake()), - types::None::new(Position::fake()), - Position::fake() - ) - .into(), - types::None::new(Position::fake()).into(), - )) + Err(AnalysisError::TypesNotMatched { + found: ( + Position::fake(), + types::Union::new( + types::Number::new(Position::fake()), + types::None::new(Position::fake()), + Position::fake() + ) + .into() + ), + expected: (Position::fake(), types::None::new(Position::fake()).into()), + }) ); } } @@ -3355,7 +3681,7 @@ mod tests { false, ),] )), - Err(AnalysisError::TypesNotMatched(_, _)) + Err(AnalysisError::TypesNotMatched { .. }) )); } @@ -3395,7 +3721,7 @@ mod tests { false, ), ])), - Err(AnalysisError::TypesNotMatched(_, _)) + Err(AnalysisError::TypesNotMatched { .. }) )); } } @@ -3540,7 +3866,7 @@ mod tests { false, )] )), - Err(AnalysisError::CollectionExpected(_)), + Err(AnalysisError::CollectionExpected(_, _)), )); } } diff --git a/lib/hir/src/analysis/type_coercer.rs b/lib/hir/src/analysis/type_coercer.rs index e0d607a2ac..4874c98320 100644 --- a/lib/hir/src/analysis/type_coercer.rs +++ b/lib/hir/src/analysis/type_coercer.rs @@ -90,7 +90,12 @@ fn transform_expression( .function_type() .ok_or_else(|| AnalysisError::TypeNotInferred(call.position().clone()))?; let function_type = type_canonicalizer::canonicalize_function(type_, context.types())? - .ok_or_else(|| AnalysisError::FunctionExpected(type_.clone()))?; + .ok_or_else(|| { + AnalysisError::FunctionExpected( + call.function().position().clone(), + type_.clone(), + ) + })?; Call::new( call.function_type().cloned(), @@ -308,7 +313,12 @@ fn transform_expression( types::Function::new( vec![], type_canonicalizer::canonicalize_list(type_, context.types())? - .ok_or_else(|| AnalysisError::ListExpected(type_.clone()))? + .ok_or_else(|| { + AnalysisError::ListExpected( + iteratee.expression().position().clone(), + type_.clone(), + ) + })? .element() .clone(), position.clone(), @@ -492,8 +502,12 @@ fn transform_record_fields( variables: &plist::FlailMap, context: &AnalysisContext, ) -> Result, AnalysisError> { - let field_types = - record_field_resolver::resolve(record_type, context.types(), context.records())?; + let field_types = record_field_resolver::resolve( + record_type, + record_type.position(), + context.types(), + context.records(), + )?; fields .iter() diff --git a/lib/hir/src/analysis/type_comparability_checker.rs b/lib/hir/src/analysis/type_comparability_checker.rs index 7133896938..558001de96 100644 --- a/lib/hir/src/analysis/type_comparability_checker.rs +++ b/lib/hir/src/analysis/type_comparability_checker.rs @@ -12,6 +12,7 @@ pub fn check( fn check_with_cache( type_: &Type, + // TODO Use a persistent data structure. record_names: &FnvHashSet, types: &FnvHashMap, record_types: &FnvHashMap>, @@ -41,7 +42,7 @@ fn check_with_cache( .chain([record.name().into()]) .collect(); - record_field_resolver::resolve(type_, types, record_types)? + record_field_resolver::resolve_record(record, record_types)? .iter() .map(|field| check_with_cache(field.type_(), &record_names)) .collect::, _>>()? diff --git a/lib/hir/src/analysis/type_extractor.rs b/lib/hir/src/analysis/type_extractor.rs index 345dc7f7d0..4cbaeaf33b 100644 --- a/lib/hir/src/analysis/type_extractor.rs +++ b/lib/hir/src/analysis/type_extractor.rs @@ -26,7 +26,12 @@ pub fn extract_from_expression( .ok_or_else(|| AnalysisError::TypeNotInferred(call.position().clone()))?; type_canonicalizer::canonicalize_function(type_, context.types())? - .ok_or_else(|| AnalysisError::FunctionExpected(type_.clone()))? + .ok_or_else(|| { + AnalysisError::FunctionExpected( + call.function().position().clone(), + type_.clone(), + ) + })? .result() .clone() } @@ -39,7 +44,7 @@ pub fn extract_from_expression( Expression::IfList(if_) => { let type_ = extract_from_expression(if_.list(), variables)?; let list_type = type_canonicalizer::canonicalize_list(&type_, context.types())? - .ok_or(AnalysisError::ListExpected(type_))?; + .ok_or_else(|| AnalysisError::ListExpected(if_.list().position().clone(), type_))?; types::Union::new( extract_from_expression( @@ -65,7 +70,7 @@ pub fn extract_from_expression( Expression::IfMap(if_) => { let type_ = extract_from_expression(if_.map(), variables)?; let map_type = type_canonicalizer::canonicalize_map(&type_, context.types())? - .ok_or(AnalysisError::MapExpected(type_))?; + .ok_or_else(|| AnalysisError::MapExpected(if_.map().position().clone(), type_))?; types::Union::new( extract_from_expression( @@ -162,18 +167,24 @@ pub fn extract_from_expression( .clone(), }, Expression::RecordConstruction(construction) => construction.type_().clone(), - Expression::RecordDeconstruction(deconstruction) => record_field_resolver::resolve( - deconstruction + Expression::RecordDeconstruction(deconstruction) => { + let type_ = deconstruction .type_() - .ok_or_else(|| AnalysisError::TypeNotInferred(deconstruction.position().clone()))?, - context.types(), - context.records(), - )? - .iter() - .find(|field| field.name() == deconstruction.field_name()) - .ok_or_else(|| AnalysisError::UnknownRecordField(deconstruction.position().clone()))? - .type_() - .clone(), + .ok_or_else(|| AnalysisError::TypeNotInferred(deconstruction.position().clone()))?; + + record_field_resolver::resolve( + type_, + deconstruction.position(), + context.types(), + context.records(), + )? + .iter() + .find(|field| field.name() == deconstruction.field_name()) + // TODO Use a field position. + .ok_or_else(|| AnalysisError::UnknownRecordField(deconstruction.position().clone()))? + .type_() + .clone() + } Expression::RecordUpdate(update) => update.type_().clone(), Expression::String(string) => types::ByteString::new(string.position().clone()).into(), Expression::Thunk(thunk) => types::Function::new( diff --git a/lib/hir/src/analysis/type_inferrer.rs b/lib/hir/src/analysis/type_inferrer.rs index 381baba72f..6eb48b41be 100644 --- a/lib/hir/src/analysis/type_inferrer.rs +++ b/lib/hir/src/analysis/type_inferrer.rs @@ -106,7 +106,7 @@ fn infer_expression( let list = infer_expression(if_.list(), variables)?; let type_ = type_extractor::extract_from_expression(context, &list, variables)?; let list_type = type_canonicalizer::canonicalize_list(&type_, context.types())? - .ok_or(AnalysisError::ListExpected(type_))?; + .ok_or_else(|| AnalysisError::ListExpected(list.position().clone(), type_))?; let then = infer_expression( if_.then(), @@ -141,7 +141,7 @@ fn infer_expression( let key = infer_expression(if_.key(), variables)?; let type_ = type_extractor::extract_from_expression(context, &map, variables)?; let map_type = type_canonicalizer::canonicalize_map(&type_, context.types())? - .ok_or(AnalysisError::MapExpected(type_))?; + .ok_or_else(|| AnalysisError::MapExpected(map.position().clone(), type_))?; let then = infer_expression( if_.then(), @@ -287,7 +287,12 @@ fn infer_expression( types::Function::new( vec![], type_canonicalizer::canonicalize_list(type_, context.types())? - .ok_or_else(|| AnalysisError::ListExpected(type_.clone()))? + .ok_or_else(|| { + AnalysisError::ListExpected( + iteratee.expression().position().clone(), + type_.clone(), + ) + })? .element() .clone(), comprehension.position().clone(), @@ -404,21 +409,25 @@ fn infer_expression( type_extractor::extract_from_expression(context, &expression, variables)?; TryOperation::new( - Some( - if let Some(type_) = type_difference_calculator::calculate( - &type_, - &types::Error::new(position.clone()).into(), - context.types(), - )? { - if type_.is_any() { - return Err(AnalysisError::UnionExpected(type_)); - } else { - type_ - } + Some(if let Some(type_) = type_difference_calculator::calculate( + &type_, + &types::Error::new(position.clone()).into(), + context.types(), + )? { + if type_.is_any() { + Err(AnalysisError::UnionExpected( + operation.expression().position().clone(), + type_, + )) } else { - return Err(AnalysisError::UnionExpected(type_)); - }, - ), + Ok(type_) + } + } else { + Err(AnalysisError::UnionExpected( + operation.expression().position().clone(), + type_, + )) + }?), expression, position.clone(), ) @@ -536,7 +545,7 @@ fn infer_built_in_call( position.clone(), ), BuiltInFunctionName::Keys => { - let [argument_type] = &argument_types[..] else { + let ([argument], [argument_type]) = (&arguments[..], &argument_types[..]) else { return Err(AnalysisError::ArgumentCount(position.clone())); }; @@ -544,7 +553,12 @@ fn infer_built_in_call( vec![argument_type.clone()], types::List::new( type_canonicalizer::canonicalize_map(argument_type, context.types())? - .ok_or_else(|| AnalysisError::MapExpected(argument_type.clone()))? + .ok_or_else(|| { + AnalysisError::MapExpected( + argument.position().clone(), + argument_type.clone(), + ) + })? .key() .clone(), position.clone(), @@ -553,12 +567,17 @@ fn infer_built_in_call( ) } BuiltInFunctionName::Race => { - let argument_type = argument_types - .first() - .ok_or_else(|| AnalysisError::ArgumentCount(position.clone()))?; + let ([argument], [argument_type]) = (&arguments[..], &argument_types[..]) else { + return Err(AnalysisError::ArgumentCount(position.clone())); + }; let argument_type = type_canonicalizer::canonicalize_list(argument_type, context.types())? - .ok_or_else(|| AnalysisError::ListExpected(argument_type.clone()))?; + .ok_or_else(|| { + AnalysisError::ListExpected( + argument.position().clone(), + argument_type.clone(), + ) + })?; types::Function::new( argument_types, @@ -602,7 +621,7 @@ fn infer_built_in_call( types::Function::new(argument_types, result_type, position.clone()) } BuiltInFunctionName::Values => { - let [argument_type] = &argument_types[..] else { + let ([argument], [argument_type]) = (&arguments[..], &argument_types[..]) else { return Err(AnalysisError::ArgumentCount(position.clone())); }; @@ -610,7 +629,12 @@ fn infer_built_in_call( vec![argument_type.clone()], types::List::new( type_canonicalizer::canonicalize_map(argument_type, context.types())? - .ok_or_else(|| AnalysisError::MapExpected(argument_type.clone()))? + .ok_or_else(|| { + AnalysisError::MapExpected( + argument.position().clone(), + argument_type.clone(), + ) + })? .value() .clone(), position.clone(), @@ -1826,6 +1850,7 @@ mod tests { ) ],)), Err(AnalysisError::UnionExpected( + Position::fake(), types::Error::new(Position::fake()).into() )) );