From 5be38d113ba0d61cd8b7021a70bad64589d691a7 Mon Sep 17 00:00:00 2001 From: IGI-111 Date: Thu, 20 Feb 2025 18:06:40 +0400 Subject: [PATCH] Extend `#[deprecated]` support 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. --- sway-core/src/language/ty/code_block.rs | 15 +- .../src/language/ty/expression/expression.rs | 215 ++++++++++++++++-- .../language/deprecated/src/main.sw | 41 +++- .../should_pass/language/deprecated/test.toml | 21 +- 4 files changed, 268 insertions(+), 24 deletions(-) diff --git a/sway-core/src/language/ty/code_block.rs b/sway-core/src/language/ty/code_block.rs index 77a841ff4bc..0284a72f6f7 100644 --- a/sway-core/src/language/ty/code_block.rs +++ b/sway-core/src/language/ty/code_block.rs @@ -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; @@ -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 { diff --git a/sway-core/src/language/ty/expression/expression.rs b/sway-core/src/language/ty/expression/expression.rs index f94902d2368..7929095e207 100644 --- a/sway-core/src/language/ty/expression/expression.rs +++ b/sway-core/src/language/ty/expression/expression.rs @@ -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, @@ -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); + } } } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/deprecated/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/deprecated/src/main.sw index a3dbe4e6b05..1c581d84ec0 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/deprecated/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/deprecated/src/main.sw @@ -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; -} \ No newline at end of file + let _ = B::B; + a.fun(); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/deprecated/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/deprecated/test.toml index 6d3bec6fe46..a32b777862b 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/deprecated/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/deprecated/test.toml @@ -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