diff --git a/external-crates/move/crates/move-cli/tests/build_tests/dependency_deprecations/Move.toml b/external-crates/move/crates/move-cli/tests/build_tests/dependency_deprecations/Move.toml new file mode 100644 index 0000000000000..f61a1e538c4f6 --- /dev/null +++ b/external-crates/move/crates/move-cli/tests/build_tests/dependency_deprecations/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "A" +edition = "2024.beta" + +[addresses] +A = "0x1" + +[dependencies] +Dep = { local = "./dep" } diff --git a/external-crates/move/crates/move-cli/tests/build_tests/dependency_deprecations/args.exp b/external-crates/move/crates/move-cli/tests/build_tests/dependency_deprecations/args.exp new file mode 100644 index 0000000000000..9adbc756494d2 --- /dev/null +++ b/external-crates/move/crates/move-cli/tests/build_tests/dependency_deprecations/args.exp @@ -0,0 +1,33 @@ +Command `build -v`: +INCLUDING DEPENDENCY Dep +BUILDING A +warning[W04037]: deprecated usage + ┌─ ./sources/l.move:8:13 + │ +8 │ am::deprecated_function(); + │ ^^^^^^^^^^^^^^^^^^^ The function 'A::m::deprecated_function' is deprecated: use a different function instead + +warning[W04037]: deprecated usage + ┌─ ./sources/l.move:10:25 + │ +10 │ mod_deprecated::deprecated_function(); + │ ^^^^^^^^^^^^^^^^^^^ The function 'A::mod_deprecated::deprecated_function' is deprecated: This function is deprecated with a deprecated module + +warning[W04037]: deprecated usage + ┌─ ./sources/l.move:11:25 + │ +11 │ mod_deprecated::make_f(); + │ ^^^^^^ The 'A::mod_deprecated::make_f' member of the module 'A::mod_deprecated' is deprecated. It is deprecated since its whole module is marked deprecated: This module is deprecated + +warning[W04037]: deprecated usage + ┌─ ./sources/l.move:13:15 + │ +13 │ l(); + │ ^^^ The struct 'A::m::Bar' is deprecated: use a different struct instead + +warning[W04037]: deprecated usage + ┌─ ./sources/l.move:15:27 + │ +15 │ l(); + │ ^ The 'A::mod_deprecated::F' member of the module 'A::mod_deprecated' is deprecated. It is deprecated since its whole module is marked deprecated: This module is deprecated + diff --git a/external-crates/move/crates/move-cli/tests/build_tests/dependency_deprecations/args.txt b/external-crates/move/crates/move-cli/tests/build_tests/dependency_deprecations/args.txt new file mode 100644 index 0000000000000..cc4865c0feda0 --- /dev/null +++ b/external-crates/move/crates/move-cli/tests/build_tests/dependency_deprecations/args.txt @@ -0,0 +1 @@ +build -v diff --git a/external-crates/move/crates/move-cli/tests/build_tests/dependency_deprecations/dep/Move.toml b/external-crates/move/crates/move-cli/tests/build_tests/dependency_deprecations/dep/Move.toml new file mode 100644 index 0000000000000..b29a3a1e586e6 --- /dev/null +++ b/external-crates/move/crates/move-cli/tests/build_tests/dependency_deprecations/dep/Move.toml @@ -0,0 +1,6 @@ +[package] +name = "Dep" +edition = "2024.beta" + +[addresses] +A = "_" diff --git a/external-crates/move/crates/move-cli/tests/build_tests/dependency_deprecations/dep/sources/m.move b/external-crates/move/crates/move-cli/tests/build_tests/dependency_deprecations/dep/sources/m.move new file mode 100644 index 0000000000000..2ee593d47f3e8 --- /dev/null +++ b/external-crates/move/crates/move-cli/tests/build_tests/dependency_deprecations/dep/sources/m.move @@ -0,0 +1,13 @@ +module A::m { + #[deprecated(note = b"use a different struct instead")] + public struct Bar() has drop; + + + public fun make_bar(): Bar { + Bar() + } + + + #[deprecated(note = b"use a different function instead")] + public fun deprecated_function() { } +} diff --git a/external-crates/move/crates/move-cli/tests/build_tests/dependency_deprecations/dep/sources/mod_deprecated.move b/external-crates/move/crates/move-cli/tests/build_tests/dependency_deprecations/dep/sources/mod_deprecated.move new file mode 100644 index 0000000000000..0547b1c82bfd6 --- /dev/null +++ b/external-crates/move/crates/move-cli/tests/build_tests/dependency_deprecations/dep/sources/mod_deprecated.move @@ -0,0 +1,12 @@ +#[deprecated(note = b"This module is deprecated")] +module A::mod_deprecated { + public struct F() has drop; + + public fun make_f(): F { + F() + } + + #[deprecated(note = b"This function is deprecated with a deprecated module")] + public fun deprecated_function() { } +} + diff --git a/external-crates/move/crates/move-cli/tests/build_tests/dependency_deprecations/sources/l.move b/external-crates/move/crates/move-cli/tests/build_tests/dependency_deprecations/sources/l.move new file mode 100644 index 0000000000000..2d8aeb908f7b7 --- /dev/null +++ b/external-crates/move/crates/move-cli/tests/build_tests/dependency_deprecations/sources/l.move @@ -0,0 +1,20 @@ +module A::l { + use A::m as am; + use A::mod_deprecated; + + #[allow(unused_function)] + fun f() { + am::make_bar(); + am::deprecated_function(); + + mod_deprecated::deprecated_function(); + mod_deprecated::make_f(); + + l(); + + l(); + } + + #[allow(unused_function, unused_type_parameter)] + fun l() { } +} diff --git a/external-crates/move/crates/move-compiler/src/diagnostics/codes.rs b/external-crates/move/crates/move-compiler/src/diagnostics/codes.rs index d084155598783..5ecc42160c971 100644 --- a/external-crates/move/crates/move-compiler/src/diagnostics/codes.rs +++ b/external-crates/move/crates/move-compiler/src/diagnostics/codes.rs @@ -289,6 +289,7 @@ codes!( IncompatibleSyntaxMethods: { msg: "'syntax' method types differ", severity: BlockingError }, InvalidErrorUsage: { msg: "invalid constant usage in error context", severity: BlockingError }, IncompletePattern: { msg: "non-exhaustive pattern", severity: BlockingError }, + DeprecatedUsage: { msg: "deprecated usage", severity: Warning }, ], // errors for ability rules. mostly typing/translate AbilitySafety: [ diff --git a/external-crates/move/crates/move-compiler/src/expansion/translate.rs b/external-crates/move/crates/move-compiler/src/expansion/translate.rs index 3d89c9fbc3618..ce41079bdd54a 100644 --- a/external-crates/move/crates/move-compiler/src/expansion/translate.rs +++ b/external-crates/move/crates/move-compiler/src/expansion/translate.rs @@ -1088,7 +1088,8 @@ fn gate_known_attribute(context: &mut Context, loc: Loc, known: &KnownAttribute) | KnownAttribute::Diagnostic(_) | KnownAttribute::DefinesPrimitive(_) | KnownAttribute::External(_) - | KnownAttribute::Syntax(_) => (), + | KnownAttribute::Syntax(_) + | KnownAttribute::Deprecation(_) => (), KnownAttribute::Error(_) => { let pkg = context.current_package(); context diff --git a/external-crates/move/crates/move-compiler/src/shared/known_attributes.rs b/external-crates/move/crates/move-compiler/src/shared/known_attributes.rs index 88e7e0f076e04..c7051ee7947f7 100644 --- a/external-crates/move/crates/move-compiler/src/shared/known_attributes.rs +++ b/external-crates/move/crates/move-compiler/src/shared/known_attributes.rs @@ -27,6 +27,7 @@ pub enum KnownAttribute { External(ExternalAttribute), Syntax(SyntaxAttribute), Error(ErrorAttribute), + Deprecation(DeprecationAttribute), } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] @@ -74,6 +75,9 @@ pub struct ExternalAttribute; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct ErrorAttribute; +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct DeprecationAttribute; + impl AttributePosition { const ALL: &'static [Self] = &[ Self::AddressBlock, @@ -102,6 +106,7 @@ impl KnownAttribute { ExternalAttribute::EXTERNAL => ExternalAttribute.into(), SyntaxAttribute::SYNTAX => SyntaxAttribute::Syntax.into(), ErrorAttribute::ERROR => ErrorAttribute.into(), + DeprecationAttribute::DEPRECATED => DeprecationAttribute.into(), _ => return None, }) } @@ -116,6 +121,7 @@ impl KnownAttribute { Self::External(a) => a.name(), Self::Syntax(a) => a.name(), Self::Error(a) => a.name(), + Self::Deprecation(a) => a.name(), } } @@ -129,6 +135,7 @@ impl KnownAttribute { Self::External(a) => a.expected_positions(), Self::Syntax(a) => a.expected_positions(), Self::Error(a) => a.expected_positions(), + Self::Deprecation(a) => a.expected_positions(), } } } @@ -326,6 +333,27 @@ impl ErrorAttribute { } } +impl DeprecationAttribute { + pub const DEPRECATED: &'static str = "deprecated"; + + pub const fn name(&self) -> &str { + Self::DEPRECATED + } + + pub fn expected_positions(&self) -> &'static BTreeSet { + static DEPRECATION_POSITIONS: Lazy> = Lazy::new(|| { + BTreeSet::from([ + AttributePosition::Constant, + AttributePosition::Module, + AttributePosition::Struct, + AttributePosition::Enum, + AttributePosition::Function, + ]) + }); + &DEPRECATION_POSITIONS + } +} + //************************************************************************************************** // Display //************************************************************************************************** @@ -357,6 +385,7 @@ impl fmt::Display for KnownAttribute { Self::External(a) => a.fmt(f), Self::Syntax(a) => a.fmt(f), Self::Error(a) => a.fmt(f), + Self::Deprecation(a) => a.fmt(f), } } } @@ -409,6 +438,12 @@ impl fmt::Display for ErrorAttribute { } } +impl fmt::Display for DeprecationAttribute { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.name()) + } +} + //************************************************************************************************** // From //************************************************************************************************** @@ -453,3 +488,8 @@ impl From for KnownAttribute { Self::Error(a) } } +impl From for KnownAttribute { + fn from(a: DeprecationAttribute) -> Self { + Self::Deprecation(a) + } +} diff --git a/external-crates/move/crates/move-compiler/src/shared/program_info.rs b/external-crates/move/crates/move-compiler/src/shared/program_info.rs index 0f4efcc271004..18f83073b2ed5 100644 --- a/external-crates/move/crates/move-compiler/src/shared/program_info.rs +++ b/external-crates/move/crates/move-compiler/src/shared/program_info.rs @@ -1,7 +1,7 @@ // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 -use std::{collections::BTreeMap, sync::Arc}; +use std::{collections::BTreeMap, fmt::Display, sync::Arc}; use move_ir_types::location::Loc; use move_symbol_pool::Symbol; @@ -19,6 +19,8 @@ use crate::{ FullyCompiledProgram, }; +use self::known_attributes::AttributePosition; + #[derive(Debug, Clone)] pub struct FunctionInfo { pub attributes: Attributes, @@ -56,6 +58,14 @@ pub enum DatatypeKind { Enum, } +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum NamedMemberKind { + Struct, + Enum, + Function, + Constant, +} + #[derive(Debug, Clone)] pub struct ProgramInfo { pub modules: UniqueMap, @@ -230,14 +240,26 @@ impl ProgramInfo { &self.enum_definition(m, n).type_parameters } + pub fn named_member_kind(&self, m: ModuleIdent, n: Name) -> NamedMemberKind { + let minfo = self.module(&m); + if minfo.structs.contains_key(&DatatypeName(n)) { + NamedMemberKind::Struct + } else if minfo.enums.contains_key(&DatatypeName(n)) { + NamedMemberKind::Enum + } else if minfo.functions.contains_key(&FunctionName(n)) { + NamedMemberKind::Function + } else if minfo.constants.contains_key(&ConstantName(n)) { + NamedMemberKind::Constant + } else { + panic!("ICE should have failed in naming") + } + } + pub fn datatype_kind(&self, m: &ModuleIdent, n: &DatatypeName) -> DatatypeKind { - match ( - self.module(m).structs.contains_key(n), - self.module(m).enums.contains_key(n), - ) { - (true, false) => DatatypeKind::Struct, - (false, true) => DatatypeKind::Enum, - (false, false) | (true, true) => panic!("ICE should have failed in naming"), + match self.named_member_kind(*m, n.0) { + NamedMemberKind::Struct => DatatypeKind::Struct, + NamedMemberKind::Enum => DatatypeKind::Enum, + _ => panic!("ICE should have failed in naming"), } } @@ -352,3 +374,34 @@ impl ProgramInfo { } } } + +impl Display for NamedMemberKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + NamedMemberKind::Struct => write!(f, "struct"), + NamedMemberKind::Enum => write!(f, "enum"), + NamedMemberKind::Function => write!(f, "function"), + NamedMemberKind::Constant => write!(f, "constant"), + } + } +} + +impl From for AttributePosition { + fn from(nmk: NamedMemberKind) -> Self { + match nmk { + NamedMemberKind::Struct => AttributePosition::Struct, + NamedMemberKind::Enum => AttributePosition::Enum, + NamedMemberKind::Function => AttributePosition::Function, + NamedMemberKind::Constant => AttributePosition::Constant, + } + } +} + +impl From for NamedMemberKind { + fn from(dt: DatatypeKind) -> Self { + match dt { + DatatypeKind::Struct => NamedMemberKind::Struct, + DatatypeKind::Enum => NamedMemberKind::Enum, + } + } +} diff --git a/external-crates/move/crates/move-compiler/src/typing/core.rs b/external-crates/move/crates/move-compiler/src/typing/core.rs index e36370ed71f2d..9ee7186f40f1d 100644 --- a/external-crates/move/crates/move-compiler/src/typing/core.rs +++ b/external-crates/move/crates/move-compiler/src/typing/core.rs @@ -28,8 +28,10 @@ use crate::{ unique_map::UniqueMap, *, }, + typing::deprecation_warnings::Deprecations, FullyCompiledProgram, }; +use known_attributes::AttributePosition; use move_ir_types::location::*; use move_symbol_pool::Symbol; use std::{ @@ -92,6 +94,8 @@ pub struct Context<'env> { pub env: &'env mut CompilationEnv, pub(super) debug: TypingDebugFlags, + deprecations: Deprecations, + // for generating new variables during match compilation next_match_var_id: usize, @@ -180,6 +184,7 @@ impl<'env> Context<'env> { info: NamingProgramInfo, ) -> Self { let global_use_funs = UseFunsScope::global(&info); + let deprecations = Deprecations::new(env, &info); let debug = TypingDebugFlags { match_counterexample: false, autocomplete_resolution: false, @@ -208,6 +213,7 @@ impl<'env> Context<'env> { macro_expansion: vec![], lambda_expansion: vec![], ide_info: IDEInfo::new(), + deprecations, } } @@ -625,6 +631,25 @@ impl<'env> Context<'env> { }) } + pub fn emit_warning_if_deprecated( + &mut self, + mident: &ModuleIdent, + name: Name, + method_opt: Option, + ) { + let in_same_module = self + .current_module + .is_some_and(|current| current == *mident); + if let Some(deprecation) = self.deprecations.get_deprecation(*mident, name) { + // Don't register a warning if we are in the module that is deprecated and the actual + // member is not deprecated. + if deprecation.location == AttributePosition::Module && in_same_module { + return; + } + deprecation.emit_deprecation_warning(self.env, name, method_opt); + } + } + fn module_info(&self, m: &ModuleIdent) -> &ModuleInfo { self.modules.module(m) } @@ -1108,6 +1133,7 @@ pub fn make_struct_type( n: &DatatypeName, ty_args_opt: Option>, ) -> (Type, Vec) { + context.emit_warning_if_deprecated(m, n.0, None); let tn = sp(loc, TypeName_::ModuleType(*m, *n)); let sdef = context.struct_definition(m, n); match ty_args_opt { @@ -1244,6 +1270,7 @@ pub fn make_enum_type( enum_: &DatatypeName, ty_args_opt: Option>, ) -> (Type, Vec) { + context.emit_warning_if_deprecated(mident, enum_.0, None); let tn = sp(loc, TypeName_::ModuleType(*mident, *enum_)); let edef = context.enum_definition(mident, enum_); match ty_args_opt { @@ -1302,6 +1329,7 @@ pub fn make_constant_type( c: &ConstantName, ) -> Type { let in_current_module = Some(m) == context.current_module.as_ref(); + context.emit_warning_if_deprecated(m, c.0, None); let (defined_loc, signature) = { let ConstantInfo { attributes: _, @@ -1410,7 +1438,15 @@ pub fn make_method_call_type( return None; }; - let function_ty = make_function_type(context, loc, &target_m, &target_f, ty_args_opt); + let target_f = target_f.with_loc(method.loc); + let function_ty = make_function_type( + context, + loc, + &target_m, + &target_f, + ty_args_opt, + Some(method), + ); Some((target_m, target_f, function_ty)) } @@ -1423,7 +1459,9 @@ pub fn make_function_type( m: &ModuleIdent, f: &FunctionName, ty_args_opt: Option>, + method_opt: Option, ) -> ResolvedFunctionType { + context.emit_warning_if_deprecated(m, f.0, method_opt); let return_ty = make_function_type_no_visibility_check(context, loc, m, f, ty_args_opt); let finfo = context.function_info(m, f); let defined_loc = finfo.defined_loc; @@ -2178,6 +2216,7 @@ fn instantiate_apply_impl( (0..*len).map(|_| AbilitySet::empty()).collect() } sp!(_, N::TypeName_::ModuleType(m, n)) => { + context.emit_warning_if_deprecated(m, n.0, None); debug_assert!(abilities_opt.is_none(), "ICE instantiated expanded type"); let tps = match context.datatype_kind(m, n) { DatatypeKind::Struct => context.struct_tparams(m, n), diff --git a/external-crates/move/crates/move-compiler/src/typing/deprecation_warnings.rs b/external-crates/move/crates/move-compiler/src/typing/deprecation_warnings.rs new file mode 100644 index 0000000000000..dc6c387a99cd9 --- /dev/null +++ b/external-crates/move/crates/move-compiler/src/typing/deprecation_warnings.rs @@ -0,0 +1,252 @@ +// Copyright (c) The Move Contributors +// SPDX-License-Identifier: Apache-2.0 + +use crate::{ + diag, + expansion::ast::{self as E, ModuleIdent}, + ice, + shared::{ + known_attributes::{AttributePosition, DeprecationAttribute, KnownAttribute}, + program_info::NamingProgramInfo, + CompilationEnv, Name, + }, +}; +use move_ir_types::location::Loc; +use std::collections::HashMap; + +const NOTE_STR: &str = "note"; + +#[derive(Debug, Clone)] +pub struct Deprecation { + // The source location of the deprecation attribute + pub source_location: Loc, + // The type of the member that is deprecated (function, constant, etc.) + pub location: AttributePosition, + // The module that the deprecated member belongs to. This is used in part to make sure we don't + // register deprecation warnings for members within a given deprecated module calling within + // that module. + pub module_ident: ModuleIdent, + // Information about the deprecation information depending on the deprecation attribute. + // #[deprecated] -- if None + // #[deprecated(note = b"message")] -- if Some(message) + pub deprecation_note: Option, +} + +#[derive(Debug, Clone)] +pub struct Deprecations { + // Name = None -- deprecation on Module + // Name = Some(Name) -- deprecation on Module::Name member + pub deprecated_members: HashMap<(ModuleIdent, Option), Deprecation>, +} + +impl Deprecations { + /// Index the modules and their members for deprecation attributes and register each + /// deprecation attribute for use later on. + pub fn new(env: &mut CompilationEnv, info: &NamingProgramInfo) -> Self { + let mut deprecated_members = HashMap::new(); + + for (mident, module_info) in info.modules.key_cloned_iter() { + if let Some(deprecation) = deprecations( + env, + AttributePosition::Module, + &module_info.attributes, + mident.loc, + mident, + ) { + deprecated_members.insert((mident, None), deprecation); + } + + for (name, constant) in module_info.constants.key_cloned_iter() { + if let Some(deprecation) = deprecations( + env, + AttributePosition::Constant, + &constant.attributes, + name.0.loc, + mident, + ) { + deprecated_members.insert((mident, Some(name.0)), deprecation); + } + } + + for (name, function) in module_info.functions.key_cloned_iter() { + if let Some(deprecation) = deprecations( + env, + AttributePosition::Function, + &function.attributes, + name.0.loc, + mident, + ) { + deprecated_members.insert((mident, Some(name.0)), deprecation); + } + } + + for (name, datatype) in module_info.structs.key_cloned_iter() { + if let Some(deprecation) = deprecations( + env, + AttributePosition::Struct, + &datatype.attributes, + name.0.loc, + mident, + ) { + deprecated_members.insert((mident, Some(name.0)), deprecation); + } + } + + for (name, datatype) in module_info.enums.key_cloned_iter() { + if let Some(deprecation) = deprecations( + env, + AttributePosition::Enum, + &datatype.attributes, + name.0.loc, + mident, + ) { + deprecated_members.insert((mident, Some(name.0)), deprecation); + } + } + } + + Self { deprecated_members } + } + + /// Return the deprecation for the specific module member if present, otherwise return the + /// deprecation for the module itself. + pub fn get_deprecation(&self, mident: ModuleIdent, member_name: Name) -> Option<&Deprecation> { + self.deprecated_members + .get(&(mident, Some(member_name))) + .or_else(|| self.deprecated_members.get(&(mident, None))) + } +} + +impl Deprecation { + /// Emit a warning for the deprecation of a module member. + pub fn emit_deprecation_warning( + &self, + env: &mut CompilationEnv, + member_name: Name, + method_opt: Option, + ) { + let mident_string = self.module_ident.to_string(); + let location_string = match (self.location, method_opt) { + (AttributePosition::Module, None) => { + format!( + "The '{mident_string}::{member_name}' member of the {} '{mident_string}' is deprecated. \ + It is deprecated since its whole module is marked deprecated", + AttributePosition::Module + ) + } + (AttributePosition::Module, Some(method)) => { + format!( + "The method '{method}' resolves to the function '{mident_string}::{member_name}' in the {} '{mident_string}' which is deprecated. \ + This function, and the method are deprecated since the whole module is marked deprecated", + AttributePosition::Module + ) + } + (position, None) => { + format!("The {position} '{mident_string}::{member_name}' is deprecated") + } + (position, Some(method)) => { + format!( + "The method '{method}' resolves to the {position} '{mident_string}::{member_name}' which is deprecated" + ) + } + }; + + let message = match &self.deprecation_note { + None => location_string, + Some(note) => format!("{location_string}: {note}"), + }; + + let location = method_opt.map_or(member_name.loc, |method| method.loc); + + env.add_diag(diag!(TypeSafety::DeprecatedUsage, (location, message))); + } +} + +// Process the deprecation attributes for a given member (module, constant, function, etc.) and +// return `Optiong` if there is a #[deprecated] attribute. If there are invalid +// #[deprecated] attributes (malformed, or multiple on the member), add an error diagnostic to +// `env` and return None. +fn deprecations( + env: &mut CompilationEnv, + attr_position: AttributePosition, + attrs: &E::Attributes, + source_location: Loc, + mident: ModuleIdent, +) -> Option { + let deprecations: Vec<_> = attrs + .iter() + .filter(|(_, v, _)| matches!(v, KnownAttribute::Deprecation(_))) + .collect(); + + if deprecations.is_empty() { + return None; + } + + if deprecations.len() != 1 { + env.add_diag(ice!(( + source_location, + "ICE: verified that there is at at least one deprecation attribute above, \ + and expansion should have failed if there were multiple deprecation attributes." + ))); + return None; + } + + let (loc, _, attr) = deprecations + .last() + .expect("Verified deprecations is not empty above"); + + let mut make_invalid_deprecation_diag = || { + let mut diag = diag!( + Attributes::InvalidUsage, + ( + *loc, + format!("Invalid '{}' attribute", DeprecationAttribute.name()) + ) + ); + let note = format!( + "Deprecation attributes must be written as `#[{0}]` or `#[{0}(note = b\"message\")]`", + DeprecationAttribute.name() + ); + diag.add_note(note); + env.add_diag(diag); + None + }; + + match &attr.value { + E::Attribute_::Name(_) => Some(Deprecation { + source_location, + location: attr_position, + deprecation_note: None, + module_ident: mident, + }), + E::Attribute_::Parameterized(_, assigns) if assigns.len() == 1 => { + let param = assigns.key_cloned_iter().next().unwrap().1; + match param { + sp!(_, E::Attribute_::Assigned(sp!(_, name), attr_val)) + if name.as_str() == NOTE_STR + && matches!( + &attr_val.value, + E::AttributeValue_::Value(sp!(_, E::Value_::Bytearray(_))) + ) => + { + let E::AttributeValue_::Value(sp!(_, E::Value_::Bytearray(b))) = + &attr_val.value + else { + unreachable!() + }; + let msg = std::str::from_utf8(b).unwrap().to_string(); + Some(Deprecation { + source_location, + location: attr_position, + deprecation_note: Some(msg), + module_ident: mident, + }) + } + _ => make_invalid_deprecation_diag(), + } + } + E::Attribute_::Assigned(_, _) | E::Attribute_::Parameterized(_, _) => { + make_invalid_deprecation_diag() + } + } +} diff --git a/external-crates/move/crates/move-compiler/src/typing/mod.rs b/external-crates/move/crates/move-compiler/src/typing/mod.rs index d287b5f59243e..b88cc173d8d21 100644 --- a/external-crates/move/crates/move-compiler/src/typing/mod.rs +++ b/external-crates/move/crates/move-compiler/src/typing/mod.rs @@ -5,6 +5,7 @@ pub mod ast; pub mod core; mod dependency_ordering; +mod deprecation_warnings; mod expand; mod infinite_instantiations; mod macro_expand; diff --git a/external-crates/move/crates/move-compiler/src/typing/translate.rs b/external-crates/move/crates/move-compiler/src/typing/translate.rs index fdcb2ae78d9f4..ee2c53b7b46e8 100644 --- a/external-crates/move/crates/move-compiler/src/typing/translate.rs +++ b/external-crates/move/crates/move-compiler/src/typing/translate.rs @@ -3865,7 +3865,7 @@ fn module_call( argloc: Loc, args: Vec, ) -> (Type, T::UnannotatedExp_) { - let fty = core::make_function_type(context, loc, &m, &f, ty_args_opt); + let fty = core::make_function_type(context, loc, &m, &f, ty_args_opt, None); let (call, ret_ty) = module_call_impl(context, loc, m, f, fty, argloc, args); (ret_ty, T::UnannotatedExp_::ModuleCall(Box::new(call))) } @@ -4287,7 +4287,7 @@ fn macro_module_call( argloc: Loc, nargs: Vec, ) -> (Type, T::UnannotatedExp_) { - let fty = core::make_function_type(context, loc, &m, &f, ty_args_opt); + let fty = core::make_function_type(context, loc, &m, &f, ty_args_opt, None); let args = nargs .into_iter() .map(|e| macro_expand::EvalStrategy::ByName(convert_macro_arg_to_block(context, e))) diff --git a/external-crates/move/crates/move-compiler/src/unit_test/filter_test_members.rs b/external-crates/move/crates/move-compiler/src/unit_test/filter_test_members.rs index 279397dce3c54..3714f0aeb4fad 100644 --- a/external-crates/move/crates/move-compiler/src/unit_test/filter_test_members.rs +++ b/external-crates/move/crates/move-compiler/src/unit_test/filter_test_members.rs @@ -245,7 +245,8 @@ fn test_attributes(attrs: &P::Attributes) -> Vec<(Loc, known_attributes::Testing | KnownAttribute::DefinesPrimitive(_) | KnownAttribute::External(_) | KnownAttribute::Syntax(_) - | KnownAttribute::Error(_) => None, + | KnownAttribute::Error(_) + | KnownAttribute::Deprecation(_) => None, }, ) .collect() diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/expansion/invalid_deprecation_locations.exp b/external-crates/move/crates/move-compiler/tests/move_2024/expansion/invalid_deprecation_locations.exp new file mode 100644 index 0000000000000..667931ffd7f41 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/expansion/invalid_deprecation_locations.exp @@ -0,0 +1,32 @@ +error[E02015]: invalid attribute + ┌─ tests/move_2024/expansion/invalid_deprecation_locations.move:5:7 + │ +5 │ #[deprecated] + │ ^^^^^^^^^^ + │ │ + │ Known attribute 'deprecated' is not expected with a friend + │ Expected to be used with one of the following: module, constant, struct, enum, function + +error[E13002]: feature is deprecated in specified edition + ┌─ tests/move_2024/expansion/invalid_deprecation_locations.move:6:5 + │ +6 │ friend 0x42::k; + │ ^^^^^^^^^^^^^^^ 'friend's are deprecated. Remove and replace 'public(friend)' with 'public(package)' + +error[E02015]: invalid attribute + ┌─ tests/move_2024/expansion/invalid_deprecation_locations.move:8:7 + │ +8 │ #[deprecated] + │ ^^^^^^^^^^ + │ │ + │ Known attribute 'deprecated' is not expected with a use + │ Expected to be used with one of the following: module, constant, struct, enum, function + +warning[W09001]: unused alias + ┌─ tests/move_2024/expansion/invalid_deprecation_locations.move:9:15 + │ +9 │ use 0x42::k; + │ ^ Unused 'use' of alias 'k'. Consider removing it + │ + = This warning can be suppressed with '#[allow(unused_use)]' applied to the 'module' or module member ('const', 'fun', or 'struct') + diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/expansion/invalid_deprecation_locations.move b/external-crates/move/crates/move-compiler/tests/move_2024/expansion/invalid_deprecation_locations.move new file mode 100644 index 0000000000000..bad2842214269 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/expansion/invalid_deprecation_locations.move @@ -0,0 +1,10 @@ +module 0x42::k { +} + +module 0x42::m { + #[deprecated] + friend 0x42::k; + + #[deprecated] + use 0x42::k; +} diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecated_macros.exp b/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecated_macros.exp new file mode 100644 index 0000000000000..f822710759f7c --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecated_macros.exp @@ -0,0 +1,90 @@ +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecated_macros.move:10:37 + │ +10 │ macro fun call_with_x($f: || -> X): X { + │ ^ The struct '0x42::m::X' is deprecated + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecated_macros.move:10:41 + │ +10 │ macro fun call_with_x($f: || -> X): X { + │ ^ The struct '0x42::m::X' is deprecated + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecated_macros.move:11:9 + │ +11 │ f(); + │ ^ The function '0x42::m::f' is deprecated + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecated_macros.move:16:9 + │ +16 │ f(); + │ ^ The function '0x42::m::f' is deprecated + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecated_macros.move:21:9 + │ +21 │ f(); + │ ^ The function '0x42::m::f' is deprecated + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecated_macros.move:26:9 + │ +26 │ f(); + │ ^ The function '0x42::m::f' is deprecated + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecated_macros.move:27:25 + │ +27 │ call_with_x!(|| X()); + │ ^ The struct '0x42::m::X' is deprecated + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecated_macros.move:31:9 + │ +31 │ f(); + │ ^ The function '0x42::m::f' is deprecated + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecated_macros.move:32:18 + │ +32 │ call!(|| X()); + │ ^ The struct '0x42::m::X' is deprecated + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecated_macros.move:33:20 + │ +33 │ call!(|| Y()); + │ ^ The struct '0x42::m::X' is deprecated + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecated_macros.move:34:22 + │ +34 │ call!(|| Y>()); + │ ^ The struct '0x42::m::X' is deprecated + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecated_macros.move:38:9 + │ +38 │ f(); + │ ^ The function '0x42::m::f' is deprecated + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecated_macros.move:39:25 + │ +39 │ call_unders!(|| X()); + │ ^ The struct '0x42::m::X' is deprecated + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecated_macros.move:40:27 + │ +40 │ call_unders!(|| Y()); + │ ^ The struct '0x42::m::X' is deprecated + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecated_macros.move:41:29 + │ +41 │ call_unders!(|| Y>()); + │ ^ The struct '0x42::m::X' is deprecated + diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecated_macros.move b/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecated_macros.move new file mode 100644 index 0000000000000..b972fc19f4eb6 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecated_macros.move @@ -0,0 +1,43 @@ +module 0x42::m { + #[deprecated] + public struct X() has drop; + + public struct Y() has drop; + + #[deprecated] + fun f() { } + + macro fun call_with_x($f: || -> X): X { + f(); + $f() + } + + macro fun call<$T>($f: || -> $T): $T { + f(); + $f() + } + + macro fun call_unders($f: || -> _): _ { + f(); + $f() + } + + fun call_call_with_x() { + f(); + call_with_x!(|| X()); + } + + fun call_call() { + f(); + call!(|| X()); + call!(|| Y()); + call!(|| Y>()); + } + + fun call_call_unders() { + f(); + call_unders!(|| X()); + call_unders!(|| Y()); + call_unders!(|| Y>()); + } +} diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecated_ty_params.exp b/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecated_ty_params.exp new file mode 100644 index 0000000000000..b82be1d645e89 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecated_ty_params.exp @@ -0,0 +1,36 @@ +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecated_ty_params.move:9:19 + │ +9 │ let _ = Y(); + │ ^ The struct '0x42::m::X' is deprecated + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecated_ty_params.move:10:15 + │ +10 │ let Y() = Y(); + │ ^ The struct '0x42::m::X' is deprecated + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecated_ty_params.move:10:24 + │ +10 │ let Y() = Y(); + │ ^ The struct '0x42::m::X' is deprecated + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecated_ty_params.move:16:11 + │ +16 │ g(); + │ ^ The struct '0x42::m::X' is deprecated + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecated_ty_params.move:17:13 + │ +17 │ g>(); + │ ^ The struct '0x42::m::X' is deprecated + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecated_ty_params.move:18:19 + │ +18 │ g>>>>(); + │ ^ The struct '0x42::m::X' is deprecated + diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecated_ty_params.move b/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecated_ty_params.move new file mode 100644 index 0000000000000..3af23f30cbd3a --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecated_ty_params.move @@ -0,0 +1,20 @@ +module 0x42::m { + #[deprecated] + public struct X() has drop; + + public struct Y() has drop; + + + fun f() { + let _ = Y(); + let Y() = Y(); + } + + fun g() { } + + fun call_g() { + g(); + g>(); + g>>>>(); + } +} diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecation_inter_module_calls.exp b/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecation_inter_module_calls.exp new file mode 100644 index 0000000000000..5a34093e70de6 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecation_inter_module_calls.exp @@ -0,0 +1,84 @@ +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_inter_module_calls.move:23:12 + │ +23 │ f: X, + │ ^ The '0x7::l::X' member of the module '0x7::l' is deprecated. It is deprecated since its whole module is marked deprecated: Use the k module instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_inter_module_calls.move:27:14 + │ +27 │ Some(X), + │ ^ The '0x7::l::X' member of the module '0x7::l' is deprecated. It is deprecated since its whole module is marked deprecated: Use the k module instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_inter_module_calls.move:28:20 + │ +28 │ Other { y: X }, + │ ^ The '0x7::l::X' member of the module '0x7::l' is deprecated. It is deprecated since its whole module is marked deprecated: Use the k module instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_inter_module_calls.move:38:24 + │ +38 │ public fun lol(_: &X) { } + │ ^ The '0x7::l::X' member of the module '0x7::l' is deprecated. It is deprecated since its whole module is marked deprecated: Use the k module instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_inter_module_calls.move:40:32 + │ +40 │ public fun quux(x: 0x7::l::X) { + │ ^ The '0x7::l::X' member of the module '0x7::l' is deprecated. It is deprecated since its whole module is marked deprecated: Use the k module instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_inter_module_calls.move:41:17 + │ +41 │ 0x7::l::foo(); + │ ^^^ The '0x7::l::foo' member of the module '0x7::l' is deprecated. It is deprecated since its whole module is marked deprecated: Use the k module instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_inter_module_calls.move:42:11 + │ +42 │ x.bar(); + │ ^^^ The method 'bar' resolves to the function '0x7::l::bar' in the module '0x7::l' which is deprecated. This function, and the method are deprecated since the whole module is marked deprecated: Use the k module instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_inter_module_calls.move:47:12 + │ +47 │ l::foo(); + │ ^^^ The '0x7::l::foo' member of the module '0x7::l' is deprecated. It is deprecated since its whole module is marked deprecated: Use the k module instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_inter_module_calls.move:52:34 + │ +52 │ public fun dep_meth_call(x: &X) { + │ ^ The '0x7::l::X' member of the module '0x7::l' is deprecated. It is deprecated since its whole module is marked deprecated: Use the k module instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_inter_module_calls.move:53:11 + │ +53 │ x.bar(); + │ ^^^ The method 'bar' resolves to the function '0x7::l::bar' in the module '0x7::l' which is deprecated. This function, and the method are deprecated since the whole module is marked deprecated: Use the k module instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_inter_module_calls.move:58:11 + │ +58 │ x.lol(); + │ ^^^ The method 'lol' resolves to the function '0x7::l::other_dep' which is deprecated: More specific deprecations override less specific ones. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_inter_module_calls.move:59:11 + │ +59 │ x.rofl(); + │ ^^^^ The method 'rofl' resolves to the function '0x7::l::other' in the module '0x7::l' which is deprecated. This function, and the method are deprecated since the whole module is marked deprecated: Use the k module instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_inter_module_calls.move:66:33 + │ +66 │ let _ = T::Some(0x7::l::make_x()); + │ ^^^^^^ The '0x7::l::make_x' member of the module '0x7::l' is deprecated. It is deprecated since its whole module is marked deprecated: Use the k module instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_inter_module_calls.move:67:39 + │ +67 │ let _ = T::Other { y: 0x7::l::make_x()}; + │ ^^^^^^ The '0x7::l::make_x' member of the module '0x7::l' is deprecated. It is deprecated since its whole module is marked deprecated: Use the k module instead. + diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecation_inter_module_calls.move b/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecation_inter_module_calls.move new file mode 100644 index 0000000000000..a6800e9f8b2a0 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecation_inter_module_calls.move @@ -0,0 +1,70 @@ +#[deprecated(note = b"Use the k module instead.")] +module 0x7::l { + public struct X() has drop; + + public fun foo() { } + + public fun bar(_: &X) { } + + #[deprecated(note = b"More specific deprecations override less specific ones.")] + public fun other_dep(_: &X) { } + + public fun other(_: &X) { } + + public fun make_x(): X { + X() + } +} + +module 0x42::m { + use 0x7::l::X; + + public struct Y has drop { + f: X, + } + + public enum T has drop { + Some(X), + Other { y: X }, + Fine, + } + + public struct B() has drop; + + use fun 0x7::l::other_dep as X.lol; + + use fun 0x7::l::other as X.rofl; + + public fun lol(_: &X) { } + + public fun quux(x: 0x7::l::X) { + 0x7::l::foo(); + x.bar(); + } + + public fun quux_use() { + use 0x7::l; + l::foo(); + } + + public fun bar(_: &B) { } + + public fun dep_meth_call(x: &X) { + x.bar(); + + // We should give deprecation notices through use fun declarations. + // Note that we get a function deprecated warning here, not a module deprecated warning. + // This is because we favor more specific deprecations over more general ones. + x.lol(); + x.rofl(); + + // No deprecation warning since it's a method call to a non-deprecated function post-resolution. + B().bar(); + } + + public fun dep_enum() { + let _ = T::Some(0x7::l::make_x()); + let _ = T::Other { y: 0x7::l::make_x()}; + let _ = T::Fine; + } +} diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecation_intra_module_calls.exp b/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecation_intra_module_calls.exp new file mode 100644 index 0000000000000..e6ec56abd7fe8 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecation_intra_module_calls.exp @@ -0,0 +1,96 @@ +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_intra_module_calls.move:8:21 + │ +8 │ public struct Z(Y) has drop; + │ ^ The struct '0x7::l::Y' is deprecated: Use the other struct instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_intra_module_calls.move:15:26 + │ +15 │ public fun other(y: &Y): &Y { y } + │ ^ The struct '0x7::l::Y' is deprecated: Use the other struct instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_intra_module_calls.move:15:31 + │ +15 │ public fun other(y: &Y): &Y { y } + │ ^ The struct '0x7::l::Y' is deprecated: Use the other struct instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_intra_module_calls.move:21:9 + │ +21 │ internal(); + │ ^^^^^^^^ The function '0x7::l::internal' is deprecated: This is a deprecated function within a deprecated module. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_intra_module_calls.move:23:17 + │ +23 │ let y = other(&Y()); + │ ^^^^^ The function '0x7::l::other' is deprecated: Use the other function instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_intra_module_calls.move:23:24 + │ +23 │ let y = other(&Y()); + │ ^ The struct '0x7::l::Y' is deprecated: Use the other struct instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_intra_module_calls.move:26:9 + │ +26 │ other(other(other(other(other(other(other(other(other(other(y)))))))))); + │ ^^^^^ The function '0x7::l::other' is deprecated: Use the other function instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_intra_module_calls.move:26:15 + │ +26 │ other(other(other(other(other(other(other(other(other(other(y)))))))))); + │ ^^^^^ The function '0x7::l::other' is deprecated: Use the other function instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_intra_module_calls.move:26:21 + │ +26 │ other(other(other(other(other(other(other(other(other(other(y)))))))))); + │ ^^^^^ The function '0x7::l::other' is deprecated: Use the other function instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_intra_module_calls.move:26:27 + │ +26 │ other(other(other(other(other(other(other(other(other(other(y)))))))))); + │ ^^^^^ The function '0x7::l::other' is deprecated: Use the other function instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_intra_module_calls.move:26:33 + │ +26 │ other(other(other(other(other(other(other(other(other(other(y)))))))))); + │ ^^^^^ The function '0x7::l::other' is deprecated: Use the other function instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_intra_module_calls.move:26:39 + │ +26 │ other(other(other(other(other(other(other(other(other(other(y)))))))))); + │ ^^^^^ The function '0x7::l::other' is deprecated: Use the other function instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_intra_module_calls.move:26:45 + │ +26 │ other(other(other(other(other(other(other(other(other(other(y)))))))))); + │ ^^^^^ The function '0x7::l::other' is deprecated: Use the other function instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_intra_module_calls.move:26:51 + │ +26 │ other(other(other(other(other(other(other(other(other(other(y)))))))))); + │ ^^^^^ The function '0x7::l::other' is deprecated: Use the other function instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_intra_module_calls.move:26:57 + │ +26 │ other(other(other(other(other(other(other(other(other(other(y)))))))))); + │ ^^^^^ The function '0x7::l::other' is deprecated: Use the other function instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_intra_module_calls.move:26:63 + │ +26 │ other(other(other(other(other(other(other(other(other(other(y)))))))))); + │ ^^^^^ The function '0x7::l::other' is deprecated: Use the other function instead. + diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecation_intra_module_calls.move b/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecation_intra_module_calls.move new file mode 100644 index 0000000000000..9002e911d428b --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecation_intra_module_calls.move @@ -0,0 +1,31 @@ +#[deprecated(note = b"Use the k module instead.")] +module 0x7::l { + public struct X() has drop; + + #[deprecated(note = b"Use the other struct instead.")] + public struct Y() has drop; + + public struct Z(Y) has drop; + + public fun foo() { } + + public fun bar(_: &X) { } + + #[deprecated(note = b"Use the other function instead.")] + public fun other(y: &Y): &Y { y } + + public fun internal_calller() { + // Should not give us a deprecation warning since it's an internal caller of a deprecated module. + foo(); + // Should give us a deprecated warning since it's an internal caller of a deprecated function. + internal(); + // Should give a warning for `other` and `Y` separately since they reference different deprecations + let y = other(&Y()); + + // This should be grouped in with the other calls to `other` in this function though + other(other(other(other(other(other(other(other(other(other(y)))))))))); + } + + #[deprecated(note = b"This is a deprecated function within a deprecated module.")] + fun internal() { } +} diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecation_use_in_constants.exp b/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecation_use_in_constants.exp new file mode 100644 index 0000000000000..a69c093ca2072 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecation_use_in_constants.exp @@ -0,0 +1,24 @@ +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_use_in_constants.move:15:9 + │ +15 │ A + B + C + D + E + B + │ ^ The constant '0x42::m::A' is deprecated + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_use_in_constants.move:15:13 + │ +15 │ A + B + C + D + E + B + │ ^ The constant '0x42::m::B' is deprecated: use D instead + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_use_in_constants.move:15:17 + │ +15 │ A + B + C + D + E + B + │ ^ The constant '0x42::m::C' is deprecated: You should use E instead + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/deprecation_use_in_constants.move:15:29 + │ +15 │ A + B + C + D + E + B + │ ^ The constant '0x42::m::B' is deprecated: use D instead + diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecation_use_in_constants.move b/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecation_use_in_constants.move new file mode 100644 index 0000000000000..27fb99fa23758 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/typing/deprecation_use_in_constants.move @@ -0,0 +1,17 @@ +module 0x42::m { + #[deprecated] + const A: u64 = 1; + + #[deprecated(note = b"use D instead")] + const B: u64 = 2; + + #[deprecated(note = b"You should use E instead")] + const C: u64 = 3; + + const D: u64 = 4; + const E: u64 = 5; + + const Combo: u64 = { + A + B + C + D + E + B + }; +} diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/typing/internal_module_deprecations.exp b/external-crates/move/crates/move-compiler/tests/move_2024/typing/internal_module_deprecations.exp new file mode 100644 index 0000000000000..4e2bdcb9ee417 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/typing/internal_module_deprecations.exp @@ -0,0 +1,102 @@ +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/internal_module_deprecations.move:3:13 + │ +3 │ Bad(A), + │ ^ The struct '0x42::m::A' is deprecated: Use the B struct instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/internal_module_deprecations.move:26:9 + │ +26 │ foo(); + │ ^^^ The function '0x42::m::foo' is deprecated + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/internal_module_deprecations.move:27:9 + │ +27 │ foo(); + │ ^^^ The function '0x42::m::foo' is deprecated + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/internal_module_deprecations.move:28:9 + │ +28 │ bar_dep(); + │ ^^^^^^^ The function '0x42::m::bar_dep' is deprecated: Use the baz function instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/internal_module_deprecations.move:31:23 + │ +31 │ public fun qux(_: A) { } + │ ^ The struct '0x42::m::A' is deprecated: Use the B struct instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/internal_module_deprecations.move:33:30 + │ +33 │ public fun return_dep(): A { + │ ^ The struct '0x42::m::A' is deprecated: Use the B struct instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/internal_module_deprecations.move:34:9 + │ +34 │ A() + │ ^ The struct '0x42::m::A' is deprecated: Use the B struct instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/internal_module_deprecations.move:38:9 + │ +38 │ H + │ ^ The constant '0x42::m::H' is deprecated: Use the L constant instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/internal_module_deprecations.move:42:15 + │ +42 │ abort OldError + │ ^^^^^^^^ The constant '0x42::m::OldError' is deprecated: Use `NewError` instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/internal_module_deprecations.move:46:18 + │ +46 │ let y = (A(): A); + │ ^ The struct '0x42::m::A' is deprecated: Use the B struct instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/internal_module_deprecations.move:46:23 + │ +46 │ let y = (A(): A); + │ ^ The struct '0x42::m::A' is deprecated: Use the B struct instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/internal_module_deprecations.move:48:13 + │ +48 │ A() => (), + │ ^ The struct '0x42::m::A' is deprecated: Use the B struct instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/internal_module_deprecations.move:50:9 + │ +50 │ A() = A(); + │ ^ The struct '0x42::m::A' is deprecated: Use the B struct instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/internal_module_deprecations.move:50:15 + │ +50 │ A() = A(); + │ ^ The struct '0x42::m::A' is deprecated: Use the B struct instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/internal_module_deprecations.move:51:13 + │ +51 │ let A() = A(); + │ ^ The struct '0x42::m::A' is deprecated: Use the B struct instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/internal_module_deprecations.move:51:19 + │ +51 │ let A() = A(); + │ ^ The struct '0x42::m::A' is deprecated: Use the B struct instead. + +warning[W04037]: deprecated usage + ┌─ tests/move_2024/typing/internal_module_deprecations.move:55:24 + │ +55 │ let _ = R::Bad(A()); + │ ^ The struct '0x42::m::A' is deprecated: Use the B struct instead. + diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/typing/internal_module_deprecations.move b/external-crates/move/crates/move-compiler/tests/move_2024/typing/internal_module_deprecations.move new file mode 100644 index 0000000000000..f2410ce66b968 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/typing/internal_module_deprecations.move @@ -0,0 +1,57 @@ +module 0x42::m { + public enum R has drop { + Bad(A), + } + + public struct B() has drop; + + #[deprecated(note = b"Use the B struct instead.")] + public struct A() has drop; + + #[deprecated] + public fun foo() { } + + #[deprecated(note = b"Use the baz function instead.")] + public fun bar_dep() { } + + #[deprecated(note = b"Use the L constant instead.")] + const H: u8 = 0x42; + + #[error, deprecated(note = b"Use `NewError` instead.")] + const OldError: vector = b"old error"; + + const NewError: vector = b"new error"; + + public fun baz() { + foo(); + foo(); + bar_dep(); + } + + public fun qux(_: A) { } + + public fun return_dep(): A { + A() + } + + public fun use_const(): u8 { + H + } + + public fun clever_error_deprecated() { + abort OldError + } + + public fun matcher() { + let y = (A(): A); + match (y) { + A() => (), + }; + A() = A(); + let A() = A(); + } + + public fun dep_enum() { + let _ = R::Bad(A()); + } +} diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/typing/invalid_deprecation_attributes.exp b/external-crates/move/crates/move-compiler/tests/move_2024/typing/invalid_deprecation_attributes.exp new file mode 100644 index 0000000000000..520679f2275d5 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/typing/invalid_deprecation_attributes.exp @@ -0,0 +1,60 @@ +error[E10004]: invalid usage of known attribute + ┌─ tests/move_2024/typing/invalid_deprecation_attributes.move:2:7 + │ +2 │ #[deprecated = b"This is a deprecated function"] + │ ^^^^^^^^^^ Invalid 'deprecated' attribute + │ + = Deprecation attributes must be written as `#[deprecated]` or `#[deprecated(note = b"message")]` + +error[E10004]: invalid usage of known attribute + ┌─ tests/move_2024/typing/invalid_deprecation_attributes.move:5:7 + │ +5 │ #[deprecated(msg = b"This is a deprecated function")] + │ ^^^^^^^^^^ Invalid 'deprecated' attribute + │ + = Deprecation attributes must be written as `#[deprecated]` or `#[deprecated(note = b"message")]` + +error[E10004]: invalid usage of known attribute + ┌─ tests/move_2024/typing/invalid_deprecation_attributes.move:8:7 + │ +8 │ #[deprecated(b"This is a deprecated function")] + │ ^^^^^^^^^^ Invalid 'deprecated' attribute + │ + = Deprecation attributes must be written as `#[deprecated]` or `#[deprecated(note = b"message")]` + +error[E01002]: unexpected token + ┌─ tests/move_2024/typing/invalid_deprecation_attributes.move:8:18 + │ +8 │ #[deprecated(b"This is a deprecated function")] + │ ^ Expected attribute + +error[E10004]: invalid usage of known attribute + ┌─ tests/move_2024/typing/invalid_deprecation_attributes.move:11:7 + │ +11 │ #[deprecated(note = b"This is a deprecated function", other = b"other")] + │ ^^^^^^^^^^ Invalid 'deprecated' attribute + │ + = Deprecation attributes must be written as `#[deprecated]` or `#[deprecated(note = b"message")]` + +error[E10004]: invalid usage of known attribute + ┌─ tests/move_2024/typing/invalid_deprecation_attributes.move:14:7 + │ +14 │ #[deprecated(note = 123)] + │ ^^^^^^^^^^ Invalid 'deprecated' attribute + │ + = Deprecation attributes must be written as `#[deprecated]` or `#[deprecated(note = b"message")]` + +warning[W02018]: unknown attribute + ┌─ tests/move_2024/typing/invalid_deprecation_attributes.move:17:7 + │ +17 │ #[deprication] + │ ^^^^^^^^^^^ Unknown attribute 'deprication'. Custom attributes must be wrapped in 'ext', e.g. #[ext(deprication)] + +error[E10004]: invalid usage of known attribute + ┌─ tests/move_2024/typing/invalid_deprecation_attributes.move:20:7 + │ +20 │ #[deprecated(foo)] + │ ^^^^^^^^^^ Invalid 'deprecated' attribute + │ + = Deprecation attributes must be written as `#[deprecated]` or `#[deprecated(note = b"message")]` + diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/typing/invalid_deprecation_attributes.move b/external-crates/move/crates/move-compiler/tests/move_2024/typing/invalid_deprecation_attributes.move new file mode 100644 index 0000000000000..ab945b9976361 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/typing/invalid_deprecation_attributes.move @@ -0,0 +1,22 @@ +module 0x42::m { + #[deprecated = b"This is a deprecated function"] + fun f() { } + + #[deprecated(msg = b"This is a deprecated function")] + fun g() { } + + #[deprecated(b"This is a deprecated function")] + fun h() { } + + #[deprecated(note = b"This is a deprecated function", other = b"other")] + fun i() { } + + #[deprecated(note = 123)] + fun j() { } + + #[deprication] + fun k() { } + + #[deprecated(foo)] + fun l() { } +} diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/typing/multiple_deprecation_attributes_invalid.exp b/external-crates/move/crates/move-compiler/tests/move_2024/typing/multiple_deprecation_attributes_invalid.exp new file mode 100644 index 0000000000000..966fabb679c54 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/typing/multiple_deprecation_attributes_invalid.exp @@ -0,0 +1,32 @@ +error[E02001]: duplicate declaration, item, or annotation + ┌─ tests/move_2024/typing/multiple_deprecation_attributes_invalid.move:3:7 + │ +2 │ #[deprecated] + │ ---------- Attribute previously given here +3 │ #[deprecated] + │ ^^^^^^^^^^ Duplicate attribute 'deprecated' attached to the same item + +error[E02001]: duplicate declaration, item, or annotation + ┌─ tests/move_2024/typing/multiple_deprecation_attributes_invalid.move:7:7 + │ +6 │ #[deprecated(note = b"note")] + │ ---------- Attribute previously given here +7 │ #[deprecated] + │ ^^^^^^^^^^ Duplicate attribute 'deprecated' attached to the same item + +error[E02001]: duplicate declaration, item, or annotation + ┌─ tests/move_2024/typing/multiple_deprecation_attributes_invalid.move:10:19 + │ +10 │ #[deprecated, deprecated(note = b"note")] + │ ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ Duplicate attribute 'deprecated' attached to the same item + │ │ + │ Attribute previously given here + +error[E02001]: duplicate declaration, item, or annotation + ┌─ tests/move_2024/typing/multiple_deprecation_attributes_invalid.move:13:19 + │ +13 │ #[deprecated, deprecated] + │ ---------- ^^^^^^^^^^ Duplicate attribute 'deprecated' attached to the same item + │ │ + │ Attribute previously given here + diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/typing/multiple_deprecation_attributes_invalid.move b/external-crates/move/crates/move-compiler/tests/move_2024/typing/multiple_deprecation_attributes_invalid.move new file mode 100644 index 0000000000000..18b3f075e347c --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/typing/multiple_deprecation_attributes_invalid.move @@ -0,0 +1,15 @@ +module 0x42::m { + #[deprecated] + #[deprecated] + fun foo() {} + + #[deprecated(note = b"note")] + #[deprecated] + fun bar() {} + + #[deprecated, deprecated(note = b"note")] + fun baz() {} + + #[deprecated, deprecated] + fun qux() {} +}