Skip to content

Commit

Permalink
Turn struct field privacy warnings into errors (#5569)
Browse files Browse the repository at this point in the history
## Description

Closes #5520.

As agreed with @FuelLabs/tooling, one LSP test fixture is changed to
temporarily fetch its `std` dependency from the local repository.

## Checklist

- [x] I have linked to any relevant issues.
- [x] I have commented my code, particularly in hard-to-understand
areas.
- [ ] I have updated the documentation where relevant (API docs, the
reference, and the Sway book).
- [x] I have added tests that prove my fix is effective or that my
feature works.
- [x] I have added (or requested a maintainer to add) the necessary
`Breaking*` or `New Feature` labels where relevant.
- [x] I have done my best to ensure that my PR adheres to [the Fuel Labs
Code Review
Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md).
- [x] I have requested a review from the relevant team or maintainers.
  • Loading branch information
ironcev authored and sdankel committed Feb 8, 2024
1 parent 388323b commit 3aad2f2
Show file tree
Hide file tree
Showing 14 changed files with 108 additions and 541 deletions.
27 changes: 7 additions & 20 deletions sway-core/src/language/ty/declaration/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use std::hash::{Hash, Hasher};
use sway_error::{
error::{CompileError, StructFieldUsageContext},
handler::{ErrorEmitted, Handler},
warning::{CompileWarning, Warning},
};
use sway_types::{state::StateIndex, Ident, Named, Span, Spanned};

Expand Down Expand Up @@ -135,25 +134,13 @@ impl TyStorageDecl {
match struct_decl.find_field(field) {
Some(struct_field) => {
if is_public_struct_access && struct_field.is_private() {
// TODO: Uncomment this code and delete the one with warnings once struct field privacy becomes a hard error.
// https://github.com/FuelLabs/sway/issues/5520
// return Err(handler.emit_err(CompileError::StructFieldIsPrivate {
// field_name: field.into(),
// struct_name: struct_decl.call_path.suffix.clone(),
// field_decl_span: struct_field.name.span(),
// struct_can_be_changed,
// usage_context: StructFieldUsageContext::StorageAccess,
// }));
handler.emit_warn(CompileWarning {
span: field.span(),
warning_content: Warning::StructFieldIsPrivate {
field_name: field.into(),
struct_name: struct_decl.call_path.suffix.clone(),
field_decl_span: struct_field.name.span(),
struct_can_be_changed,
usage_context: StructFieldUsageContext::StorageAccess,
},
});
return Err(handler.emit_err(CompileError::StructFieldIsPrivate {
field_name: field.into(),
struct_name: struct_decl.call_path.suffix.clone(),
field_decl_span: struct_field.name.span(),
struct_can_be_changed,
usage_context: StructFieldUsageContext::StorageAccess,
}));
}

// Everything is fine. Push the storage access descriptor and move to the next field.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use itertools::Itertools;
use sway_error::{
error::{CompileError, StructFieldUsageContext},
handler::{ErrorEmitted, Handler},
warning::{CompileWarning, Warning},
};
use sway_types::{BaseIdent, Ident, Span, Spanned};

Expand Down Expand Up @@ -308,25 +307,13 @@ fn type_check_struct(
.expect("The struct field with the given field name must exist.");

if struct_field.is_private() {
// TODO: Uncomment this code and delete the one with warnings once struct field privacy becomes a hard error.
// https://github.com/FuelLabs/sway/issues/5520
// handler.emit_err(CompileError::StructFieldIsPrivate {
// field_name: field_name.into(),
// struct_name: struct_decl.call_path.suffix.clone(),
// field_decl_span: struct_field.name.span(),
// struct_can_be_changed,
// usage_context: StructFieldUsageContext::PatternMatching { has_rest_pattern },
// });
handler.emit_warn(CompileWarning {
span: field_name.span(),
warning_content: Warning::StructFieldIsPrivate {
field_name: field_name.into(),
struct_name: struct_decl.call_path.suffix.clone(),
field_decl_span: struct_field.name.span(),
struct_can_be_changed,
usage_context: StructFieldUsageContext::PatternMatching {
has_rest_pattern,
},
handler.emit_err(CompileError::StructFieldIsPrivate {
field_name: field_name.into(),
struct_name: struct_decl.call_path.suffix.clone(),
field_decl_span: struct_field.name.span(),
struct_can_be_changed,
usage_context: StructFieldUsageContext::PatternMatching {
has_rest_pattern,
},
});
}
Expand Down Expand Up @@ -377,83 +364,48 @@ fn type_check_struct(
.collect_vec()
};

// TODO: Uncomment this code and delete the one with warnings once struct field privacy becomes a hard error.
// https://github.com/FuelLabs/sway/issues/5520
// handler.emit_err(
// match (is_public_struct_access, all_public_fields_are_matched, only_public_fields_are_matched) {
// // Public access. Only all public fields are matched. All missing fields are private.
// // -> Emit error for the mandatory ignore `..`.
// (true, true, true) => CompileError::MatchStructPatternMustIgnorePrivateFields {
// private_fields: missing_fields(false),
// struct_name: struct_decl.call_path.suffix.clone(),
// struct_decl_span: struct_decl.span(),
// all_fields_are_private: struct_decl.has_only_private_fields(),
// span: span.clone(),
// },

// // Public access. All public fields are matched. Some private fields are matched.
// // -> Do not emit error here because it is already covered when reporting private field.
// (true, true, false) => unreachable!("The above if condition eliminates this case."),

// // Public access. Some or non of the public fields are matched. Some or none of the private fields are matched.
// // -> Emit error listing only missing public fields. Recommendation for mandatory use of `..` is already given
// // when reporting the inaccessible private field.
// // or
// // In struct decl module access. We do not distinguish between private and public fields here.
// // -> Emit error listing all missing fields.
// (true, false, _) | (false, _, _) => CompileError::MatchStructPatternMissingFields {
// missing_fields: missing_fields(is_public_struct_access),
// missing_fields_are_public: is_public_struct_access,
// struct_name: struct_decl.call_path.suffix.clone(),
// struct_decl_span: struct_decl.span(),
// total_number_of_fields: struct_decl.fields.len(),
// span: span.clone(),
// },
// });

match (
is_public_struct_access,
all_public_fields_are_matched,
only_public_fields_are_matched,
) {
// Public access. Only all public fields are matched. All missing fields are private.
// -> Emit error for the mandatory ignore `..`.
(true, true, true) => {
handler.emit_warn(CompileWarning {
span: span.clone(),
warning_content: Warning::MatchStructPatternMustIgnorePrivateFields {
handler.emit_err(
match (
is_public_struct_access,
all_public_fields_are_matched,
only_public_fields_are_matched,
) {
// Public access. Only all public fields are matched. All missing fields are private.
// -> Emit error for the mandatory ignore `..`.
(true, true, true) => {
CompileError::MatchStructPatternMustIgnorePrivateFields {
private_fields: missing_fields(false),
struct_name: struct_decl.call_path.suffix.clone(),
struct_decl_span: struct_decl.span(),
all_fields_are_private: struct_decl.has_only_private_fields(),
span: span.clone(),
},
});
}
}
}

// Public access. All public fields are matched. Some private fields are matched.
// -> Do not emit error here because it is already covered when reporting private field.
(true, true, false) => {
unreachable!("The above if condition eliminates this case.")
}
// Public access. All public fields are matched. Some private fields are matched.
// -> Do not emit error here because it is already covered when reporting private field.
(true, true, false) => {
unreachable!("The above if condition eliminates this case.")
}

// Public access. Some or non of the public fields are matched. Some or none of the private fields are matched.
// -> Emit error listing only missing public fields. Recommendation for mandatory use of `..` is already given
// when reporting the inaccessible private field.
// or
// In struct decl module access. We do not distinguish between private and public fields here.
// -> Emit error listing all missing fields.
(true, false, _) | (false, _, _) => {
handler.emit_err(CompileError::MatchStructPatternMissingFields {
missing_fields: missing_fields(is_public_struct_access),
missing_fields_are_public: is_public_struct_access,
struct_name: struct_decl.call_path.suffix.clone(),
struct_decl_span: struct_decl.span(),
total_number_of_fields: struct_decl.fields.len(),
span: span.clone(),
});
}
};
// Public access. Some or non of the public fields are matched. Some or none of the private fields are matched.
// -> Emit error listing only missing public fields. Recommendation for mandatory use of `..` is already given
// when reporting the inaccessible private field.
// or
// In struct decl module access. We do not distinguish between private and public fields here.
// -> Emit error listing all missing fields.
(true, false, _) | (false, _, _) => {
CompileError::MatchStructPatternMissingFields {
missing_fields: missing_fields(is_public_struct_access),
missing_fields_are_public: is_public_struct_access,
struct_name: struct_decl.call_path.suffix.clone(),
struct_decl_span: struct_decl.span(),
total_number_of_fields: struct_decl.fields.len(),
span: span.clone(),
}
}
},
);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use sway_error::{
error::{CompileError, StructFieldUsageContext},
handler::{ErrorEmitted, Handler},
warning::{CompileWarning, Warning},
};
use sway_types::{Ident, Span, Spanned};

Expand Down Expand Up @@ -69,25 +68,13 @@ pub(crate) fn instantiate_struct_field_access(
let field = match decl.find_field(&field_to_access) {
Some(field) => {
if is_public_struct_access && field.is_private() {
// TODO: Uncomment this code and delete the one with warnings once struct field privacy becomes a hard error.
// https://github.com/FuelLabs/sway/issues/5520
// return Err(handler.emit_err(CompileError::StructFieldIsPrivate {
// field_name: (&field_to_access).into(),
// struct_name: decl.call_path.suffix.clone(),
// field_decl_span: field.name.span(),
// struct_can_be_changed,
// usage_context: StructFieldUsageContext::StructFieldAccess,
// }));
handler.emit_warn(CompileWarning {
span: field_to_access.span(),
warning_content: Warning::StructFieldIsPrivate {
field_name: (&field_to_access).into(),
struct_name: decl.call_path.suffix.clone(),
field_decl_span: field.name.span(),
struct_can_be_changed,
usage_context: StructFieldUsageContext::StructFieldAccess,
},
});
return Err(handler.emit_err(CompileError::StructFieldIsPrivate {
field_name: (&field_to_access).into(),
struct_name: decl.call_path.suffix.clone(),
field_decl_span: field.name.span(),
struct_can_be_changed,
usage_context: StructFieldUsageContext::StructFieldAccess,
}));
}

field.clone()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use itertools::Itertools;
use sway_error::{
error::{CompileError, StructFieldUsageContext},
handler::{ErrorEmitted, Handler},
warning::{CompileWarning, Warning},
};
use sway_types::{Ident, Span, Spanned};

Expand Down Expand Up @@ -135,34 +134,19 @@ pub(crate) fn struct_instantiation(
ctx.storage_declaration(),
);

// TODO: Uncomment this code and delete the one with warnings once struct field privacy becomes a hard error.
// https://github.com/FuelLabs/sway/issues/5520
// handler.emit_err(CompileError::StructCannotBeInstantiated {
// struct_name: struct_name.clone(),
// span: inner_span.clone(),
// struct_decl_span: struct_decl.span.clone(),
// private_fields: struct_fields.iter().filter(|field| field.is_private()).map(|field| field.name.clone()).collect(),
// constructors,
// all_fields_are_private,
// is_in_storage_declaration: ctx.storage_declaration(),
// struct_can_be_changed,
// });
handler.emit_warn(CompileWarning {
handler.emit_err(CompileError::StructCannotBeInstantiated {
struct_name: struct_name.clone(),
span: inner_span.clone(),
warning_content: Warning::StructCannotBeInstantiated {
struct_name: struct_name.clone(),
span: inner_span.clone(),
struct_decl_span: struct_decl.span.clone(),
private_fields: struct_fields
.iter()
.filter(|field| field.is_private())
.map(|field| field.name.clone())
.collect(),
constructors,
all_fields_are_private,
is_in_storage_declaration: ctx.storage_declaration(),
struct_can_be_changed,
},
struct_decl_span: struct_decl.span.clone(),
private_fields: struct_fields
.iter()
.filter(|field| field.is_private())
.map(|field| field.name.clone())
.collect(),
constructors,
all_fields_are_private,
is_in_storage_declaration: ctx.storage_declaration(),
struct_can_be_changed,
});
}

Expand Down Expand Up @@ -212,35 +196,19 @@ pub(crate) fn struct_instantiation(
for field in fields {
if let Some(ty_field) = struct_fields.iter().find(|x| x.name == field.name) {
if ty_field.is_private() {
// TODO: Uncomment this code and delete the one with warnings once struct field privacy becomes a hard error.
// https://github.com/FuelLabs/sway/issues/5520
// handler.emit_err(CompileError::StructFieldIsPrivate {
// field_name: (&field.name).into(),
// struct_name: struct_name.clone(),
// field_decl_span: ty_field.name.span(),
// struct_can_be_changed,
// usage_context: if ctx.storage_declaration() {
// StructFieldUsageContext::StorageDeclaration { struct_can_be_instantiated }
// } else {
// StructFieldUsageContext::StructInstantiation { struct_can_be_instantiated }
// }
// });
handler.emit_warn(CompileWarning {
span: field.name.span(),
warning_content: Warning::StructFieldIsPrivate {
field_name: (&field.name).into(),
struct_name: struct_name.clone(),
field_decl_span: ty_field.name.span(),
struct_can_be_changed,
usage_context: if ctx.storage_declaration() {
StructFieldUsageContext::StorageDeclaration {
struct_can_be_instantiated,
}
} else {
StructFieldUsageContext::StructInstantiation {
struct_can_be_instantiated,
}
},
handler.emit_err(CompileError::StructFieldIsPrivate {
field_name: (&field.name).into(),
struct_name: struct_name.clone(),
field_decl_span: ty_field.name.span(),
struct_can_be_changed,
usage_context: if ctx.storage_declaration() {
StructFieldUsageContext::StorageDeclaration {
struct_can_be_instantiated,
}
} else {
StructFieldUsageContext::StructInstantiation {
struct_can_be_instantiated,
}
},
});
}
Expand Down
Loading

0 comments on commit 3aad2f2

Please sign in to comment.