diff --git a/examples/borrow.reid b/examples/borrow.reid index 6afb9b1..a3189a3 100644 --- a/examples/borrow.reid +++ b/examples/borrow.reid @@ -12,4 +12,4 @@ fn main() -> u32 { fn mutate(value: &mut [u32; 3]) { // Dereference the borrow to mutate it *value[1] = 17; -} \ No newline at end of file +} diff --git a/reid/src/ast/mod.rs b/reid/src/ast/mod.rs index 18cc297..104c1aa 100644 --- a/reid/src/ast/mod.rs +++ b/reid/src/ast/mod.rs @@ -80,8 +80,8 @@ pub struct Expression(pub ExpressionKind, pub TokenRange); #[derive(Debug, Clone)] pub enum ExpressionKind { VariableName(String), - Borrow(String, bool), - Deref(String), + Borrow(Box, bool), + Deref(Box), Literal(Literal), Array(Vec), ArrayShort(Box, u64), diff --git a/reid/src/ast/parse.rs b/reid/src/ast/parse.rs index 27809bb..526c244 100644 --- a/reid/src/ast/parse.rs +++ b/reid/src/ast/parse.rs @@ -179,6 +179,36 @@ impl Parse for AssociatedFunctionCall { } } +fn apply_inner(expr: PrimaryExpression, fun: T) -> Expression +where + T: FnOnce(PrimaryExpression) -> Expression, +{ + match &expr.0 .0 { + ExpressionKind::Indexed(value_expr, index_expr) => Expression( + ExpressionKind::Indexed( + Box::new(apply_inner(PrimaryExpression(*value_expr.clone()), fun)), + index_expr.clone(), + ), + expr.0 .1, + ), + ExpressionKind::Accessed(value_expr, index_name) => Expression( + ExpressionKind::Accessed( + Box::new(apply_inner(PrimaryExpression(*value_expr.clone()), fun)), + index_name.clone(), + ), + expr.0 .1, + ), + ExpressionKind::AccessCall(value_expr, fn_call) => Expression( + ExpressionKind::AccessCall( + Box::new(apply_inner(PrimaryExpression(*value_expr.clone()), fun)), + fn_call.clone(), + ), + expr.0 .1, + ), + _ => fun(expr), + } +} + #[derive(Debug)] pub struct PrimaryExpression(Expression); @@ -195,18 +225,21 @@ impl Parse for PrimaryExpression { } else if let (Some(Token::Et), Some(Token::MutKeyword)) = (stream.peek(), stream.peek2()) { stream.next(); // Consume Et stream.next(); // Consume mut - let Some(Token::Identifier(name)) = stream.next() else { - return Err(stream.expected_err("identifier")?); - }; - Expression(Kind::Borrow(name, true), stream.get_range().unwrap()) - } else if let (Some(Token::Et), Some(Token::Identifier(name))) = (stream.peek(), stream.peek2()) { + Expression( + Kind::Borrow(Box::new(stream.parse()?), true), + stream.get_range().unwrap(), + ) + } else if let Some(Token::Et) = stream.peek() { stream.next(); // Consume Et - stream.next(); // Consume identifier - Expression(Kind::Borrow(name, false), stream.get_range().unwrap()) - } else if let (Some(Token::Star), Some(Token::Identifier(name))) = (stream.peek(), stream.peek2()) { + Expression( + Kind::Borrow(Box::new(stream.parse()?), false), + stream.get_range().unwrap(), + ) + } else if let Some(Token::Star) = stream.peek() { stream.next(); // Consume Et - stream.next(); // Consume identifier - Expression(Kind::Deref(name), stream.get_range().unwrap()) + apply_inner(stream.parse()?, |e| { + Expression(Kind::Deref(Box::new(e.0)), stream.get_range().unwrap()) + }) } else if let Ok(unary) = stream.parse() { Expression( Kind::UnaryOperation(unary, Box::new(stream.parse()?)), diff --git a/reid/src/ast/process.rs b/reid/src/ast/process.rs index 4ae0e87..ca0c8ff 100644 --- a/reid/src/ast/process.rs +++ b/reid/src/ast/process.rs @@ -361,19 +361,10 @@ impl ast::Expression { mir::TypeKind::Vague(mir::VagueType::Unknown), name.clone(), ), - ast::ExpressionKind::Borrow(name, mutable) => mir::ExprKind::Borrow( - NamedVariableRef( - mir::TypeKind::Vague(mir::VagueType::Unknown), - name.clone(), - self.1.as_meta(module_id), - ), - *mutable, - ), - ast::ExpressionKind::Deref(name) => mir::ExprKind::Deref(NamedVariableRef( - mir::TypeKind::Vague(mir::VagueType::Unknown), - name.clone(), - self.1.as_meta(module_id), - )), + ast::ExpressionKind::Borrow(expr, mutable) => { + mir::ExprKind::Borrow(Box::new(expr.process(module_id)), *mutable) + } + ast::ExpressionKind::Deref(expr) => mir::ExprKind::Deref(Box::new(expr.process(module_id))), ast::ExpressionKind::UnaryOperation(unary_operator, expr) => match unary_operator { ast::UnaryOperator::Plus => mir::ExprKind::BinOp( mir::BinaryOperator::Add, diff --git a/reid/src/codegen/mod.rs b/reid/src/codegen/mod.rs index 3c73953..59a61d4 100644 --- a/reid/src/codegen/mod.rs +++ b/reid/src/codegen/mod.rs @@ -1144,12 +1144,8 @@ impl mir::Expression { TypeKind::CustomType(type_key), )) } - mir::ExprKind::Borrow(varref, mutable) => { - varref.0.known().expect("variable type unknown"); - let v = scope - .stack_values - .get(&varref.1) - .expect("Variable reference not found?!"); + mir::ExprKind::Borrow(expr, mutable) => { + let v = expr.codegen(scope, &state.load(false))?.unwrap(); let TypeKind::CodegenPtr(ptr_inner) = &v.1 else { panic!(); @@ -1160,12 +1156,8 @@ impl mir::Expression { TypeKind::Borrow(Box::new(*ptr_inner.clone()), *mutable), )) } - mir::ExprKind::Deref(varref) => { - varref.0.known().expect("variable type unknown"); - let v = scope - .stack_values - .get(&varref.1) - .expect("Variable reference not found?!"); + mir::ExprKind::Deref(expr) => { + let v = expr.codegen(scope, &state.load(false))?.unwrap(); let TypeKind::CodegenPtr(ptr_inner) = &v.1 else { panic!(); @@ -1174,7 +1166,7 @@ impl mir::Expression { let var_ptr_instr = scope .block .build_named( - format!("{}.deref", varref.1), + format!("{}.deref", expr.backing_var().unwrap().1), Instr::Load(v.0.instr(), ptr_inner.get_type(scope.type_values)), ) .unwrap(); @@ -1187,7 +1179,7 @@ impl mir::Expression { scope .block .build_named( - format!("{}.deref.inner", varref.1), + format!("{}.deref.inner", expr.backing_var().unwrap().1), Instr::Load(var_ptr_instr, inner.get_type(scope.type_values)), ) .unwrap(), diff --git a/reid/src/mir/implement.rs b/reid/src/mir/implement.rs index 5cc62f5..16bef72 100644 --- a/reid/src/mir/implement.rs +++ b/reid/src/mir/implement.rs @@ -425,15 +425,15 @@ impl Expression { ReturnKind::Soft, TypeKind::CustomType(CustomTypeKey(name.clone(), mod_id)), )), - Borrow(var, mutable) => { - let ret_type = var.return_type()?; + Borrow(expr, mutable) => { + let ret_type = expr.return_type(refs, mod_id)?; Ok((ret_type.0, TypeKind::Borrow(Box::new(ret_type.1), *mutable))) } - Deref(var) => { - let (kind, ret_type) = var.return_type()?; + Deref(expr) => { + let (kind, ret_type) = expr.return_type(refs, mod_id)?; match ret_type.resolve_weak(refs) { TypeKind::Borrow(type_kind, _) => Ok((kind, *type_kind)), - _ => Err(ReturnTypeOther::DerefNonBorrow(var.2)), + _ => Err(ReturnTypeOther::DerefNonBorrow(expr.1)), } } CastTo(expr, type_kind) => match expr.return_type(refs, mod_id) { @@ -452,8 +452,8 @@ impl Expression { ExprKind::Variable(var_ref) => Some(var_ref), ExprKind::Indexed(lhs, _, _) => lhs.backing_var(), ExprKind::Accessed(lhs, _, _) => lhs.backing_var(), - ExprKind::Borrow(var, _) => Some(var), - ExprKind::Deref(var) => Some(var), + ExprKind::Borrow(expr, _) => expr.backing_var(), + ExprKind::Deref(expr) => expr.backing_var(), ExprKind::Block(block) => block.backing_var(), ExprKind::Array(_) => None, ExprKind::Struct(_, _) => None, diff --git a/reid/src/mir/linker.rs b/reid/src/mir/linker.rs index 695e319..dc844de 100644 --- a/reid/src/mir/linker.rs +++ b/reid/src/mir/linker.rs @@ -401,12 +401,8 @@ impl<'map> Pass for LinkerPass<'map> { } super::ExprKind::BinOp(.., type_kind) => *type_kind = type_kind.update_imported(extern_types, mod_id), - super::ExprKind::Borrow(var_ref, _) => { - var_ref.0 = var_ref.0.update_imported(extern_types, mod_id); - } - super::ExprKind::Deref(var_ref) => { - var_ref.0 = var_ref.0.update_imported(extern_types, mod_id); - } + super::ExprKind::Borrow(expr, _) => {} + super::ExprKind::Deref(expr) => {} super::ExprKind::CastTo(_, type_kind) => *type_kind = type_kind.update_imported(extern_types, mod_id), _ => {} } diff --git a/reid/src/mir/mod.rs b/reid/src/mir/mod.rs index 8b9c81a..8cdcb84 100644 --- a/reid/src/mir/mod.rs +++ b/reid/src/mir/mod.rs @@ -261,8 +261,8 @@ pub enum ExprKind { AssociatedFunctionCall(TypeKind, FunctionCall), If(IfExpression), Block(Block), - Borrow(NamedVariableRef, bool), - Deref(NamedVariableRef), + Borrow(Box, bool), + Deref(Box), CastTo(Box, TypeKind), } diff --git a/reid/src/mir/typecheck/mod.rs b/reid/src/mir/typecheck/mod.rs index 14607cf..b01cb10 100644 --- a/reid/src/mir/typecheck/mod.rs +++ b/reid/src/mir/typecheck/mod.rs @@ -65,7 +65,9 @@ pub enum ErrorKind { #[error("This type of expression can not be used for assignment")] InvalidSetExpression, #[error("Can not deref {0}, as it is not a borrow")] - AttemptedDerefNonBorrow(String), + AttemptedDerefNonBorrow(TypeKind), + #[error("Can not borrow this kind of expression")] + ImpossibleBorrow, #[error("Types {0} and {1} differ in mutability")] TypesDifferMutability(TypeKind, TypeKind), #[error("Cannot mutably borrow variable {0}, which is not declared as mutable")] diff --git a/reid/src/mir/typecheck/typecheck.rs b/reid/src/mir/typecheck/typecheck.rs index 1495b1a..1baa1a3 100644 --- a/reid/src/mir/typecheck/typecheck.rs +++ b/reid/src/mir/typecheck/typecheck.rs @@ -1,6 +1,6 @@ //! This module contains code relevant to doing a type checking pass on the MIR. //! During typechecking relevant types are also coerced if possible. -use std::{collections::HashSet, convert::Infallible, iter}; +use std::{collections::HashSet, convert::Infallible, hint, iter}; use crate::{mir::*, util::try_all}; use VagueType as Vague; @@ -668,60 +668,49 @@ impl Expression { Ok(TypeKind::CustomType(type_key)) } - ExprKind::Borrow(var_ref, mutable) => { - let scope_var = state.scope.variables.get(&var_ref.1).cloned(); - - let existing = state - .or_else( - scope_var - .clone() - .map(|var| var.ty) - .ok_or(ErrorKind::VariableNotDefined(var_ref.1.clone())), - TypeKind::Vague(Vague::Unknown), - var_ref.2, - ) - .resolve_ref(typerefs); - - if let Some(scope_var) = scope_var { - if !scope_var.mutable && *mutable { - return Err(ErrorKind::ImpossibleMutableBorrow(var_ref.1.clone())); + ExprKind::Borrow(expr, mutable) => { + let hint_t = if let HintKind::Coerce(hint_t) = hint_t { + if let TypeKind::Borrow(inner, _) = hint_t { + HintKind::Coerce(*inner) + } else { + return Err(ErrorKind::TypesIncompatible( + hint_t, + TypeKind::Borrow(Box::new(TypeKind::Vague(VagueType::Unknown)), *mutable), + )); } - } - - // Update typing to be more accurate - var_ref.0 = state.or_else( - var_ref.0.resolve_ref(typerefs).narrow_into(&existing), - TypeKind::Vague(Vague::Unknown), - var_ref.2, - ); - - Ok(TypeKind::Borrow(Box::new(var_ref.0.clone()), *mutable)) - } - ExprKind::Deref(var_ref) => { - let existing = state - .or_else( - state - .scope - .variables - .get(&var_ref.1) - .map(|var| &var.ty) - .cloned() - .ok_or(ErrorKind::VariableNotDefined(var_ref.1.clone())), - TypeKind::Vague(Vague::Unknown), - var_ref.2, - ) - .resolve_ref(typerefs); - - // Update typing to be more accurate - let TypeKind::Borrow(inner, mutable) = state.or_else( - var_ref.0.resolve_ref(typerefs).narrow_into(&existing), - TypeKind::Vague(Vague::Unknown), - var_ref.2, - ) else { - return Err(ErrorKind::AttemptedDerefNonBorrow(var_ref.1.clone())); + } else { + hint_t }; - var_ref.0 = TypeKind::Borrow(inner.clone(), mutable); + let expr_ty = expr.typecheck(state, typerefs, hint_t)?.resolve_ref(typerefs); + + if let Some(backing_var) = expr.backing_var() { + if let Some(scope_var) = state.scope.variables.get(&backing_var.1) { + if !scope_var.mutable && *mutable { + return Err(ErrorKind::ImpossibleMutableBorrow(backing_var.1.clone())); + } + } else { + return Err(ErrorKind::VariableNotDefined(backing_var.1.clone())); + } + } else { + return Err(ErrorKind::ImpossibleBorrow); + } + + Ok(TypeKind::Borrow(Box::new(expr_ty.clone()), *mutable)) + } + ExprKind::Deref(expr) => { + let hint_t = if let HintKind::Coerce(hint_t) = hint_t { + HintKind::Coerce(TypeKind::Borrow(Box::new(hint_t), false)) + } else { + hint_t + }; + + let expr_ty = expr.typecheck(state, typerefs, hint_t)?.resolve_ref(typerefs); + + // Update typing to be more accurate + let TypeKind::Borrow(inner, _) = expr_ty else { + return Err(ErrorKind::AttemptedDerefNonBorrow(expr_ty.clone())); + }; Ok(*inner) } diff --git a/reid/src/mir/typecheck/typeinference.rs b/reid/src/mir/typecheck/typeinference.rs index bd7712c..26b84a4 100644 --- a/reid/src/mir/typecheck/typeinference.rs +++ b/reid/src/mir/typecheck/typeinference.rs @@ -557,37 +557,23 @@ impl Expression { } Ok(type_refs.from_type(&TypeKind::CustomType(type_key.clone())).unwrap()) } - ExprKind::Borrow(var, mutable) => { + ExprKind::Borrow(expr, mutable) => { // Find variable type - let type_ref = type_refs - .find_var(&var.1) - .map(|(_, hint)| hint) - .ok_or(ErrorKind::VariableNotDefined(var.1.clone())); - - // Update MIR type to TypeRef if found - if let Ok(hint) = &type_ref { - var.0 = hint.as_type(); - } + let type_ref = expr.infer_types(state, type_refs)?; Ok(type_refs - .from_type(&TypeKind::Borrow(Box::new(var.0.clone()), *mutable)) + .from_type(&TypeKind::Borrow(Box::new(type_ref.as_type()), *mutable)) .unwrap()) } - ExprKind::Deref(var) => { + ExprKind::Deref(expr) => { // Find variable type - let type_ref = type_refs - .find_var(&var.1) - .map(|(_, hint)| hint) - .ok_or(ErrorKind::VariableNotDefined(var.1.clone())); + let type_ref = expr.infer_types(state, type_refs)?; - // Update MIR type to TypeRef if found - if let Ok(hint) = &type_ref { - var.0 = hint.as_type(); - } + // Update typing to be more accurate - match &var.0.resolve_weak(type_refs.types) { - Borrow(type_kind, _) => Ok(type_refs.from_type(&type_kind).unwrap()), - _ => Err(ErrorKind::AttemptedDerefNonBorrow(var.1.clone())), + match type_ref.resolve_weak().unwrap() { + Borrow(inner, _) => Ok(type_refs.from_type(&inner).unwrap()), + _ => Err(ErrorKind::AttemptedDerefNonBorrow(type_ref.resolve_deep().unwrap())), } } ExprKind::CastTo(expression, type_kind) => { diff --git a/reid/src/mir/typecheck/typerefs.rs b/reid/src/mir/typecheck/typerefs.rs index 3b0d695..fe91702 100644 --- a/reid/src/mir/typecheck/typerefs.rs +++ b/reid/src/mir/typecheck/typerefs.rs @@ -27,6 +27,10 @@ impl<'scope> TypeRef<'scope> { let resolved_elem_ty = self.1.from_type(&elem_ty).unwrap().resolve_weak()?; Some(TypeKind::Array(Box::new(resolved_elem_ty), len)) } + TypeKind::Borrow(inner_ty, mutable) => { + let resolved_elem_ty = self.1.from_type(&inner_ty).unwrap().resolve_weak()?; + Some(TypeKind::Borrow(Box::new(resolved_elem_ty), mutable)) + } _ => Some(resolved), } }