diff --git a/lib/edlang_check/src/lib.rs b/lib/edlang_check/src/lib.rs index 4a580b3db..c551dd09c 100644 --- a/lib/edlang_check/src/lib.rs +++ b/lib/edlang_check/src/lib.rs @@ -193,10 +193,44 @@ pub fn lowering_error_to_report( .with_code("ParamCountMismatch") .with_label( Label::new((path, span.into())) - .with_message(format!("function call parameter count mismatch: has {}, needs {}.", has_args, needs)) + .with_message(format!( + "function call parameter count mismatch: has {}, needs {}.", + has_args, needs + )) .with_color(colors.next()), ) .finish() - }, + } + LoweringError::NotMutable { span, file_id } => { + let path = session.file_paths[file_id].display().to_string(); + Report::build(ReportKind::Error, path.clone(), span.lo) + .with_code("NotMutable") + .with_label( + Label::new((path, span.into())) + .with_message("can't mutate this value because it's not declared mutable") + .with_color(colors.next()), + ) + .finish() + } + LoweringError::NotMutableSelf { + span, + path_span, + file_id, + } => { + let path = session.file_paths[file_id].display().to_string(); + Report::build(ReportKind::Error, path.clone(), span.lo) + .with_code("NotMutableSelf") + .with_label( + Label::new((path.clone(), path_span.into())) + .with_message("this value is not declared mutable") + .with_color(colors.next()), + ) + .with_label( + Label::new((path, span.into())) + .with_message("this method requires a mutable 'self'") + .with_color(colors.next()), + ) + .finish() + } } } diff --git a/lib/edlang_driver/tests/programs.rs b/lib/edlang_driver/tests/programs.rs index fdee2151c..0b6357a42 100644 --- a/lib/edlang_driver/tests/programs.rs +++ b/lib/edlang_driver/tests/programs.rs @@ -10,6 +10,7 @@ mod common; #[test_case(include_str!("programs/factorial.ed"), "factorial", false, 24, &[] ; "factorial")] #[test_case(include_str!("programs/refs.ed"), "refs", false, 2, &[] ; "refs")] #[test_case(include_str!("programs/struct.ed"), "struct", false, 5, &[] ; "r#struct")] +#[test_case(include_str!("programs/struct_impl.ed"), "struct_impl", false, 6, &[] ; "struct_impl")] #[test_case(include_str!("programs/casts.ed"), "casts", false, 2, &[] ; "casts")] #[test_case(TEST_ADD, "test_add", false, 2, &[] ; "test_add")] #[test_case(TEST_SUB, "test_sub", false, 1, &[] ; "test_sub")] diff --git a/lib/edlang_driver/tests/programs/refs.ed b/lib/edlang_driver/tests/programs/refs.ed index 316356071..b1852c90f 100644 --- a/lib/edlang_driver/tests/programs/refs.ed +++ b/lib/edlang_driver/tests/programs/refs.ed @@ -7,6 +7,6 @@ pub fn main() -> i64 { return a; } -pub fn hello(a: &mut i32) { +pub fn hello(a: &mut i64) { *a = 2; } diff --git a/lib/edlang_driver/tests/programs/struct_impl.ed b/lib/edlang_driver/tests/programs/struct_impl.ed new file mode 100644 index 000000000..01be68007 --- /dev/null +++ b/lib/edlang_driver/tests/programs/struct_impl.ed @@ -0,0 +1,21 @@ +extern fn printf(a: &str); + +fn main() -> u32 { + let x: A = A { + a: 2 + }; + + let y: u32 = x.hello(4); + + return y; +} + +struct A { + a: u32, +} + +impl A { + pub fn hello(self: &A, x: u32) -> u32 { + return self.a + x; + } +} diff --git a/lib/edlang_lowering/src/errors.rs b/lib/edlang_lowering/src/errors.rs index 321262788..693b7b988 100644 --- a/lib/edlang_lowering/src/errors.rs +++ b/lib/edlang_lowering/src/errors.rs @@ -70,4 +70,12 @@ pub enum LoweringError { needs: usize, file_id: usize, }, + #[error("can't mutate this value because it's not declared mutable")] + NotMutable { span: Span, file_id: usize }, + #[error("this method requires a mutable 'self'")] + NotMutableSelf { + span: Span, + path_span: Span, + file_id: usize, + }, } diff --git a/lib/edlang_lowering/src/lib.rs b/lib/edlang_lowering/src/lib.rs index 18ccc3af9..839d38dbd 100644 --- a/lib/edlang_lowering/src/lib.rs +++ b/lib/edlang_lowering/src/lib.rs @@ -1277,6 +1277,7 @@ fn lower_path( )?; let mut ty = builder.body.locals[local].ty.kind.clone(); + let mutable = builder.body.locals[local].mutable; let mut place = Place { local, projection: Default::default(), @@ -1353,26 +1354,65 @@ fn lower_path( } }; + if args_ty.len() - 1 != value.params.len() { + return Err(LoweringError::ParamCountMismatch { + span: value.span, + has_args: value.params.len(), + needs: args_ty.len(), + file_id: builder.file_id, + }); + } + let mut args = Vec::new(); - assert_eq!( - args_ty.len() - 1, - value.params.len(), - "param length mismatch" - ); - for (arg, arg_ty) in value.params.iter().zip(&args_ty[1..]) { - let (rvalue, _rvalue_ty, _span) = lower_expr(builder, arg, Some(arg_ty))?; + let (rvalue, rvalue_ty, arg_span) = lower_expr(builder, arg, Some(arg_ty))?; + + if rvalue_ty != arg_ty.kind { + return Err(LoweringError::UnexpectedType { + span: arg_span, + found: rvalue_ty, + expected: arg_ty.clone(), + file_id: builder.file_id, + }); + } + args.push(rvalue); } // insert self match &args_ty[0].kind { - TypeKind::Ptr(is_mut, _) | TypeKind::Ref(is_mut, _) => { + TypeKind::Ptr(is_mut, inner_ty) | TypeKind::Ref(is_mut, inner_ty) => { + if ty != inner_ty.kind { + return Err(LoweringError::UnexpectedType { + span: info.span, + found: inner_ty.kind.clone(), + expected: args_ty[0].clone(), + file_id: builder.file_id, + }); + } + + if !mutable && *is_mut { + return Err(LoweringError::NotMutableSelf { + span: value.span, + path_span: info.span, + file_id: builder.file_id, + }); + } + args.insert(0, RValue::Ref(*is_mut, Operand::Move(place), *span)); } - _ => { + expected_ty => { + if ty != *expected_ty { + return Err(LoweringError::UnexpectedType { + span: value.span, + found: ty.clone(), + expected: args_ty[0].clone(), + file_id: builder.file_id, + }); + } + args.insert(0, RValue::Use(Operand::Move(place), *span)); } }