diff --git a/dora-frontend/src/error/msg.rs b/dora-frontend/src/error/msg.rs index 230ac9416..d08f1724d 100644 --- a/dora-frontend/src/error/msg.rs +++ b/dora-frontend/src/error/msg.rs @@ -213,6 +213,8 @@ pub enum ErrorMessage { FieldShouldBeUnnamed, OldClassDefinition, ExpectedNamedPattern, + IndexGetNotImplemented(String), + IndexSetNotImplemented(String), } impl ErrorMessage { @@ -735,6 +737,12 @@ impl ErrorMessage { ErrorMessage::ExpectedNamedPattern => { format!("Expected named pattern field.") } + ErrorMessage::IndexGetNotImplemented(ref ty) => { + format!("Type `{}` does not implement trait IndexGet.", ty) + } + ErrorMessage::IndexSetNotImplemented(ref ty) => { + format!("Type `{}` does not implement trait IndexGet.", ty) + } } } } diff --git a/dora-frontend/src/fctdefck.rs b/dora-frontend/src/fctdefck.rs index 86471cd9c..1f8572e49 100644 --- a/dora-frontend/src/fctdefck.rs +++ b/dora-frontend/src/fctdefck.rs @@ -3,22 +3,6 @@ use crate::ErrorMessage; pub fn check(sa: &Sema) { for (_id, fct) in sa.fcts.iter() { - for p in fct.params_without_self() { - let ast_node = p.ast.as_ref().expect("missing ast"); - - if fct.is_variadic() { - sa.report( - fct.file_id, - ast_node.span, - ErrorMessage::VariadicParameterNeedsToBeLast, - ); - } - - if ast_node.variadic { - fct.is_variadic.set(true); - } - } - check_test(sa, &*fct); } } diff --git a/dora-frontend/src/generator.rs b/dora-frontend/src/generator.rs index bec60d83d..785ad2941 100644 --- a/dora-frontend/src/generator.rs +++ b/dora-frontend/src/generator.rs @@ -1805,7 +1805,7 @@ impl<'a> AstBytecodeGen<'a> { }; // Calculate number of non-variadic arguments - let non_variadic_arguments = if callee.is_variadic.get() { + let non_variadic_arguments = if callee.params.is_variadic() { arg_types.len() - arg_start_offset - 1 } else { arg_types.len() @@ -1817,7 +1817,7 @@ impl<'a> AstBytecodeGen<'a> { registers.push(reg); } - if callee.is_variadic.get() { + if callee.params.is_variadic() { let array_reg = self.emit_array_with_variadic_arguments( expr, arg_types, diff --git a/dora-frontend/src/impldefck.rs b/dora-frontend/src/impldefck.rs index 61304a97f..0bb41d809 100644 --- a/dora-frontend/src/impldefck.rs +++ b/dora-frontend/src/impldefck.rs @@ -103,7 +103,7 @@ pub fn check_definition_against_trait(sa: &mut Sema) { let self_ty = Some(impl_.extended_ty()); let params = trait_method.params.clone(); - for param in ¶ms { + for param in ¶ms.params { param.set_ty(replace_type(sa, param.ty(), None, self_ty.clone())); } diff --git a/dora-frontend/src/program_emitter.rs b/dora-frontend/src/program_emitter.rs index 40d8f4572..7c2ee8018 100644 --- a/dora-frontend/src/program_emitter.rs +++ b/dora-frontend/src/program_emitter.rs @@ -197,7 +197,7 @@ fn create_functions(sa: &Sema, e: &mut Emitter) -> Vec { is_internal: fct.is_internal, is_test: fct.is_test, is_optimize_immediately: fct.is_optimize_immediately, - is_variadic: fct.is_variadic.get(), + is_variadic: fct.params.is_variadic(), is_force_inline: fct.is_force_inline, is_never_inline: fct.is_never_inline, bytecode: fct.bytecode.get().cloned(), diff --git a/dora-frontend/src/program_parser.rs b/dora-frontend/src/program_parser.rs index 77a0cc548..6043e3e27 100644 --- a/dora-frontend/src/program_parser.rs +++ b/dora-frontend/src/program_parser.rs @@ -13,9 +13,9 @@ use crate::sema::{ EnumDefinition, EnumField, EnumVariant, ExtensionDefinition, ExtensionDefinitionId, FctDefinition, FctDefinitionId, FctParent, Field, FieldId, GlobalDefinition, ImplDefinition, ImplDefinitionId, ModuleDefinition, ModuleDefinitionId, PackageDefinition, PackageDefinitionId, - PackageName, Param, Sema, SourceFile, SourceFileId, StructDefinition, StructDefinitionField, - StructDefinitionFieldId, TraitDefinition, TraitDefinitionId, TypeParamDefinition, - UseDefinition, Visibility, + PackageName, Param, Params, Sema, SourceFile, SourceFileId, StructDefinition, + StructDefinitionField, StructDefinitionFieldId, TraitDefinition, TraitDefinitionId, + TypeParamDefinition, UseDefinition, Visibility, }; use crate::sym::{SymTable, Symbol, SymbolKind}; use crate::{report_sym_shadow_span, ty, ParsedType, SourceType}; @@ -529,7 +529,7 @@ impl<'x> visit::Visitor for TopLevelDeclaration<'x> { .set(extension_id) .is_ok()); - find_elements_in_extension(self.sa, extension_id, node); + find_elements_in_extension(self.sa, self.file_id, extension_id, node); } } @@ -701,7 +701,7 @@ impl<'x> visit::Visitor for TopLevelDeclaration<'x> { ); let parent = FctParent::None; - let params = parse_function_params(self.sa, node, parent.clone(), &modifiers); + let params = parse_function_params(self.sa, self.file_id, node, parent.clone(), &modifiers); let fct = FctDefinition::new( self.package_id, @@ -912,7 +912,8 @@ fn find_elements_in_trait( ); let parent = FctParent::Trait(trait_id); - let params = parse_function_params(sa, method_node, parent.clone(), &modifiers); + let params = + parse_function_params(sa, file_id, method_node, parent.clone(), &modifiers); let fct = FctDefinition::new( trait_.package_id, @@ -1081,7 +1082,8 @@ fn find_elements_in_impl( ); let parent = FctParent::Impl(impl_id); - let params = parse_function_params(sa, method_node, parent.clone(), &modifiers); + let params = + parse_function_params(sa, file_id, method_node, parent.clone(), &modifiers); let fct = FctDefinition::new( impl_.package_id, @@ -1180,6 +1182,7 @@ fn find_elements_in_impl( fn find_elements_in_extension( sa: &mut Sema, + file_id: SourceFileId, extension_id: ExtensionDefinitionId, node: &Arc, ) { @@ -1213,7 +1216,8 @@ fn find_elements_in_extension( ); let parent = FctParent::Extension(extension_id); - let params = parse_function_params(sa, method_node, parent.clone(), &modifiers); + let params = + parse_function_params(sa, file_id, method_node, parent.clone(), &modifiers); let fct = FctDefinition::new( extension.package_id, @@ -1529,16 +1533,19 @@ fn parse_type_param_definition( } fn parse_function_params( - _sa: &Sema, + sa: &Sema, + file_id: SourceFileId, ast: &ast::Function, parent: FctParent, modifiers: &ParsedModifierList, -) -> Vec { +) -> Params { let mut params: Vec = Vec::new(); + let mut has_self = false; match parent { FctParent::Impl(..) | FctParent::Extension(..) | FctParent::Trait(..) => { if !modifiers.is_static { + has_self = true; params.push(Param::new_ty(SourceType::This)); } } @@ -1548,12 +1555,26 @@ fn parse_function_params( FctParent::Function => unreachable!(), } - for p in &ast.params { - let param = Param::new(p.clone()); + let mut is_variadic = false; + + for (idx, ast_param) in ast.params.iter().enumerate() { + if ast_param.variadic { + if idx + 1 == ast.params.len() { + is_variadic = true; + } else { + sa.report( + file_id, + ast_param.span, + ErrorMessage::VariadicParameterNeedsToBeLast, + ); + } + } + + let param = Param::new(ast_param.clone()); params.push(param); } - params + Params::new(params, has_self, is_variadic) } #[cfg(test)] diff --git a/dora-frontend/src/sema.rs b/dora-frontend/src/sema.rs index a224b4403..b3194800d 100644 --- a/dora-frontend/src/sema.rs +++ b/dora-frontend/src/sema.rs @@ -25,7 +25,7 @@ pub use self::elements::{ pub use self::enums::{EnumDefinition, EnumDefinitionId, EnumField, EnumVariant}; pub use self::extensions::{ExtensionDefinition, ExtensionDefinitionId}; pub use self::functions::{ - emit_as_bytecode_operation, FctDefinition, FctDefinitionId, FctParent, Intrinsic, Param, + emit_as_bytecode_operation, FctDefinition, FctDefinitionId, FctParent, Intrinsic, Param, Params, }; pub use self::globals::{GlobalDefinition, GlobalDefinitionId}; pub use self::impl_matching::{find_impl, impl_matches, implements_trait, maybe_alias_ty}; diff --git a/dora-frontend/src/sema/functions.rs b/dora-frontend/src/sema/functions.rs index 3545d9363..b3446f4a1 100644 --- a/dora-frontend/src/sema/functions.rs +++ b/dora-frontend/src/sema/functions.rs @@ -1,4 +1,4 @@ -use std::cell::{Cell, OnceCell}; +use std::cell::OnceCell; use std::rc::Rc; use std::sync::Arc; @@ -37,9 +37,8 @@ pub struct FctDefinition { pub is_internal: bool, pub is_force_inline: bool, pub is_never_inline: bool, - pub params: Vec, + pub params: Params, pub return_type: ParsedType, - pub is_variadic: Cell, pub analysis: OnceCell, @@ -58,7 +57,7 @@ impl FctDefinition { modifiers: ParsedModifierList, name: Name, type_params: Rc, - params: Vec, + params: Params, parent: FctParent, ) -> FctDefinition { let return_type = if let Some(ref ast_return_type) = ast.return_type { @@ -86,7 +85,6 @@ impl FctDefinition { is_internal: modifiers.is_internal, is_force_inline: modifiers.is_force_inline, is_never_inline: modifiers.is_never_inline, - is_variadic: Cell::new(false), analysis: OnceCell::new(), type_param_definition: type_params, container_type_params: OnceCell::new(), @@ -181,10 +179,6 @@ impl FctDefinition { self.ast.kind.is_lambda() } - pub fn is_variadic(&self) -> bool { - self.is_variadic.get() - } - pub fn span(&self) -> Span { self.span } @@ -202,7 +196,7 @@ impl FctDefinition { } pub fn params_with_self(&self) -> &[Param] { - &self.params + &self.params.params } pub fn params_without_self(&self) -> &[Param] { @@ -215,7 +209,7 @@ impl FctDefinition { pub fn self_param(&self) -> Option<&Param> { if self.has_hidden_self_argument() { - Some(&self.params[0]) + Some(&self.params.params[0]) } else { None } @@ -349,6 +343,42 @@ impl FctParent { } } +#[derive(Debug, Clone)] +pub struct Params { + pub params: Vec, + pub has_self: bool, + pub is_variadic: bool, +} + +impl Params { + pub fn new(params: Vec, has_self: bool, is_variadic: bool) -> Params { + Params { + params, + has_self, + is_variadic, + } + } + + pub fn regular_params(&self) -> &[Param] { + let start = self.has_self as usize; + let end = self.params.len() - self.is_variadic as usize; + + &self.params[start..end] + } + + pub fn variadic_param(&self) -> Option<&Param> { + if self.is_variadic() { + Some(self.params.last().expect("missing param")) + } else { + None + } + } + + pub fn is_variadic(&self) -> bool { + self.is_variadic + } +} + #[derive(Debug, Clone)] pub struct Param { pub ast: Option>, diff --git a/dora-frontend/src/typeck.rs b/dora-frontend/src/typeck.rs index eda0d5c95..e7acf28a7 100644 --- a/dora-frontend/src/typeck.rs +++ b/dora-frontend/src/typeck.rs @@ -7,7 +7,7 @@ use crate::sema::{ LazyLambdaCreationData, Sema, TypeParamDefinition, }; use crate::sym::ModuleSymTable; -use crate::typeck::call::{check_expr_call, find_method}; +use crate::typeck::call::{check_expr_call, create_call_arguments, find_method}; use crate::typeck::constck::ConstCheck; pub use crate::typeck::control::is_pattern_check; use crate::typeck::control::{ @@ -17,8 +17,9 @@ use crate::typeck::control::{ use crate::typeck::expr::{check_expr, read_ident, read_path, read_path_expr}; pub use crate::typeck::expr::{compute_lit_float, compute_lit_int}; use crate::typeck::function::{ - add_local, args_compatible, args_compatible_fct, check_lit_char, check_lit_float, - check_lit_int, check_lit_str, is_simple_enum, TypeCheck, VarManager, + add_local, arg_allows, args_compatible, args_compatible_fct, check_args_compatible, + check_args_compatible_fct, check_lit_char, check_lit_float, check_lit_int, check_lit_str, + is_simple_enum, TypeCheck, VarManager, }; pub use crate::typeck::lookup::find_method_call_candidates; use crate::typeck::lookup::MethodLookup; @@ -203,18 +204,10 @@ impl CallArguments { } } - self.positional_types(ck) - } - - fn positional_types(&self, ck: &TypeCheck) -> Vec { self.arguments .iter() .filter(|a| a.name.is_none()) .map(|p| ck.analysis.ty(p.id)) .collect::>() } - - fn len(&self) -> usize { - self.arguments.len() - } } diff --git a/dora-frontend/src/typeck/call.rs b/dora-frontend/src/typeck/call.rs index 23c5ceb03..8920fd9ea 100644 --- a/dora-frontend/src/typeck/call.rs +++ b/dora-frontend/src/typeck/call.rs @@ -17,8 +17,8 @@ use crate::sema::{ use crate::specialize::replace_type; use crate::sym::SymbolKind; use crate::typeck::{ - args_compatible, args_compatible_fct, check_expr, find_method_call_candidates, read_path_expr, - CallArguments, MethodLookup, TypeCheck, + args_compatible, args_compatible_fct, check_args_compatible_fct, check_expr, + find_method_call_candidates, read_path_expr, CallArguments, MethodLookup, TypeCheck, }; use crate::typeparamck::{self, ErrorReporting}; use crate::{ @@ -77,7 +77,7 @@ pub(super) fn check_expr_call( } } -fn create_call_arguments(ck: &mut TypeCheck, e: &ast::ExprCallType) -> CallArguments { +pub(super) fn create_call_arguments(ck: &mut TypeCheck, e: &ast::ExprCallType) -> CallArguments { let mut arguments = CallArguments { arguments: Vec::with_capacity(e.args.len()), span: e.span, @@ -218,9 +218,7 @@ fn check_expr_call_expr( let method = ck.sa.fct(method_id); - if !args_compatible_fct(ck.sa, method, &arg_types, &SourceTypeArray::empty(), None) { - unimplemented!() - } + check_args_compatible_fct(ck, method, arguments, &SourceTypeArray::empty(), None); let return_type = method.return_type(); ck.analysis.set_ty(e.id, return_type.clone()); @@ -245,6 +243,13 @@ fn check_expr_call_expr( descriptor.return_type } else { + let ty = ck.ty_name(&expr_type); + ck.sa.report( + ck.file_id, + e.callee.span(), + ErrorMessage::IndexGetNotImplemented(ty), + ); + ck.analysis.set_ty(e.id, ty_error()); ty_error() diff --git a/dora-frontend/src/typeck/expr.rs b/dora-frontend/src/typeck/expr.rs index 54da78d5f..b7bd67a46 100644 --- a/dora-frontend/src/typeck/expr.rs +++ b/dora-frontend/src/typeck/expr.rs @@ -12,15 +12,15 @@ use crate::program_parser::ParsedModifierList; use crate::sema::{ create_tuple, find_field_in_class, find_impl, implements_trait, AnalysisData, CallType, ConstValue, EnumDefinitionId, FctDefinition, FctParent, IdentType, Intrinsic, - LazyLambdaCreationData, LazyLambdaId, ModuleDefinitionId, NestedVarId, Param, Sema, + LazyLambdaCreationData, LazyLambdaId, ModuleDefinitionId, NestedVarId, Param, Params, Sema, SourceFileId, TraitDefinitionId, }; use crate::ty::TraitType; use crate::typeck::{ - check_expr_break_and_continue, check_expr_call, check_expr_for, check_expr_if, - check_expr_match, check_expr_return, check_expr_while, check_lit_char, check_lit_float, - check_lit_int, check_lit_str, check_pattern, check_stmt, find_method, is_simple_enum, - TypeCheck, + arg_allows, check_args_compatible, check_expr_break_and_continue, check_expr_call, + check_expr_for, check_expr_if, check_expr_match, check_expr_return, check_expr_while, + check_lit_char, check_lit_float, check_lit_int, check_lit_str, check_pattern, check_stmt, + create_call_arguments, find_method, is_simple_enum, TypeCheck, }; use crate::typeparamck::{self, ErrorReporting}; use crate::{replace_type, ty::error as ty_error, SourceType, SourceTypeArray, SymbolKind}; @@ -274,16 +274,15 @@ fn check_expr_assign_call(ck: &mut TypeCheck, e: &ast::ExprBinType) { let call = e.lhs.to_call().unwrap(); let expr_type = check_expr(ck, &call.callee, SourceType::Any); - let mut arg_types: Vec = call - .args - .iter() - .map(|arg| check_expr(ck, &arg.expr, SourceType::Any)) - .collect(); + let args = create_call_arguments(ck, call); let value_type = check_expr(ck, &e.rhs, SourceType::Any); + ck.analysis.set_ty(e.rhs.id(), value_type.clone()); let name = ck.sa.interner.intern("set"); - arg_types.push(value_type); + + let mut arg_types = args.assume_all_positional(ck); + arg_types.push(value_type.clone()); let trait_id = ck.sa.known.traits.index_set(); let trait_ty = TraitType::from_trait_id(trait_id); @@ -301,16 +300,40 @@ fn check_expr_assign_call(ck: &mut TypeCheck, e: &ast::ExprBinType) { let trait_method_id = trait_ .get_method(trait_method_name, false) .expect("missing method"); + let item_name = ck.sa.interner.intern("Item"); + let trait_item_type_alias_id = trait_.alias_names().get(&item_name).expect("missing Item"); let method_id = ck .sa .impl_(impl_match.id) .get_method_for_trait_method_id(trait_method_id) .expect("method not found"); + let impl_ = ck.sa.impl_(impl_match.id); + let impl_item_type_alias_id = impl_ + .trait_alias_map() + .get(&trait_item_type_alias_id) + .cloned() + .expect("missing alias"); + let impl_item_type_alias = ck.sa.alias(impl_item_type_alias_id); + let call_type = CallType::Method(expr_type.clone(), method_id, SourceTypeArray::empty()); ck.analysis .map_calls .insert_or_replace(e.id, Arc::new(call_type)); + + let method = ck.sa.fct(method_id); + let index_param = &method.params.params[1..2]; + check_args_compatible(ck, index_param, None, args, &SourceTypeArray::empty(), None); + + if !arg_allows(ck.sa, impl_item_type_alias.ty(), value_type.clone(), None) { + let exp = ck.ty_name(&impl_item_type_alias.ty()); + let got = ck.ty_name(&value_type); + ck.sa.report( + ck.file_id, + e.rhs.span(), + ErrorMessage::WrongTypeForArgument(exp, got), + ); + } } else if let Some(descriptor) = find_method( ck, e.span, @@ -324,6 +347,13 @@ fn check_expr_assign_call(ck: &mut TypeCheck, e: &ast::ExprBinType) { ck.analysis .map_calls .insert_or_replace(e.id, Arc::new(call_type)); + } else { + let ty = ck.ty_name(&expr_type); + ck.sa.report( + ck.file_id, + call.callee.span(), + ErrorMessage::IndexSetNotImplemented(ty), + ); } } @@ -1555,7 +1585,7 @@ fn check_expr_lambda( ParsedModifierList::default(), name, ck.type_param_definition.clone(), - lambda_params, + Params::new(lambda_params, true, false), FctParent::Function, ); lambda.parsed_return_type().set_ty(lambda_return_type); diff --git a/dora-frontend/src/typeck/function.rs b/dora-frontend/src/typeck/function.rs index 4b8991176..9357ce18b 100644 --- a/dora-frontend/src/typeck/function.rs +++ b/dora-frontend/src/typeck/function.rs @@ -433,7 +433,7 @@ pub(super) fn args_compatible_fct( self_ty: Option, ) -> bool { let arg_types = callee.params_without_self(); - let variadic_arguments = callee.is_variadic.get(); + let variadic_arguments = callee.params.is_variadic(); args_compatible( sa, &arg_types.iter().map(|p| p.ty()).collect::>(), @@ -444,24 +444,97 @@ pub(super) fn args_compatible_fct( ) } -#[allow(unused)] -pub(super) fn args_compatible_fct2( +pub(super) fn check_args_compatible_fct( ck: &TypeCheck, callee: &FctDefinition, args: CallArguments, type_params: &SourceTypeArray, self_ty: Option, -) -> bool { - let arg_types = callee.params_without_self(); - let variadic_arguments = callee.is_variadic.get(); - args_compatible2( +) { + check_args_compatible( ck, - arg_types, - variadic_arguments, - &args, + callee.params.regular_params(), + callee.params.variadic_param(), + args, type_params, self_ty, - ) + ); +} + +pub(super) fn check_args_compatible( + ck: &TypeCheck, + regular_params: &[Param], + variadic_param: Option<&Param>, + args: CallArguments, + type_params: &SourceTypeArray, + self_ty: Option, +) { + for arg in &args.arguments { + if let Some(ref name) = arg.name { + ck.sa + .report(ck.file_id, name.span, ErrorMessage::UnexpectedNamedArgument); + } + } + + for (param, arg) in regular_params.iter().zip(&args.arguments) { + let param_ty = replace_type( + ck.sa, + param.ty().clone(), + Some(&type_params), + self_ty.clone(), + ); + let arg_ty = ck.analysis.ty(arg.id); + + if !arg_allows(ck.sa, param_ty.clone(), arg_ty.clone(), self_ty.clone()) { + let exp = ck.ty_name(¶m_ty); + let got = ck.ty_name(&arg_ty); + + ck.sa.report( + ck.file_id, + arg.expr.span(), + ErrorMessage::WrongTypeForArgument(exp, got), + ); + } + } + + let no_regular_params = regular_params.len(); + + if args.arguments.len() < no_regular_params { + ck.sa.report( + ck.file_id, + args.span, + ErrorMessage::MissingArguments(no_regular_params, args.arguments.len()), + ); + } else { + if let Some(variadic_param) = variadic_param { + let variadic_ty = replace_type( + ck.sa, + variadic_param.ty(), + Some(&type_params), + self_ty.clone(), + ); + + for arg in &args.arguments[no_regular_params..] { + let arg_ty = ck.analysis.ty(arg.id); + + if !arg_allows(ck.sa, variadic_ty.clone(), arg_ty.clone(), self_ty.clone()) { + let exp = ck.ty_name(&variadic_ty); + let got = ck.ty_name(&arg_ty); + + ck.sa.report( + ck.file_id, + arg.expr.span(), + ErrorMessage::WrongTypeForArgument(exp, got), + ); + } + } + } else { + for arg in &args.arguments[no_regular_params..] { + ck.sa + .report(ck.file_id, arg.span, ErrorMessage::SuperfluousArgument); + } + } + } } pub(super) fn args_compatible( @@ -513,67 +586,12 @@ pub(super) fn args_compatible( true } -pub(super) fn args_compatible2( - ck: &TypeCheck, - fct_params: &[Param], - is_variadic: bool, - args: &CallArguments, - type_params: &SourceTypeArray, +pub(super) fn arg_allows( + sa: &Sema, + def: SourceType, + arg: SourceType, self_ty: Option, ) -> bool { - let right_number_of_arguments = if is_variadic { - fct_params.len() - 1 <= args.len() - } else { - fct_params.len() == args.len() - }; - - if !right_number_of_arguments { - return false; - } - - let (fixed_params, variadic_param): (&[Param], Option<&Param>) = if is_variadic { - (&fct_params[0..fct_params.len() - 1], fct_params.last()) - } else { - (&fct_params, None) - }; - - for (ind, param) in fixed_params.iter().enumerate() { - let param_ty = replace_type( - ck.sa, - param.ty().clone(), - Some(&type_params), - self_ty.clone(), - ); - let arg = &args.arguments[ind]; - let arg_ty = ck.analysis.ty(arg.id); - - if !arg_allows(ck.sa, param_ty, arg_ty, self_ty.clone()) { - return false; - } - } - - if let Some(variadic_param) = variadic_param { - let ind = fixed_params.len(); - let variadic_ty = replace_type( - ck.sa, - variadic_param.ty(), - Some(&type_params), - self_ty.clone(), - ); - - for arg in &args.arguments[ind..] { - let arg_ty = ck.analysis.ty(arg.id); - - if !arg_allows(ck.sa, variadic_ty.clone(), arg_ty, self_ty.clone()) { - return false; - } - } - } - - true -} - -fn arg_allows(sa: &Sema, def: SourceType, arg: SourceType, self_ty: Option) -> bool { match def { SourceType::Error => true, SourceType::Any => unreachable!(), diff --git a/dora-frontend/src/typeck/lookup.rs b/dora-frontend/src/typeck/lookup.rs index b808f28a6..9d89249db 100644 --- a/dora-frontend/src/typeck/lookup.rs +++ b/dora-frontend/src/typeck/lookup.rs @@ -5,6 +5,7 @@ use crate::sema::{ TraitDefinition, TypeParamDefinition, }; use crate::typeck::function::args_compatible_fct; +use crate::typeck::CallArguments; use crate::typeparamck::{self, ErrorReporting}; use crate::{specialize_for_element, ty, SourceType, SourceTypeArray}; use dora_parser::Span; @@ -64,6 +65,7 @@ pub struct MethodLookup<'a> { kind: Option, name: Option, args: Option<&'a [SourceType]>, + args2: Option<&'a CallArguments>, fct_tps: Option<&'a SourceTypeArray>, type_param_defs: &'a TypeParamDefinition, ret: Option, @@ -84,6 +86,7 @@ impl<'a> MethodLookup<'a> { kind: None, name: None, args: None, + args2: None, fct_tps: None, ret: None, fct_parent: None, @@ -124,6 +127,12 @@ impl<'a> MethodLookup<'a> { self } + #[allow(unused)] + pub fn arguments(mut self, arguments: &'a CallArguments) -> MethodLookup<'a> { + self.args2 = Some(arguments); + self + } + pub fn span(mut self, span: Span) -> MethodLookup<'a> { self.span = Some(span); self @@ -210,27 +219,31 @@ impl<'a> MethodLookup<'a> { return result; } - let args = self.args.expect("args not set"); + if let Some(args) = self.args { + if args.contains(&ty::error()) { + return result; + } - if args.contains(&ty::error()) { - return result; - } + if !args_compatible_fct(self.sa, &*fct, args, &type_params, None) { + if !self.report_errors { + return result; + } - if !args_compatible_fct(self.sa, &*fct, args, &type_params, None) { - if !self.report_errors { + let fct_name = self.sa.interner.str(fct.name).to_string(); + let fct_params = fct + .params_without_self() + .iter() + .map(|a| a.ty().name_fct(self.sa, &*fct)) + .collect::>(); + let call_types = args.iter().map(|a| self.ty_name(a)).collect::>(); + let msg = ErrorMessage::ParamTypesIncompatible(fct_name, fct_params, call_types); + self.report_error(msg); return result; } - - let fct_name = self.sa.interner.str(fct.name).to_string(); - let fct_params = fct - .params_without_self() - .iter() - .map(|a| a.ty().name_fct(self.sa, &*fct)) - .collect::>(); - let call_types = args.iter().map(|a| self.ty_name(a)).collect::>(); - let msg = ErrorMessage::ParamTypesIncompatible(fct_name, fct_params, call_types); - self.report_error(msg); - return result; + } else if let Some(_arguments) = self.args2 { + unimplemented!() + } else { + unreachable!() } let cmp_type = { diff --git a/dora-frontend/src/typeck/tests.rs b/dora-frontend/src/typeck/tests.rs index 561273235..c81db5761 100644 --- a/dora-frontend/src/typeck/tests.rs +++ b/dora-frontend/src/typeck/tests.rs @@ -483,10 +483,18 @@ fn type_array_assign() { (1, 32), ErrorMessage::ReturnType("Int32".into(), "()".into()), ); - err( + errors( "fn f(a: Array[Int32]) { a(3) = \"b\"; }", - (1, 25), - ErrorMessage::UnknownMethod("Array[Int32]".into(), "set".into()), + &[ + ( + (1, 25), + ErrorMessage::UnknownMethod("Array[Int32]".into(), "set".into()), + ), + ( + (1, 25), + ErrorMessage::IndexSetNotImplemented("Array[Int32]".into()), + ), + ], ); } @@ -1331,19 +1339,35 @@ fn test_array_syntax_set() { #[test] fn test_array_syntax_set_wrong_value() { - err( + errors( "fn f(t: Array[Int32]) { t(0) = true; }", - (1, 25), - ErrorMessage::UnknownMethod("Array[Int32]".into(), "set".into()), + &[ + ( + (1, 25), + ErrorMessage::UnknownMethod("Array[Int32]".into(), "set".into()), + ), + ( + (1, 25), + ErrorMessage::IndexSetNotImplemented("Array[Int32]".into()), + ), + ], ); } #[test] fn test_array_syntax_set_wrong_index() { - err( + errors( "fn f(t: Array[Int32]){ t(\"bla\") = 9i32; }", - (1, 24), - ErrorMessage::UnknownMethod("Array[Int32]".into(), "set".into()), + &[ + ( + (1, 24), + ErrorMessage::UnknownMethod("Array[Int32]".into(), "set".into()), + ), + ( + (1, 24), + ErrorMessage::IndexSetNotImplemented("Array[Int32]".into()), + ), + ], ); } @@ -2549,7 +2573,7 @@ fn variadic_parameter() { ); err( "fn f(x: Int32..., y: Int32) {}", - (1, 19), + (1, 6), ErrorMessage::VariadicParameterNeedsToBeLast, ); } @@ -2681,10 +2705,18 @@ fn show_type_param_with_name() { #[test] fn shadow_function() { ok("fn f() { let f = 1i32; }"); - err( + errors( "fn f() { let f = 1i32; f(); }", - (1, 24), - ErrorMessage::UnknownMethod("Int32".into(), "get".into()), + &[ + ( + (1, 24), + ErrorMessage::UnknownMethod("Int32".into(), "get".into()), + ), + ( + (1, 24), + ErrorMessage::IndexGetNotImplemented("Int32".into()), + ), + ], ); } @@ -3450,6 +3482,10 @@ fn different_fct_call_kinds() { (1, 10), ErrorMessage::UnknownMethod("Int32".into(), "get".into()), ), + ( + (1, 10), + ErrorMessage::IndexGetNotImplemented("Int32".into()), + ), ], ); ok("enum Foo { A(Int32), B } fn f() { Foo::A(1i32); }"); @@ -5217,7 +5253,6 @@ fn struct_index_get() { } #[test] -#[ignore] fn struct_index_get_wrong_index_type() { err( " @@ -5238,8 +5273,8 @@ fn struct_index_get_wrong_index_type() { x(0.0) } ", - (1, 1), - ErrorMessage::Unimplemented, + (16, 15), + ErrorMessage::WrongTypeForArgument("Int64".into(), "Float64".into()), ); } @@ -5264,3 +5299,55 @@ fn class_index_set() { } ") } + +#[test] +fn class_index_set_wrong_type() { + err( + " + class Foo { a: Float64, b: Float64 } + impl std::traits::IndexSet for Foo { + type Index = Int; + type Item = Float64; + fn set(index: Self::Index, value: Self::Item) { + if index == 0 { + self.a = value; + } else { + assert(index == 1); + self.b = value; + } + } + } + fn f(x: Foo, value: Float64) { + x(0.0) = value; + } + ", + (16, 15), + ErrorMessage::WrongTypeForArgument("Int64".into(), "Float64".into()), + ); +} + +#[test] +fn class_index_set_wrong_item_type() { + err( + " + class Foo { a: Float64, b: Float64 } + impl std::traits::IndexSet for Foo { + type Index = Int; + type Item = Float64; + fn set(index: Self::Index, value: Self::Item) { + if index == 0 { + self.a = value; + } else { + assert(index == 1); + self.b = value; + } + } + } + fn f(x: Foo, value: Float32) { + x(0) = value; + } + ", + (16, 20), + ErrorMessage::WrongTypeForArgument("Float64".into(), "Float32".into()), + ); +} diff --git a/pkgs/std/collections.dora b/pkgs/std/collections.dora index f69174129..03fb2d272 100644 --- a/pkgs/std/collections.dora +++ b/pkgs/std/collections.dora @@ -1,4 +1,4 @@ -use std::traits::{Comparable, Hash, Equals, Default, Zero, IntoIterator, Iterator}; +use std::traits::{Comparable, Hash, Equals, Default, Zero, IndexGet, IntoIterator, Iterator}; use std::string::{Stringable, StringBuffer}; use std::{fatalError, unsafeKillRefs};