add asref check

This commit is contained in:
Edgar 2024-05-07 09:11:09 +02:00
parent 9a7e510e1f
commit 7657a05ebd
No known key found for this signature in database
GPG key ID: 70ADAE8F35904387
5 changed files with 107 additions and 9 deletions

View file

@ -201,16 +201,28 @@ pub fn lowering_error_to_report(
) )
.finish() .finish()
} }
LoweringError::NotMutable { span, file_id } => { LoweringError::NotMutable {
span,
declare_span,
file_id,
} => {
let path = session.file_paths[file_id].display().to_string(); let path = session.file_paths[file_id].display().to_string();
Report::build(ReportKind::Error, path.clone(), span.lo) let mut report = Report::build(ReportKind::Error, path.clone(), span.lo)
.with_code("NotMutable") .with_code("NotMutable")
.with_label( .with_label(
Label::new((path, span.into())) Label::new((path.clone(), span.into()))
.with_message("can't mutate this value because it's not declared mutable") .with_message("can't mutate this variable because it's not mutable")
.with_color(colors.next()), .with_color(colors.next()),
) );
.finish()
if let Some(declare_span) = declare_span {
report = report.with_label(
Label::new((path, declare_span.into()))
.with_message("variable declared here")
.with_color(colors.next()),
);
}
report.finish()
} }
LoweringError::NotMutableSelf { LoweringError::NotMutableSelf {
span, span,
@ -232,5 +244,28 @@ pub fn lowering_error_to_report(
) )
.finish() .finish()
} }
LoweringError::CantTakeMutableBorrow {
span,
declare_span,
file_id,
} => {
let path = session.file_paths[file_id].display().to_string();
let mut report = Report::build(ReportKind::Error, path.clone(), span.lo)
.with_code("CantTakeMutableBorrow")
.with_label(
Label::new((path.clone(), span.into()))
.with_message("can't take a mutate borrow to this variable because it's not declared mutable")
.with_color(colors.next()),
);
if let Some(declare_span) = declare_span {
report = report.with_label(
Label::new((path, declare_span.into()))
.with_message("variable declared here")
.with_color(colors.next()),
);
}
report.finish()
}
} }
} }

View file

@ -1,6 +1,6 @@
fn main() -> i32 { fn main() -> i32 {
let foo: i32 = 7; let mut foo: i32 = 7;
if true { if true {
if false { if false {

View file

@ -178,6 +178,18 @@ impl Local {
mutable: false, mutable: false,
} }
} }
pub fn is_mutable(&self) -> bool {
if self.mutable {
return true;
}
match self.ty.kind {
TypeKind::Ptr(is_mut, _) => is_mut,
TypeKind::Ref(is_mut, _) => is_mut,
_ => false,
}
}
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
@ -424,6 +436,19 @@ pub enum RValue {
Cast(Operand, TypeInfo, Span), Cast(Operand, TypeInfo, Span),
} }
impl RValue {
pub fn get_local(&self) -> Option<usize> {
match self {
RValue::Use(op, _) => op.get_local(),
RValue::Ref(_, op, _) => op.get_local(),
RValue::BinOp(_, _, _, _) => None,
RValue::LogicOp(_, _, _, _) => None,
RValue::UnOp(_, _, _) => None,
RValue::Cast(op, _, _) => op.get_local(),
}
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Operand { pub enum Operand {
Copy(Place), Copy(Place),
@ -431,6 +456,16 @@ pub enum Operand {
Constant(ConstData), Constant(ConstData),
} }
impl Operand {
pub fn get_local(&self) -> Option<usize> {
match self {
Operand::Copy(place) => Some(place.local),
Operand::Move(place) => Some(place.local),
Operand::Constant(_) => None,
}
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Place { pub struct Place {
pub local: usize, pub local: usize,

View file

@ -71,7 +71,17 @@ pub enum LoweringError {
file_id: usize, file_id: usize,
}, },
#[error("can't mutate this value because it's not declared mutable")] #[error("can't mutate this value because it's not declared mutable")]
NotMutable { span: Span, file_id: usize }, NotMutable {
span: Span,
declare_span: Option<Span>,
file_id: usize,
},
#[error("can't take a mutable borrow to this value because it's not declared mutable")]
CantTakeMutableBorrow {
span: Span,
declare_span: Option<Span>,
file_id: usize,
},
#[error("this method requires a mutable 'self'")] #[error("this method requires a mutable 'self'")]
NotMutableSelf { NotMutableSelf {
span: Span, span: Span,

View file

@ -536,6 +536,14 @@ fn lower_assign(builder: &mut BodyBuilder, info: &ast::AssignStmt) -> Result<(),
kind: ty, kind: ty,
}; };
if !builder.body.locals[place.local].is_mutable() {
return Err(LoweringError::NotMutable {
span: info.span,
declare_span: builder.body.locals[place.local].span,
file_id: builder.file_id,
});
}
for _ in 0..info.deref_times { for _ in 0..info.deref_times {
match &path_ty.kind { match &path_ty.kind {
TypeKind::Ptr(is_mut, inner) => { TypeKind::Ptr(is_mut, inner) => {
@ -687,7 +695,7 @@ fn lower_expr(
let ty = match ty { let ty = match ty {
TypeKind::Ptr(_, inner) => *inner, TypeKind::Ptr(_, inner) => *inner,
TypeKind::Ref(_, inner) => *inner, TypeKind::Ref(_, inner) => *inner,
_ => todo!("proepr error here"), _ => todo!("proper error here"),
}; };
( (
@ -706,6 +714,16 @@ fn lower_expr(
}; };
let (mut value, ty, _span) = lower_expr(builder, inner, type_hint)?; let (mut value, ty, _span) = lower_expr(builder, inner, type_hint)?;
if let Some(local) = value.get_local() {
if *mutable && !builder.body.locals[local].mutable {
return Err(LoweringError::CantTakeMutableBorrow {
span: *as_ref_span,
declare_span: builder.body.locals[local].span,
file_id: builder.file_id,
});
}
}
// check if its a use directly, to avoid a temporary. // check if its a use directly, to avoid a temporary.
value = match value { value = match value {
RValue::Use(op, _span) => RValue::Ref(*mutable, op, *as_ref_span), RValue::Use(op, _span) => RValue::Ref(*mutable, op, *as_ref_span),