Skip to content

Commit

Permalink
Implement mutability checks for references to aggregate type fields.
Browse files Browse the repository at this point in the history
Fixes #6368.
  • Loading branch information
tritao committed Aug 14, 2024
1 parent 3ade41c commit 735ae71
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2326,26 +2326,14 @@ impl ty::TyExpression {
let expr = ty::TyExpression::type_check(handler, ctx, value)?;

if to_mutable_value {
match expr.expression {
ty::TyExpressionVariant::ConstantExpression { .. } => {
return Err(
handler.emit_err(CompileError::RefMutCannotReferenceConstant {
constant: expr_span.str(),
span,
}),
)
}
ty::TyExpressionVariant::VariableExpression {
name: decl_name,
mutability: VariableMutability::Immutable,
..
} => {
return Err(handler.emit_err(
CompileError::RefMutCannotReferenceImmutableVariable { decl_name, span },
))
}
// TODO-IG: Check referencing parts of aggregates once reassignment is implemented.
_ => (),
if let Some(value) = Self::check_ref_mutability_mismatch(
&expr.expression,
handler,
expr_span,
span.clone(),
engines,
) {
return value;
}
};

Expand All @@ -2366,6 +2354,57 @@ impl ty::TyExpression {
Ok(typed_expr)
}

fn check_ref_mutability_mismatch(
expr: &TyExpressionVariant,
handler: &Handler,
expr_span: Span,
ref_span: Span,
engines: &Engines,
) -> Option<Result<TyExpression, ErrorEmitted>> {
match expr {
ty::TyExpressionVariant::ConstantExpression { .. } => {
return Some(Err(handler.emit_err(
CompileError::RefMutCannotReferenceConstant {
constant: expr_span.str(),
span: ref_span,
},
)))
}
ty::TyExpressionVariant::VariableExpression {
name: decl_name,
mutability: VariableMutability::Immutable,
..
} => {
return Some(Err(handler.emit_err(
CompileError::RefMutCannotReferenceImmutableVariable {
decl_name: decl_name.clone(),
span: ref_span,
},
)))
}
ty::TyExpressionVariant::StructFieldAccess { ref prefix, .. } => {
return Self::check_ref_mutability_mismatch(
&prefix.expression,
handler,
expr_span,
ref_span,
engines,
)
}
ty::TyExpressionVariant::TupleElemAccess { ref prefix, .. } => {
return Self::check_ref_mutability_mismatch(
&prefix.expression,
handler,
expr_span,
ref_span,
engines,
)
}
_ => (),
}
None
}

fn type_check_deref(
handler: &Handler,
mut ctx: TypeCheckContext<'_>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ impl S {
const X = 0;
}

struct S2 {
s: S,
}

fn function(f_x: u8) {
let _ = &mut f_x;
}
Expand Down Expand Up @@ -73,5 +77,18 @@ fn main() {
}

function(0);

// aggregates checking

let _ = &mut s.x;

let s2 = S2 { s: S { x: 0 } };

let _ = &mut s2.s.x;

let t : (u32, u32) = (0, 0);
let _ : &mut u32 = &mut t.0;

let _ = &mut { t }; // No error here.
}

Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,24 @@ category = "fail"
#check: $()let _ = &mut n;
#nextln: $()"n" is an immutable variable. `&mut` cannot reference immutable variables.
#check: $()- referencing a mutable copy of "n", by returning it from a block: `&mut { n }`.

#check: $()References to mutable values cannot reference immutable variables
#check: $()let s = S { x: 0 };
#nextln: $()Variable "s" is declared here as immutable.
#check: $()let _ = &mut s.x;
#nextln: $()"s" is an immutable variable. `&mut` cannot reference immutable variables.
#check: $()- referencing a mutable copy of "s", by returning it from a block: `&mut { s }`.

#check: $()References to mutable values cannot reference immutable variables
#check: $()let s2 = S2 { s: S { x: 0 } };
#nextln: $()Variable "s2" is declared here as immutable.
#check: $()let _ = &mut s2.s.x;
#nextln: $()"s2" is an immutable variable. `&mut` cannot reference immutable variables.
#check: $()- referencing a mutable copy of "s2", by returning it from a block: `&mut { s2 }`.

#check: $()References to mutable values cannot reference immutable variables
#check: $()let t : (u32, u32) = (0, 0);
#nextln: $()Variable "t" is declared here as immutable.
#check: $()let _ : &mut u32 = &mut t.0;
#nextln: $()"t" is an immutable variable. `&mut` cannot reference immutable variables.
#check: $()- referencing a mutable copy of "t", by returning it from a block: `&mut { t }`.

0 comments on commit 735ae71

Please sign in to comment.