Skip to content

Commit

Permalink
deprecated attribute (#5142)
Browse files Browse the repository at this point in the history
## Description

This PR is part of #4794. It is the
minimum implementation for deprecation. Pretty much only what was needed
for deprecating `U256`.

It also minimally implements `#[allow(deprecated)]`.

## Checklist

- [x] I have linked to any relevant issues.
- [x] I have commented my code, particularly in hard-to-understand
areas.
- [x] 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
xunilrj authored Oct 3, 2023
1 parent 91046eb commit 32582e0
Show file tree
Hide file tree
Showing 30 changed files with 394 additions and 18 deletions.
11 changes: 10 additions & 1 deletion docs/book/src/reference/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ The Sway compiler supports a list of attributes that perform various operations

## Allow

The `#[allow(dead_code)]` attribute overrides the check for dead code so that violations will go unreported.
The `#[allow(...)]` attribute overrides checks so that violations will go unreported. The following checks can be disabled:

- `#[allow(dead_code)]` disable checks for dead code;
- `#[allow(deprecated)]` disables checks for usage of deprecated structs, functions and other items.

## Doc

Expand Down Expand Up @@ -50,3 +53,9 @@ The `#[test]` attribute marks a function to be executed as a test.
The `#[test(should_revert)]` attribute marks a function to be executed as a test that should revert.

More details in [Unit Testing](../testing/unit-testing.md).

## Deprecated

The `#[deprecated]` attribute marks a item as deprecated and makes the compiler emit a warning for every usage of the deprecated item. This warning can be disabled using `#[allow(deprecated)]`.

It is possible to improve the warning message with `#[deprecated(note = "your message")]`
1 change: 1 addition & 0 deletions docs/book/src/reference/keywords.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,4 @@ Keywords associated with defining the funcitonallity of attributes
- [`payable`](./attributes.md#payable) - implies method is payable for compile time
- [`storage`](./attributes.md#storage) - declaration that contains a list of stored variables
- [`test`](./attributes.md#test) - marks a function to be executed as a test
- [`deprecated`](./attributes.md#deprecated) - marks an item as deprecated
1 change: 1 addition & 0 deletions docs/reference/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
- [Test](./documentation/language/annotations/attributes/test.md)
- [Allow](./documentation/language/annotations/attributes/allow.md)
- [Inline](./documentation/language/annotations/attributes/inline.md)
- [Deprecated](./documentation/language/annotations/attributes/deprecated.md)
- [Traits](./documentation/language/traits/index.md)
- [Generics](./documentation/language/generics/index.md)
- [Style Guide](./documentation/language/style-guide/index.md)
Expand Down
11 changes: 11 additions & 0 deletions docs/reference/src/code/language/annotations/src/main.sw
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,14 @@ fn foo() {}
#[inline(always)]
fn bar() {}
// ANCHOR_END: always_inline


// ANCHOR: allow_deprecated_annotation
#[deprecated(note = "this is deprecated")]
struct DeprecatedStruct {}

#[allow(deprecated)]
fn using_deprecated_struct() {
let _ = DeprecatedStruct {};
}
// ANCHOR_END: allow_deprecated_annotation
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,11 @@ The `#[allow(dead_code)]` annotation disables warnings which are emitted by the
```sway
{{#include ../../../../code/language/annotations/src/main.sw:allow_deadcode_annotation}}
```

## Deprecated

The `#[allow(deprecated)]` annotation disables warnings which are emitted by the compiler for usage of deprecated items.

```sway
{{#include ../../../../code/language/annotations/src/main.sw:allow_deprecated_annotation}}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Deprecated

This annotation marks an item as deprecated, which makes the compiler to emit a warning for each usage of the item. This warning can be disabled using `#[allow(deprecated)]`.

It is also possible to customize the warning message using the argument `note`.

```sway
{{#include ../../../../code/language/annotations/src/main.sw:allow_deprecated_annotation}}
```
71 changes: 70 additions & 1 deletion sway-core/src/language/ty/ast_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
engine_threading::*,
language::{parsed::TreeType, ty::*, Visibility},
semantic_analysis::{TypeCheckContext, TypeCheckFinalization, TypeCheckFinalizationContext},
transform::AttributeKind,
transform::{AllowDeprecatedState, AttributeKind},
type_system::*,
types::*,
};
Expand Down Expand Up @@ -335,6 +335,75 @@ impl TyAstNode {
TyAstNodeContent::Error(_, error) => TypeInfo::ErrorRecovery(*error),
}
}

pub(crate) fn check_deprecated(
&self,
engines: &Engines,
handler: &Handler,
allow_deprecated: &mut AllowDeprecatedState,
) {
match &self.content {
TyAstNodeContent::Declaration(node) => match node {
TyDecl::VariableDecl(decl) => {
decl.body
.check_deprecated(engines, handler, allow_deprecated);
}
TyDecl::ConstantDecl(decl) => {
let decl = engines.de().get(&decl.decl_id);
if let Some(value) = decl.value {
value.check_deprecated(engines, handler, allow_deprecated);
}
}
TyDecl::TraitTypeDecl(_) => {}
TyDecl::FunctionDecl(decl) => {
let decl = engines.de().get(&decl.decl_id);
let token = allow_deprecated.enter(decl.attributes);
for node in decl.body.contents.iter() {
node.check_deprecated(engines, handler, allow_deprecated);
}
allow_deprecated.exit(token);
}
TyDecl::ImplTrait(decl) => {
let decl = engines.de().get(&decl.decl_id);
for item in decl.items.iter() {
match item {
TyTraitItem::Fn(item) => {
let decl = engines.de().get(item.id());
let token = allow_deprecated.enter(decl.attributes);
for node in decl.body.contents.iter() {
node.check_deprecated(engines, handler, allow_deprecated);
}
allow_deprecated.exit(token);
}
TyTraitItem::Constant(item) => {
let decl = engines.de().get(item.id());
if let Some(expr) = decl.value.as_ref() {
expr.check_deprecated(engines, handler, allow_deprecated);
}
}
TyTraitItem::Type(_) => {}
}
}
}
TyDecl::AbiDecl(_)
| TyDecl::GenericTypeForFunctionScope(_)
| TyDecl::ErrorRecovery(_, _)
| TyDecl::StorageDecl(_)
| TyDecl::TraitDecl(_)
| TyDecl::StructDecl(_)
| TyDecl::EnumDecl(_)
| TyDecl::EnumVariantDecl(_)
| TyDecl::TypeAliasDecl(_) => {}
},
TyAstNodeContent::Expression(node) => {
node.check_deprecated(engines, handler, allow_deprecated);
}
TyAstNodeContent::ImplicitReturnExpression(node) => {
node.check_deprecated(engines, handler, allow_deprecated);
}
TyAstNodeContent::SideEffect(_) | TyAstNodeContent::Error(_, _) => {}
}
}
}

#[derive(Clone, Debug)]
Expand Down
84 changes: 83 additions & 1 deletion sway-core/src/language/ty/expression/expression.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
use std::{fmt, hash::Hasher};

use sway_error::handler::{ErrorEmitted, Handler};
use sway_error::{
handler::{ErrorEmitted, Handler},
warning::{CompileWarning, Warning},
};
use sway_types::{Span, Spanned};

use crate::{
decl_engine::*,
engine_threading::*,
language::{ty::*, Literal},
semantic_analysis::{TypeCheckContext, TypeCheckFinalization, TypeCheckFinalizationContext},
transform::{AllowDeprecatedState, AttributeKind, AttributesMap},
type_system::*,
types::*,
};
Expand Down Expand Up @@ -429,4 +433,82 @@ impl TyExpression {
pub(crate) fn extract_literal_value(&self) -> Option<Literal> {
self.expression.extract_literal_value()
}

// Checks if this expression references a deprecated item
// TODO: Change this fn for more deprecated checks.
pub(crate) fn check_deprecated(
&self,
engines: &Engines,
handler: &Handler,
allow_deprecated: &mut AllowDeprecatedState,
) {
fn emit_warning_if_deprecated(
attributes: &AttributesMap,
span: &Span,
handler: &Handler,
message: &str,
allow_deprecated: &mut AllowDeprecatedState,
) {
if allow_deprecated.is_allowed() {
return;
}

if let Some(v) = attributes
.get(&AttributeKind::Deprecated)
.and_then(|x| x.last())
{
let mut message = message.to_string();

if let Some(sway_ast::Literal::String(s)) = v
.args
.iter()
.find(|x| x.name.as_str() == "note")
.and_then(|x| x.value.as_ref())
{
message.push_str(": ");
message.push_str(s.parsed.as_str());
}

handler.emit_warn(CompileWarning {
span: span.clone(),
warning_content: Warning::UsingDeprecated { message },
})
}
}

match &self.expression {
TyExpressionVariant::StructExpression {
struct_ref,
instantiation_span,
..
} => {
let s = engines.de().get(struct_ref.id());
emit_warning_if_deprecated(
&s.attributes,
instantiation_span,
handler,
"deprecated struct",
allow_deprecated,
);
}
TyExpressionVariant::FunctionApplication {
call_path, fn_ref, ..
} => {
if let Some(TyDecl::ImplTrait(t)) = engines.de().get(fn_ref).implementing_type {
let t = engines.de().get(&t.decl_id).implementing_for;
if let TypeInfo::Struct(struct_ref) = engines.te().get(t.type_id) {
let s = engines.de().get(struct_ref.id());
emit_warning_if_deprecated(
&s.attributes,
&call_path.span(),
handler,
"deprecated struct",
allow_deprecated,
);
}
}
}
_ => {}
}
}
}
21 changes: 20 additions & 1 deletion sway-core/src/language/ty/module.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use sway_error::handler::Handler;
use sway_types::Span;

use crate::{
decl_engine::{DeclEngine, DeclRef, DeclRefFunction},
language::ty::*,
language::ModName,
semantic_analysis::namespace,
transform,
transform::{self, AllowDeprecatedState},
Engines,
};

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -67,6 +69,23 @@ impl TyModule {
None
})
}

pub(crate) fn check_deprecated(
&self,
engines: &Engines,
handler: &Handler,
allow_deprecated: &mut AllowDeprecatedState,
) {
for (_, submodule) in self.submodules.iter() {
submodule
.module
.check_deprecated(engines, handler, allow_deprecated);
}

for node in self.all_nodes.iter() {
node.check_deprecated(engines, handler, allow_deprecated);
}
}
}

impl<'module> Iterator for SubmodulesRecursive<'module> {
Expand Down
8 changes: 8 additions & 0 deletions sway-core/src/language/ty/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::{
decl_engine::*,
fuel_prelude::fuel_tx::StorageSlot,
language::{parsed, ty::*, Purity},
transform::AllowDeprecatedState,
type_system::*,
types::*,
Engines,
Expand Down Expand Up @@ -75,6 +76,7 @@ impl TyProgram {
let mut declarations = Vec::<TyDecl>::new();
let mut abi_entries = Vec::new();
let mut fn_declarations = std::collections::HashSet::new();

for node in &root.all_nodes {
match &node.content {
TyAstNodeContent::Declaration(TyDecl::FunctionDecl(FunctionDecl {
Expand Down Expand Up @@ -391,6 +393,12 @@ impl TyProgram {
.flat_map(|(_, submod)| submod.module.test_fns(decl_engine))
.chain(self.root.test_fns(decl_engine))
}

pub fn check_deprecated(&self, engines: &Engines, handler: &Handler) {
let mut allow_deprecated = AllowDeprecatedState::default();
self.root
.check_deprecated(engines, handler, &mut allow_deprecated);
}
}

impl CollectTypesMetadata for TyProgram {
Expand Down
2 changes: 2 additions & 0 deletions sway-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,8 @@ pub fn parsed_to_ast(
Err(e) => return Err(e),
};

typed_program.check_deprecated(engines, handler);

// Collect information about the types used in this program
let types_metadata_result = typed_program
.collect_types_metadata(handler, &mut CollectTypesMetadataContext::new(engines));
Expand Down
Loading

0 comments on commit 32582e0

Please sign in to comment.