Skip to content

Commit

Permalink
Extend #[deprecated] support
Browse files Browse the repository at this point in the history
Add support for the `#[deprecated]` attribute to functions, enums,
struct items, enum variants and propagate deprecation check exhaustively
throughout expressions variants.

Partially addresses #6942.

Support for deprecating traits, abis and the methods thereof in their
definitions is still missing, as well as scrutinees and storage fields.
  • Loading branch information
IGI-111 committed Feb 20, 2025
1 parent 69ac39e commit 5be38d1
Show file tree
Hide file tree
Showing 4 changed files with 268 additions and 24 deletions.
15 changes: 14 additions & 1 deletion sway-core/src/language/ty/code_block.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
decl_engine::*, engine_threading::*, language::ty::*, semantic_analysis::TypeCheckContext,
type_system::*,
transform::AllowDeprecatedState, type_system::*,
};
use serde::{Deserialize, Serialize};
use std::hash::Hasher;
Expand All @@ -13,6 +13,19 @@ pub struct TyCodeBlock {
pub(crate) whole_block_span: Span,
}

impl TyCodeBlock {
pub(crate) fn check_deprecated(
&self,
engines: &Engines,
handler: &Handler,
allow_deprecated: &mut AllowDeprecatedState,
) {
for n in self.contents.iter() {
n.check_deprecated(engines, handler, allow_deprecated);
}
}
}

impl Default for TyCodeBlock {
fn default() -> Self {
Self {
Expand Down
215 changes: 198 additions & 17 deletions sway-core/src/language/ty/expression/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,81 @@ impl TyExpression {
}

match &self.expression {
TyExpressionVariant::Literal(..) => {}
TyExpressionVariant::FunctionApplication {
call_path,
fn_ref,
arguments,
..
} => {
for (_, expr) in arguments.iter() {
expr.check_deprecated(engines, handler, allow_deprecated);
}

let fn_ty = engines.de().get(fn_ref);
if let Some(TyDecl::ImplSelfOrTrait(t)) = &fn_ty.implementing_type {
let t = &engines.de().get(&t.decl_id).implementing_for;
if let TypeInfo::Struct(struct_id) = &*engines.te().get(t.type_id) {
let s = engines.de().get(struct_id);
emit_warning_if_deprecated(
&s.attributes,
&call_path.span(),
handler,
"deprecated struct",
allow_deprecated,
);
}
}

emit_warning_if_deprecated(
&fn_ty.attributes,
&call_path.span(),
handler,
"deprecated function",
allow_deprecated,
);
}
TyExpressionVariant::LazyOperator { lhs, rhs, .. } => {
lhs.check_deprecated(engines, handler, allow_deprecated);
rhs.check_deprecated(engines, handler, allow_deprecated);
}
TyExpressionVariant::ConstantExpression { span, decl, .. } => {
emit_warning_if_deprecated(
&decl.attributes,
span,
handler,
"deprecated constant",
allow_deprecated,
);
}
TyExpressionVariant::ConfigurableExpression { span, decl, .. } => {
emit_warning_if_deprecated(
&decl.attributes,
span,
handler,
"deprecated configurable",
allow_deprecated,
);
}
TyExpressionVariant::VariableExpression { .. } => {}
TyExpressionVariant::Tuple { fields } => {
for e in fields.iter() {
e.check_deprecated(engines, handler, allow_deprecated);
}
}
TyExpressionVariant::ArrayExplicit { contents, .. } => {
for e in contents.iter() {
e.check_deprecated(engines, handler, allow_deprecated);
}
}
TyExpressionVariant::ArrayRepeat { value, length, .. } => {
value.check_deprecated(engines, handler, allow_deprecated);
length.check_deprecated(engines, handler, allow_deprecated);
}
TyExpressionVariant::ArrayIndex { prefix, index } => {
prefix.check_deprecated(engines, handler, allow_deprecated);
index.check_deprecated(engines, handler, allow_deprecated);
}
TyExpressionVariant::StructExpression {
struct_id,
instantiation_span,
Expand All @@ -451,26 +526,132 @@ impl TyExpression {
allow_deprecated,
);
}
TyExpressionVariant::FunctionApplication {
call_path, fn_ref, ..
TyExpressionVariant::CodeBlock(block) => {
block.check_deprecated(engines, handler, allow_deprecated);
}
TyExpressionVariant::FunctionParameter => {}
TyExpressionVariant::MatchExp {
desugared,
//scrutinees,
..
} => {
if let Some(TyDecl::ImplSelfOrTrait(t)) =
&engines.de().get(fn_ref).implementing_type
{
let t = &engines.de().get(&t.decl_id).implementing_for;
if let TypeInfo::Struct(struct_id) = &*engines.te().get(t.type_id) {
let s = engines.de().get(struct_id);
emit_warning_if_deprecated(
&s.attributes,
&call_path.span(),
handler,
"deprecated struct",
allow_deprecated,
);
}
desugared.check_deprecated(engines, handler, allow_deprecated);
// TODO: check scrutinees if necessary
}
TyExpressionVariant::IfExp {
condition,
then,
r#else,
} => {
condition.check_deprecated(engines, handler, allow_deprecated);
then.check_deprecated(engines, handler, allow_deprecated);
if let Some(e) = r#else {
e.check_deprecated(engines, handler, allow_deprecated);
}
}
_ => {}
TyExpressionVariant::AsmExpression { .. } => {}
TyExpressionVariant::StructFieldAccess {
prefix,
field_to_access,
field_instantiation_span,
..
} => {
prefix.check_deprecated(engines, handler, allow_deprecated);
emit_warning_if_deprecated(
&field_to_access.attributes,
field_instantiation_span,
handler,
"deprecated struct field",
allow_deprecated,
);
}
TyExpressionVariant::TupleElemAccess { prefix, .. } => {
prefix.check_deprecated(engines, handler, allow_deprecated);
}
TyExpressionVariant::EnumInstantiation {
enum_ref,
tag,
contents,
variant_instantiation_span,
..
} => {
let enum_ty = engines.de().get(enum_ref);
emit_warning_if_deprecated(
&enum_ty.attributes,
variant_instantiation_span,
handler,
"deprecated enum",
allow_deprecated,
);
if let Some(variant_decl) = enum_ty.variants.get(*tag) {
emit_warning_if_deprecated(
&variant_decl.attributes,
variant_instantiation_span,
handler,
"deprecated enum variant",
allow_deprecated,
);
}
if let Some(expr) = contents {
expr.check_deprecated(engines, handler, allow_deprecated);
}
}
TyExpressionVariant::AbiCast { address, .. } => {
// TODO: check abi name?
address.check_deprecated(engines, handler, allow_deprecated);
}
TyExpressionVariant::StorageAccess(access) => {
// TODO: check storage access?
if let Some(expr) = &access.key_expression {
expr.check_deprecated(engines, handler, allow_deprecated);
}
}
TyExpressionVariant::IntrinsicFunction(kind) => {
for arg in kind.arguments.iter() {
arg.check_deprecated(engines, handler, allow_deprecated);
}
}
TyExpressionVariant::AbiName(..) => {}
TyExpressionVariant::EnumTag { exp } => {
exp.check_deprecated(engines, handler, allow_deprecated);
}
TyExpressionVariant::UnsafeDowncast {
exp,
//variant,
..
} => {
exp.check_deprecated(engines, handler, allow_deprecated);
// TODO: maybe check variant?
}
TyExpressionVariant::WhileLoop { condition, body } => {
condition.check_deprecated(engines, handler, allow_deprecated);
body.check_deprecated(engines, handler, allow_deprecated);
}
TyExpressionVariant::ForLoop { desugared } => {
desugared.check_deprecated(engines, handler, allow_deprecated);
}
TyExpressionVariant::Break => {}
TyExpressionVariant::Continue => {}
TyExpressionVariant::Reassignment(reass) => {
if let TyReassignmentTarget::Deref(expr) = &reass.lhs {
expr.check_deprecated(engines, handler, allow_deprecated);
}
reass
.rhs
.check_deprecated(engines, handler, allow_deprecated);
}
TyExpressionVariant::ImplicitReturn(expr) => {
expr.check_deprecated(engines, handler, allow_deprecated);
}
TyExpressionVariant::Return(expr) => {
expr.check_deprecated(engines, handler, allow_deprecated);
}
TyExpressionVariant::Ref(expr) => {
expr.check_deprecated(engines, handler, allow_deprecated);
}
TyExpressionVariant::Deref(expr) => {
expr.check_deprecated(engines, handler, allow_deprecated);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,46 @@
library;
script;

#[deprecated]
struct A {
#[deprecated]
a: u64,
b: u64,
}

impl A {
#[deprecated]
fn fun(self) {}
}

#[deprecated]
enum B {
A: ()
A: (),
#[deprecated]
B: (),
}

pub fn f() {
let _ = A {};

#[deprecated]
fn depr(_a: A) {}

fn fun(_a: A) {}

#[deprecated]
fn depr_b(_b: B) {}

// TODO: support for traits, abis and their methods
pub fn main() {
let a = A { a: 0, b: 0 };
let b = B::A;
depr(a);
depr(A { a: 0, b: 0 });
depr_b(b);
depr_b(B::A);
fun(a);
fun(A { a: 0, b: 0 });
let _ = a.a;
let _ = a.b;
let _ = B::A;
}
let _ = B::B;
a.fun();
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,23 @@
category = "compile"
expected_warnings = 1
expected_warnings = 20

# check: $()deprecated struct field
# check: $()deprecated struct
# check: $()deprecated enum
# check: $()deprecated enum
# check: $()deprecated enum variant
# check: $()deprecated struct
# check: $()deprecated enum
# check: $()deprecated function
# check: $()deprecated struct
# check: $()deprecated function
# check: $()deprecated function
# check: $()deprecated enum
# check: $()deprecated function
# check: $()deprecated struct
# check: $()deprecated struct field
# check: $()deprecated enum
# check: $()deprecated enum
# check: $()deprecated enum variant
# check: $()deprecated struct
# check: $()deprecated function

0 comments on commit 5be38d1

Please sign in to comment.