From 31c7d83c1dfe8307f2a4976e374466ac1672341d Mon Sep 17 00:00:00 2001 From: Wilbert-mad Date: Fri, 18 Oct 2024 18:54:44 -0500 Subject: [PATCH 01/21] rebase fix --- compiler-core/src/analyse.rs | 2 + compiler-core/src/ast.rs | 1 + compiler-core/src/parse.rs | 35 ++++++++ compiler-core/src/parse/error.rs | 23 ++++- ...cation_attribute_on_all_type_variants.snap | 22 +++++ ...deprecation_attribute_on_type_variant.snap | 89 +++++++++++++++++++ ..._parse__tests__record_access_no_label.snap | 1 + compiler-core/src/parse/tests.rs | 13 +++ 8 files changed, 183 insertions(+), 3 deletions(-) create mode 100644 compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_all_type_variants.snap create mode 100644 compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_type_variant.snap diff --git a/compiler-core/src/analyse.rs b/compiler-core/src/analyse.rs index 88e465e0efe..9265d70c571 100644 --- a/compiler-core/src/analyse.rs +++ b/compiler-core/src/analyse.rs @@ -832,6 +832,7 @@ impl<'a, A> ModuleAnalyzer<'a, A> { name, arguments: args, documentation, + deprecation: constructor_deprecation, }| { self.check_name_case(name_location, &name, Named::CustomTypeVariant); @@ -868,6 +869,7 @@ impl<'a, A> ModuleAnalyzer<'a, A> { name, arguments: args, documentation, + deprecation: constructor_deprecation, } }, ) diff --git a/compiler-core/src/ast.rs b/compiler-core/src/ast.rs index efcff40e310..fd83f898519 100644 --- a/compiler-core/src/ast.rs +++ b/compiler-core/src/ast.rs @@ -232,6 +232,7 @@ pub struct RecordConstructor { pub name: EcoString, pub arguments: Vec>, pub documentation: Option<(u32, EcoString)>, + pub deprecation: Deprecation, } impl RecordConstructor { diff --git a/compiler-core/src/parse.rs b/compiler-core/src/parse.rs index 9b7f6b4a396..02285e7eb29 100644 --- a/compiler-core/src/parse.rs +++ b/compiler-core/src/parse.rs @@ -2145,6 +2145,24 @@ where let constructors = Parser::series_of( self, &|p| { + // The only attribute supported on constructors is @deprecated out of `external` and `target` + let mut attributes = Attributes::default(); + let attr_loc = Parser::parse_attributes(p, &mut attributes)?; + + // Expecting all but the deprecated atterbutes to be default + if attr_loc.is_some() // only if attributes are present + && (attributes.external_erlang.is_some() + || attributes.external_javascript.is_some() + || attributes.target.is_some() + || attributes.internal != InternalAttribute::Missing) + { + let attr_span = attr_loc.unwrap(); + return parse_error( + ParseErrorType::UnknownAttributeRecordConstructor, + attr_span, + ); + } + if let Some((c_s, c_n, c_e)) = Parser::maybe_upname(p) { let documentation = p.take_documentation(c_s); let (args, args_e) = Parser::parse_type_constructor_args(p)?; @@ -2158,6 +2176,7 @@ where name: c_n, arguments: args, documentation, + deprecation: attributes.deprecated, })) } else { Ok(None) @@ -2193,6 +2212,22 @@ where } else { (vec![], end) }; + + // check if all constructors are deprecation if so err + if constructors.len() > 0 // prevent checking an empty type `type wobble` which will always be true + && constructors + .iter() + .all(|record| record.deprecation.is_deprecated()) + { + return parse_error( + ParseErrorType::AllVariantRecordConstructorDeprecated, + SrcSpan { + start, + end: end_position, + }, + ); + } + Ok(Some(Definition::CustomType(CustomType { documentation, location: SrcSpan { start, end }, diff --git a/compiler-core/src/parse/error.rs b/compiler-core/src/parse/error.rs index e99e49eeb5c..b1c17482cf2 100644 --- a/compiler-core/src/parse/error.rs +++ b/compiler-core/src/parse/error.rs @@ -327,6 +327,21 @@ utf16_codepoint, utf32_codepoint, signed, unsigned, big, little, native, size, u "Hint: If a type is not generic you should omit the `()`.".into(), ], ), + ParseErrorType::UnknownAttributeRecordConstructor => ( + "Type constructor attribute is unknow.", + vec!["Try `@deprecated`.".into()], + ), + ParseErrorType::AllVariantRecordConstructorDeprecated => ( + "Can't deprecate all variants of a type.", + vec![ + "Consider deprecating the type as a whole:".into(), + "@deprecated(\"message\")".into(), + "type Wibble {".into(), + " Wobble1".into(), + " Wobble2".into(), + "}".into(), + ], + ), } } } @@ -395,9 +410,11 @@ pub enum ParseErrorType { }, CallInClauseGuard, // case x { _ if f() -> 1 } IfExpression, - ConstantRecordConstructorNoArguments, // const x = Record() - TypeConstructorNoArguments, // let a : Int() - TypeDefinitionNoArguments, // pub type Wibble() { ... } + ConstantRecordConstructorNoArguments, // const x = Record() + TypeConstructorNoArguments, // let a : Int() + TypeDefinitionNoArguments, // pub type Wibble() { ... } + UnknownAttributeRecordConstructor, // an attribute was used that is not know for a custom type constructor + AllVariantRecordConstructorDeprecated, // a the variants within a custom type are deprecated } impl LexicalError { diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_all_type_variants.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_all_type_variants.snap new file mode 100644 index 00000000000..f8fc5d5dfbd --- /dev/null +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_all_type_variants.snap @@ -0,0 +1,22 @@ +--- +source: compiler-core/src/parse/tests.rs +assertion_line: 1512 +expression: "\ntype Wibble {\n @deprecated(\"1\")\n Wibble1\n @deprecated(\"2\")\n Wibble2\n}\n" +--- +error: Syntax error + ┌─ /src/parse/error.gleam:2:1 + │ +2 │ ╭ type Wibble { +3 │ │ @deprecated("1") +4 │ │ Wibble1 +5 │ │ @deprecated("2") +6 │ │ Wibble2 +7 │ │ } + │ ╰─^ Can't deprecate all variants of a type. + +Consider deprecating the type as a whole: +@deprecated("message") +type Wibble { + Wobble1 + Wobble2 +} diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_type_variant.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_type_variant.snap new file mode 100644 index 00000000000..397339a6b33 --- /dev/null +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_type_variant.snap @@ -0,0 +1,89 @@ +--- +source: compiler-core/src/parse/tests.rs +assertion_line: 1526 +expression: "\ntype Wibble {\n @deprecated(\"1\")\n Wibble1\n Wibble2\n}\n" +--- +Parsed { + module: Module { + name: "", + documentation: [], + type_info: (), + definitions: [ + TargetedDefinition { + definition: CustomType( + CustomType { + location: SrcSpan { + start: 1, + end: 12, + }, + end_position: 61, + name: "Wibble", + name_location: SrcSpan { + start: 6, + end: 12, + }, + publicity: Private, + constructors: [ + RecordConstructor { + location: SrcSpan { + start: 40, + end: 47, + }, + name_location: SrcSpan { + start: 40, + end: 47, + }, + name: "Wibble1", + arguments: [], + documentation: None, + deprecation: Deprecated { + message: "1", + }, + }, + RecordConstructor { + location: SrcSpan { + start: 52, + end: 59, + }, + name_location: SrcSpan { + start: 52, + end: 59, + }, + name: "Wibble2", + arguments: [], + documentation: None, + deprecation: NotDeprecated, + }, + ], + documentation: None, + deprecation: NotDeprecated, + opaque: false, + parameters: [], + typed_parameters: [], + }, + ), + target: None, + }, + ], + names: Names { + local_types: {}, + imported_modules: {}, + type_variables: {}, + local_value_constructors: {}, + }, + }, + extra: ModuleExtra { + module_comments: [], + doc_comments: [], + comments: [], + empty_lines: [], + new_lines: [ + 0, + 14, + 35, + 47, + 59, + 61, + ], + }, +} diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__record_access_no_label.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__record_access_no_label.snap index fc2a876d958..ad0330040fa 100644 --- a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__record_access_no_label.snap +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__record_access_no_label.snap @@ -64,6 +64,7 @@ Parsed { }, ], documentation: None, + deprecation: NotDeprecated, }, ], documentation: None, diff --git a/compiler-core/src/parse/tests.rs b/compiler-core/src/parse/tests.rs index c68c778eec5..4b76235fb26 100644 --- a/compiler-core/src/parse/tests.rs +++ b/compiler-core/src/parse/tests.rs @@ -1574,3 +1574,16 @@ fn missing_type_constructor_arguments_in_type_annotation_2() { }" ); } + +#[test] +fn deprecation_attribute_on_type_variant() { + assert_parse_module!( + r#" +type Wibble { + @deprecated("1") + Wibble1 + Wibble2 +} +"# + ); +} From 88f5a81c4d16c9bb9c2381a4405ca17e5a7a30ed Mon Sep 17 00:00:00 2001 From: Wilbert-mad Date: Fri, 18 Oct 2024 18:59:33 -0500 Subject: [PATCH 02/21] fix typo --- compiler-core/src/parse/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler-core/src/parse/error.rs b/compiler-core/src/parse/error.rs index b1c17482cf2..049868b04d6 100644 --- a/compiler-core/src/parse/error.rs +++ b/compiler-core/src/parse/error.rs @@ -414,7 +414,7 @@ pub enum ParseErrorType { TypeConstructorNoArguments, // let a : Int() TypeDefinitionNoArguments, // pub type Wibble() { ... } UnknownAttributeRecordConstructor, // an attribute was used that is not know for a custom type constructor - AllVariantRecordConstructorDeprecated, // a the variants within a custom type are deprecated + AllVariantRecordConstructorDeprecated, // all the variants within a custom type are deprecated } impl LexicalError { From f1a9f7bef0a7d8305fac233acab2a419b1c2179f Mon Sep 17 00:00:00 2001 From: Wilbert-mad Date: Fri, 18 Oct 2024 19:09:49 -0500 Subject: [PATCH 03/21] fix typo --- compiler-core/src/parse.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler-core/src/parse.rs b/compiler-core/src/parse.rs index 02285e7eb29..af5f4c652dd 100644 --- a/compiler-core/src/parse.rs +++ b/compiler-core/src/parse.rs @@ -2213,7 +2213,7 @@ where (vec![], end) }; - // check if all constructors are deprecation if so err + // check if all constructors are deprecated if so error if constructors.len() > 0 // prevent checking an empty type `type wobble` which will always be true && constructors .iter() From 231f4ae4ab7e294862fe14f8f085c7546e2df8ca Mon Sep 17 00:00:00 2001 From: Wilbert-mad Date: Fri, 18 Oct 2024 19:11:29 -0500 Subject: [PATCH 04/21] fix incorrection --- compiler-core/src/parse.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler-core/src/parse.rs b/compiler-core/src/parse.rs index af5f4c652dd..42bf9181df7 100644 --- a/compiler-core/src/parse.rs +++ b/compiler-core/src/parse.rs @@ -2145,7 +2145,7 @@ where let constructors = Parser::series_of( self, &|p| { - // The only attribute supported on constructors is @deprecated out of `external` and `target` + // The only attribute supported on constructors is @deprecated let mut attributes = Attributes::default(); let attr_loc = Parser::parse_attributes(p, &mut attributes)?; From dc65c5db248b79e8782f0ab2484fa5c4f746183f Mon Sep 17 00:00:00 2001 From: Wilbert-mad Date: Fri, 18 Oct 2024 19:50:57 -0500 Subject: [PATCH 05/21] more testing with attrs in variants and error message --- compiler-core/src/parse/error.rs | 2 +- ...s__external_attribute_on_type_variant.snap | 12 ++++ ...s__internal_attribute_on_type_variant.snap | 12 ++++ ...deprecation_attribute_on_type_variant.snap | 12 ++++ ...nsupported_attributes_on_type_variant.snap | 14 ++++ ...sts__target_attribute_on_type_variant.snap | 12 ++++ compiler-core/src/parse/tests.rs | 64 +++++++++++++++++++ 7 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 compiler-core/src/parse/snapshots/gleam_core__parse__tests__external_attribute_on_type_variant.snap create mode 100644 compiler-core/src/parse/snapshots/gleam_core__parse__tests__internal_attribute_on_type_variant.snap create mode 100644 compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_deprecation_attribute_on_type_variant.snap create mode 100644 compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_unsupported_attributes_on_type_variant.snap create mode 100644 compiler-core/src/parse/snapshots/gleam_core__parse__tests__target_attribute_on_type_variant.snap diff --git a/compiler-core/src/parse/error.rs b/compiler-core/src/parse/error.rs index 049868b04d6..6d5dff03bc6 100644 --- a/compiler-core/src/parse/error.rs +++ b/compiler-core/src/parse/error.rs @@ -328,7 +328,7 @@ utf16_codepoint, utf32_codepoint, signed, unsigned, big, little, native, size, u ], ), ParseErrorType::UnknownAttributeRecordConstructor => ( - "Type constructor attribute is unknow.", + "Variant attribute(s) are unknow.", vec!["Try `@deprecated`.".into()], ), ParseErrorType::AllVariantRecordConstructorDeprecated => ( diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__external_attribute_on_type_variant.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__external_attribute_on_type_variant.snap new file mode 100644 index 00000000000..36986b35f15 --- /dev/null +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__external_attribute_on_type_variant.snap @@ -0,0 +1,12 @@ +--- +source: compiler-core/src/parse/tests.rs +assertion_line: 1577 +expression: "\ntype Wibble {\n @external(erlang, \"one\", \"two\")\n Wibble1\n}\n" +--- +error: Syntax error + ┌─ /src/parse/error.gleam:3:5 + │ +3 │ @external(erlang, "one", "two") + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Variant attribute(s) are unknow. + +Try `@deprecated`. diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__internal_attribute_on_type_variant.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__internal_attribute_on_type_variant.snap new file mode 100644 index 00000000000..0ba4bff0ea2 --- /dev/null +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__internal_attribute_on_type_variant.snap @@ -0,0 +1,12 @@ +--- +source: compiler-core/src/parse/tests.rs +assertion_line: 1565 +expression: "\ntype Wibble {\n @internal\n Wibble1\n}\n" +--- +error: Syntax error + ┌─ /src/parse/error.gleam:3:5 + │ +3 │ @internal + │ ^^^^^^^^^ Variant attribute(s) are unknow. + +Try `@deprecated`. diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_deprecation_attribute_on_type_variant.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_deprecation_attribute_on_type_variant.snap new file mode 100644 index 00000000000..be9923be162 --- /dev/null +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_deprecation_attribute_on_type_variant.snap @@ -0,0 +1,12 @@ +--- +source: compiler-core/src/parse/tests.rs +assertion_line: 1539 +expression: "\ntype Wibble {\n @deprecated(\"1\")\n @deprecated(\"2\")\n Wibble1\n Wibble2\n}\n" +--- +error: Syntax error + ┌─ /src/parse/error.gleam:4:5 + │ +4 │ @deprecated("2") + │ ^^^^^^^^^^^ Duplicate attribute + +This attribute has already been given. diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_unsupported_attributes_on_type_variant.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_unsupported_attributes_on_type_variant.snap new file mode 100644 index 00000000000..217fdd4719a --- /dev/null +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_unsupported_attributes_on_type_variant.snap @@ -0,0 +1,14 @@ +--- +source: compiler-core/src/parse/tests.rs +assertion_line: 1589 +expression: "\ntype Wibble {\n @external(erlang, \"one\", \"two\")\n @target(erlang)\n @internal\n Wibble1\n}\n" +--- +error: Syntax error + ┌─ /src/parse/error.gleam:3:5 + │ +3 │ ╭ @external(erlang, "one", "two") +4 │ │ @target(erlang) +5 │ │ @internal + │ ╰─────────────^ Variant attribute(s) are unknow. + +Try `@deprecated`. diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__target_attribute_on_type_variant.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__target_attribute_on_type_variant.snap new file mode 100644 index 00000000000..3f184d00d7d --- /dev/null +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__target_attribute_on_type_variant.snap @@ -0,0 +1,12 @@ +--- +source: compiler-core/src/parse/tests.rs +assertion_line: 1553 +expression: "\ntype Wibble {\n @target(erlang)\n Wibble2\n}\n" +--- +error: Syntax error + ┌─ /src/parse/error.gleam:3:5 + │ +3 │ @target(erlang) + │ ^^^^^^^^^^^^^^^ Variant attribute(s) are unknow. + +Try `@deprecated`. diff --git a/compiler-core/src/parse/tests.rs b/compiler-core/src/parse/tests.rs index 4b76235fb26..b66fb7f9a4d 100644 --- a/compiler-core/src/parse/tests.rs +++ b/compiler-core/src/parse/tests.rs @@ -1587,3 +1587,67 @@ type Wibble { "# ); } + +#[test] +fn multiple_deprecation_attribute_on_type_variant() { + assert_module_error!( + r#" +type Wibble { + @deprecated("1") + @deprecated("2") + Wibble1 + Wibble2 +} +"# + ); +} + +#[test] +fn target_attribute_on_type_variant() { + assert_module_error!( + r#" +type Wibble { + @target(erlang) + Wibble2 +} +"# + ); +} + +#[test] +fn internal_attribute_on_type_variant() { + assert_module_error!( + r#" +type Wibble { + @internal + Wibble1 +} +"# + ); +} + +#[test] +fn external_attribute_on_type_variant() { + assert_module_error!( + r#" +type Wibble { + @external(erlang, "one", "two") + Wibble1 +} +"# + ); +} + +#[test] +fn multiple_unsupported_attributes_on_type_variant() { + assert_module_error!( + r#" +type Wibble { + @external(erlang, "one", "two") + @target(erlang) + @internal + Wibble1 +} +"# + ); +} From 185f4097352b290f617572bbe688189e3c36dc53 Mon Sep 17 00:00:00 2001 From: Wilbert-mad Date: Sat, 19 Oct 2024 13:44:58 -0500 Subject: [PATCH 06/21] shorter error span --- compiler-core/src/parse.rs | 5 +---- ...s__deprecation_attribute_on_all_type_variants.snap | 11 +++-------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/compiler-core/src/parse.rs b/compiler-core/src/parse.rs index 42bf9181df7..5c1636997b3 100644 --- a/compiler-core/src/parse.rs +++ b/compiler-core/src/parse.rs @@ -2221,10 +2221,7 @@ where { return parse_error( ParseErrorType::AllVariantRecordConstructorDeprecated, - SrcSpan { - start, - end: end_position, - }, + SrcSpan { start, end }, ); } diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_all_type_variants.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_all_type_variants.snap index f8fc5d5dfbd..e02e3f916b1 100644 --- a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_all_type_variants.snap +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_all_type_variants.snap @@ -5,14 +5,9 @@ expression: "\ntype Wibble {\n @deprecated(\"1\")\n Wibble1\n @deprecat --- error: Syntax error ┌─ /src/parse/error.gleam:2:1 - │ -2 │ ╭ type Wibble { -3 │ │ @deprecated("1") -4 │ │ Wibble1 -5 │ │ @deprecated("2") -6 │ │ Wibble2 -7 │ │ } - │ ╰─^ Can't deprecate all variants of a type. + │ +2 │ type Wibble { + │ ^^^^^^^^^^^ Can't deprecate all variants of a type. Consider deprecating the type as a whole: @deprecated("message") From b1d5edc46f8abeda0896d91b7e184fde4a1d4ba7 Mon Sep 17 00:00:00 2001 From: Wilbert-mad Date: Sun, 20 Oct 2024 09:19:17 -0500 Subject: [PATCH 07/21] all variants error in analyse phase --- compiler-core/src/analyse.rs | 12 ++++++++- compiler-core/src/error.rs | 25 +++++++++++++++++++ compiler-core/src/parse.rs | 12 --------- compiler-core/src/parse/error.rs | 10 +++++--- ...s__external_attribute_on_type_variant.snap | 4 +-- ...s__internal_attribute_on_type_variant.snap | 4 +-- ...nsupported_attributes_on_type_variant.snap | 4 +-- ...sts__target_attribute_on_type_variant.snap | 4 +-- compiler-core/src/type_/error.rs | 17 ++++++++++++- compiler-core/src/type_/tests/custom_types.rs | 14 +++++++++++ ...m_types__deprecated_all_varients_type.snap | 18 +++++++++++++ 11 files changed, 94 insertions(+), 30 deletions(-) create mode 100644 compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_all_varients_type.snap diff --git a/compiler-core/src/analyse.rs b/compiler-core/src/analyse.rs index 9265d70c571..d771c65f9b9 100644 --- a/compiler-core/src/analyse.rs +++ b/compiler-core/src/analyse.rs @@ -823,7 +823,7 @@ impl<'a, A> ModuleAnalyzer<'a, A> { } => self.track_feature_usage(FeatureKind::InternalAnnotation, location), } - let constructors = constructors + let constructors: Vec>> = constructors .into_iter() .map( |RecordConstructor { @@ -880,6 +880,16 @@ impl<'a, A> ModuleAnalyzer<'a, A> { .parameters .clone(); + // check if all constructors are deprecated if so error + if constructors.len() > 0 // prevent checking an empty type `type wobble` which will always be true + && constructors + .iter() + .all(|record| record.deprecation.is_deprecated()) + { + self.problems + .error(Error::AllVariantsConstructorDeprecated { location }); + } + Ok(Definition::CustomType(CustomType { documentation: doc, location, diff --git a/compiler-core/src/error.rs b/compiler-core/src/error.rs index cc6ed301e2e..903a052c1b3 100644 --- a/compiler-core/src/error.rs +++ b/compiler-core/src/error.rs @@ -3129,6 +3129,31 @@ Try: _{}", kind_str.to_title_case(), name.to_snake_case()), }), } }, + TypeError::AllVariantsConstructorDeprecated { location } => { + let text = format!("Consider deprecating the type as a whole. + + @deprecated(\"message\") + type Wibble {{ + Wobble1 + Wobble2 + }} +"); + Diagnostic { + title: "Can't deprecate all variants of a type.".into(), + text, + hint: None, + level: Level::Error, + location: Some(Location { + label: Label { + text: None, + span: *location, + }, + path: path.clone(), + src: src.clone(), + extra_labels: vec![], + }) + } + } } }).collect_vec(), diff --git a/compiler-core/src/parse.rs b/compiler-core/src/parse.rs index 5c1636997b3..796c6d71e98 100644 --- a/compiler-core/src/parse.rs +++ b/compiler-core/src/parse.rs @@ -2213,18 +2213,6 @@ where (vec![], end) }; - // check if all constructors are deprecated if so error - if constructors.len() > 0 // prevent checking an empty type `type wobble` which will always be true - && constructors - .iter() - .all(|record| record.deprecation.is_deprecated()) - { - return parse_error( - ParseErrorType::AllVariantRecordConstructorDeprecated, - SrcSpan { start, end }, - ); - } - Ok(Some(Definition::CustomType(CustomType { documentation, location: SrcSpan { start, end }, diff --git a/compiler-core/src/parse/error.rs b/compiler-core/src/parse/error.rs index 6d5dff03bc6..94b2cc5cecc 100644 --- a/compiler-core/src/parse/error.rs +++ b/compiler-core/src/parse/error.rs @@ -342,6 +342,9 @@ utf16_codepoint, utf32_codepoint, signed, unsigned, big, little, native, size, u "}".into(), ], ), + ParseErrorType::UnknownAttributeRecordConstructor => { + ("This attribute cannot be used on a type variant.", vec![]) + } } } } @@ -410,11 +413,10 @@ pub enum ParseErrorType { }, CallInClauseGuard, // case x { _ if f() -> 1 } IfExpression, - ConstantRecordConstructorNoArguments, // const x = Record() - TypeConstructorNoArguments, // let a : Int() - TypeDefinitionNoArguments, // pub type Wibble() { ... } + ConstantRecordConstructorNoArguments, // const x = Record() + TypeConstructorNoArguments, // let a : Int() + TypeDefinitionNoArguments, // pub type Wibble() { ... } UnknownAttributeRecordConstructor, // an attribute was used that is not know for a custom type constructor - AllVariantRecordConstructorDeprecated, // all the variants within a custom type are deprecated } impl LexicalError { diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__external_attribute_on_type_variant.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__external_attribute_on_type_variant.snap index 36986b35f15..ed6d1abdec4 100644 --- a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__external_attribute_on_type_variant.snap +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__external_attribute_on_type_variant.snap @@ -7,6 +7,4 @@ error: Syntax error ┌─ /src/parse/error.gleam:3:5 │ 3 │ @external(erlang, "one", "two") - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Variant attribute(s) are unknow. - -Try `@deprecated`. + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This attribute cannot be used on a type variant. diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__internal_attribute_on_type_variant.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__internal_attribute_on_type_variant.snap index 0ba4bff0ea2..721b445cc9d 100644 --- a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__internal_attribute_on_type_variant.snap +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__internal_attribute_on_type_variant.snap @@ -7,6 +7,4 @@ error: Syntax error ┌─ /src/parse/error.gleam:3:5 │ 3 │ @internal - │ ^^^^^^^^^ Variant attribute(s) are unknow. - -Try `@deprecated`. + │ ^^^^^^^^^ This attribute cannot be used on a type variant. diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_unsupported_attributes_on_type_variant.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_unsupported_attributes_on_type_variant.snap index 217fdd4719a..9bf67052b73 100644 --- a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_unsupported_attributes_on_type_variant.snap +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_unsupported_attributes_on_type_variant.snap @@ -9,6 +9,4 @@ error: Syntax error 3 │ ╭ @external(erlang, "one", "two") 4 │ │ @target(erlang) 5 │ │ @internal - │ ╰─────────────^ Variant attribute(s) are unknow. - -Try `@deprecated`. + │ ╰─────────────^ This attribute cannot be used on a type variant. diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__target_attribute_on_type_variant.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__target_attribute_on_type_variant.snap index 3f184d00d7d..bdf16eeca70 100644 --- a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__target_attribute_on_type_variant.snap +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__target_attribute_on_type_variant.snap @@ -7,6 +7,4 @@ error: Syntax error ┌─ /src/parse/error.gleam:3:5 │ 3 │ @target(erlang) - │ ^^^^^^^^^^^^^^^ Variant attribute(s) are unknow. - -Try `@deprecated`. + │ ^^^^^^^^^^^^^^^ This attribute cannot be used on a type variant. diff --git a/compiler-core/src/type_/error.rs b/compiler-core/src/type_/error.rs index 66ac984c608..70dcf8b5840 100644 --- a/compiler-core/src/type_/error.rs +++ b/compiler-core/src/type_/error.rs @@ -561,6 +561,20 @@ pub enum Error { kind: Named, name: EcoString, }, + + /// Occers when all the variant type of a custom type are deprecated + /// + /// ```gleam + /// type Wibble { + /// @deprecated("1") + /// Wobble1 + /// @deprecated("1") + /// Wobble1 + /// } + /// ``` + AllVariantsConstructorDeprecated { + location: SrcSpan, + }, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -972,7 +986,8 @@ impl Error { } | Error::UseFnDoesntTakeCallback { location, .. } | Error::UseFnIncorrectArity { location, .. } - | Error::BadName { location, .. } => location.start, + | Error::BadName { location, .. } + | Error::AllVariantsConstructorDeprecated { location } => location.start, Error::UnknownLabels { unknown, .. } => { unknown.iter().map(|(_, s)| s.start).min().unwrap_or(0) } diff --git a/compiler-core/src/type_/tests/custom_types.rs b/compiler-core/src/type_/tests/custom_types.rs index 1878c766fde..ff646c34f2e 100644 --- a/compiler-core/src/type_/tests/custom_types.rs +++ b/compiler-core/src/type_/tests/custom_types.rs @@ -30,6 +30,20 @@ pub fn name() -> String { ); } +#[test] +fn deprecated_all_varients_type() { + assert_module_error!( + r#" +pub type Numbers { + @deprecated("1") + One + @deprecated("2") + Two +} +"# + ); +} + #[test] fn fault_tolerance() { // An error in a custom type does not stop analysis diff --git a/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_all_varients_type.snap b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_all_varients_type.snap new file mode 100644 index 00000000000..1eb9855c7ff --- /dev/null +++ b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_all_varients_type.snap @@ -0,0 +1,18 @@ +--- +source: compiler-core/src/type_/tests/custom_types.rs +assertion_line: 35 +expression: "\npub type Numbers {\n @deprecated(\"1\")\n One\n @deprecated(\"2\")\n Two\n}\n" +--- +error: Can't deprecate all variants of a type. + ┌─ /src/one/two.gleam:2:1 + │ +2 │ pub type Numbers { + │ ^^^^^^^^^^^^^^^^ + +Consider deprecating the type as a whole. + + @deprecated("message") + type Wibble { + Wobble1 + Wobble2 + } From cf4dcbc401a6683541bf29c742130b03ad5bc8ac Mon Sep 17 00:00:00 2001 From: Wilbert-mad Date: Sun, 20 Oct 2024 09:25:43 -0500 Subject: [PATCH 08/21] remove removed snapshot test in parser that was moved to analysis --- ...recation_attribute_on_all_type_variants.snap | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_all_type_variants.snap diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_all_type_variants.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_all_type_variants.snap deleted file mode 100644 index e02e3f916b1..00000000000 --- a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_all_type_variants.snap +++ /dev/null @@ -1,17 +0,0 @@ ---- -source: compiler-core/src/parse/tests.rs -assertion_line: 1512 -expression: "\ntype Wibble {\n @deprecated(\"1\")\n Wibble1\n @deprecated(\"2\")\n Wibble2\n}\n" ---- -error: Syntax error - ┌─ /src/parse/error.gleam:2:1 - │ -2 │ type Wibble { - │ ^^^^^^^^^^^ Can't deprecate all variants of a type. - -Consider deprecating the type as a whole: -@deprecated("message") -type Wibble { - Wobble1 - Wobble2 -} From b13cc8f9b337e9c29a625ed1fb531506d4ab3efb Mon Sep 17 00:00:00 2001 From: Wilbert-mad Date: Tue, 22 Oct 2024 19:04:51 -0500 Subject: [PATCH 09/21] adjust formater --- compiler-core/src/format.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler-core/src/format.rs b/compiler-core/src/format.rs index 21e4e2d07f2..709e69f1d8f 100644 --- a/compiler-core/src/format.rs +++ b/compiler-core/src/format.rs @@ -1566,17 +1566,18 @@ impl<'comments> Formatter<'comments> { ) -> Document<'a> { let comments = self.pop_comments(constructor.location.start); let doc_comments = self.doc_comments(constructor.location.start); + let attributes = AttributesPrinter::new() + .set_deprecation(&constructor.deprecation) + .to_doc(); let doc = if constructor.arguments.is_empty() { if self.any_comments(constructor.location.end) { - constructor - .name - .as_str() - .to_doc() + attributes + .append(constructor.name.as_str().to_doc()) .append(self.wrap_args(vec![], constructor.location.end)) .group() } else { - constructor.name.as_str().to_doc() + attributes.append(constructor.name.as_str().to_doc()) } } else { let args = constructor @@ -1602,10 +1603,9 @@ impl<'comments> Formatter<'comments> { }, ) .collect_vec(); - constructor - .name - .as_str() - .to_doc() + + attributes + .append(constructor.name.as_str().to_doc()) .append(self.wrap_args(args, constructor.location.end)) .group() }; From 110e01dfe4ceba97dabb4e2545dd84346f1ac183 Mon Sep 17 00:00:00 2001 From: Wilbert-mad Date: Tue, 22 Oct 2024 20:15:39 -0500 Subject: [PATCH 10/21] fix formatting --- compiler-core/src/format.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler-core/src/format.rs b/compiler-core/src/format.rs index 709e69f1d8f..5f5efd2e954 100644 --- a/compiler-core/src/format.rs +++ b/compiler-core/src/format.rs @@ -1606,8 +1606,7 @@ impl<'comments> Formatter<'comments> { attributes .append(constructor.name.as_str().to_doc()) - .append(self.wrap_args(args, constructor.location.end)) - .group() + .append(self.wrap_args(args, constructor.location.end).group()) }; commented(doc_comments.append(doc).group(), comments) From 292e9484ab94c60dde17318ad48c810598f0670d Mon Sep 17 00:00:00 2001 From: Wilbert-mad Date: Tue, 22 Oct 2024 22:31:40 -0500 Subject: [PATCH 11/21] lsp & cleanup --- compiler-core/src/analyse.rs | 14 +++++++++++--- compiler-core/src/error.rs | 2 +- compiler-core/src/language_server/engine.rs | 2 +- compiler-core/src/parse.rs | 3 ++- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/compiler-core/src/analyse.rs b/compiler-core/src/analyse.rs index d771c65f9b9..f5915671b23 100644 --- a/compiler-core/src/analyse.rs +++ b/compiler-core/src/analyse.rs @@ -881,7 +881,7 @@ impl<'a, A> ModuleAnalyzer<'a, A> { .clone(); // check if all constructors are deprecated if so error - if constructors.len() > 0 // prevent checking an empty type `type wobble` which will always be true + if !constructors.is_empty() && constructors .iter() .all(|record| record.deprecation.is_deprecated()) @@ -1026,11 +1026,19 @@ impl<'a, A> ModuleAnalyzer<'a, A> { *publicity }; + // If the whole custom type is deprecated all of its varints are too. + // Otherwise just the varint(s) attributed as deprecated are. + let deprecate_constructor = if deprecation.is_deprecated() { + deprecation + } else { + &constructor.deprecation + }; + environment.insert_module_value( constructor.name.clone(), ValueConstructor { publicity: value_constructor_publicity, - deprecation: deprecation.clone(), + deprecation: deprecate_constructor.clone(), type_: type_.clone(), variant: constructor_info.clone(), }, @@ -1054,7 +1062,7 @@ impl<'a, A> ModuleAnalyzer<'a, A> { constructor_info, type_, value_constructor_publicity, - deprecation.clone(), + deprecate_constructor.clone(), ); environment.names.named_constructor_in_scope( diff --git a/compiler-core/src/error.rs b/compiler-core/src/error.rs index 903a052c1b3..fa75cb578cc 100644 --- a/compiler-core/src/error.rs +++ b/compiler-core/src/error.rs @@ -3130,7 +3130,7 @@ Try: _{}", kind_str.to_title_case(), name.to_snake_case()), } }, TypeError::AllVariantsConstructorDeprecated { location } => { - let text = format!("Consider deprecating the type as a whole. + let text = String::from("Consider deprecating the type as a whole. @deprecated(\"message\") type Wibble {{ diff --git a/compiler-core/src/language_server/engine.rs b/compiler-core/src/language_server/engine.rs index de3188abc16..71b0ce0970c 100644 --- a/compiler-core/src/language_server/engine.rs +++ b/compiler-core/src/language_server/engine.rs @@ -729,7 +729,7 @@ fn custom_type_symbol( } else { SymbolKind::CONSTRUCTOR }, - tags: None, + tags: make_deprecated_symbol_tag(&constructor.deprecation), deprecated: None, range: src_span_to_lsp_range(full_constructor_span, line_numbers), selection_range: src_span_to_lsp_range(constructor.name_location, line_numbers), diff --git a/compiler-core/src/parse.rs b/compiler-core/src/parse.rs index 796c6d71e98..7c306fb0f98 100644 --- a/compiler-core/src/parse.rs +++ b/compiler-core/src/parse.rs @@ -2156,7 +2156,8 @@ where || attributes.target.is_some() || attributes.internal != InternalAttribute::Missing) { - let attr_span = attr_loc.unwrap(); + let attr_span = attr_loc + .expect("RecordConstructor musn't be None already checked if None"); return parse_error( ParseErrorType::UnknownAttributeRecordConstructor, attr_span, From 709ef77704388a042abae652c07ad74d723ba015 Mon Sep 17 00:00:00 2001 From: Wilbert-mad Date: Wed, 23 Oct 2024 17:24:29 -0500 Subject: [PATCH 12/21] tests --- compiler-core/src/error.rs | 4 +- compiler-core/src/type_/tests/custom_types.rs | 38 +++++++++++++++++++ ...ed_constructor_deprecate_all_varients.snap | 12 ++++++ ...ustom_types__deprecated_varients_type.snap | 12 ++++++ 4 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__depreacted_constructor_deprecate_all_varients.snap create mode 100644 compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_varients_type.snap diff --git a/compiler-core/src/error.rs b/compiler-core/src/error.rs index fa75cb578cc..8ff1e5fe64d 100644 --- a/compiler-core/src/error.rs +++ b/compiler-core/src/error.rs @@ -3133,10 +3133,10 @@ Try: _{}", kind_str.to_title_case(), name.to_snake_case()), let text = String::from("Consider deprecating the type as a whole. @deprecated(\"message\") - type Wibble {{ + type Wibble { Wobble1 Wobble2 - }} + } "); Diagnostic { title: "Can't deprecate all variants of a type.".into(), diff --git a/compiler-core/src/type_/tests/custom_types.rs b/compiler-core/src/type_/tests/custom_types.rs index ff646c34f2e..6cb35ae8521 100644 --- a/compiler-core/src/type_/tests/custom_types.rs +++ b/compiler-core/src/type_/tests/custom_types.rs @@ -44,6 +44,44 @@ pub type Numbers { ); } +#[test] +fn deprecated_varients_type() { + assert_warning!( + r#" +pub type Numbers { + @deprecated("1") + One + Two +} + +pub fn num() { + let _one = One + let _two = Two + Nil +} +"# + ); +} + +#[test] +fn depreacted_constructor_deprecate_all_varients() { + assert_warning!( + r#" +@deprecated("2") +pub type Numbers { + @deprecated("1") + One + Two +} + +pub fn num() { + let _two = Two + Nil +} +"# + ); +} + #[test] fn fault_tolerance() { // An error in a custom type does not stop analysis diff --git a/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__depreacted_constructor_deprecate_all_varients.snap b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__depreacted_constructor_deprecate_all_varients.snap new file mode 100644 index 00000000000..dfe4b317529 --- /dev/null +++ b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__depreacted_constructor_deprecate_all_varients.snap @@ -0,0 +1,12 @@ +--- +source: compiler-core/src/type_/tests/custom_types.rs +assertion_line: 68 +expression: "\n@deprecated(\"2\")\npub type Numbers {\n @deprecated(\"1\")\n One\n Two\n}\n\npub fn num() {\n let _two = Two\n Nil\n}\n" +--- +warning: Deprecated value used + ┌─ /src/warning/wrn.gleam:10:14 + │ +10 │ let _two = Two + │ ^^^ This value has been deprecated + +It was deprecated with this message: 2 diff --git a/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_varients_type.snap b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_varients_type.snap new file mode 100644 index 00000000000..9e42e9918eb --- /dev/null +++ b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_varients_type.snap @@ -0,0 +1,12 @@ +--- +source: compiler-core/src/type_/tests/custom_types.rs +assertion_line: 49 +expression: "\npub type Numbers {\n @deprecated(\"1\")\n One\n Two\n}\n\npub fn num() {\n let _one = One\n let _two = Two\n Nil\n}\n" +--- +warning: Deprecated value used + ┌─ /src/warning/wrn.gleam:9:14 + │ +9 │ let _one = One + │ ^^^ This value has been deprecated + +It was deprecated with this message: 1 From 03dd50162d0149c313aedfd570a1b33432c2eddf Mon Sep 17 00:00:00 2001 From: Wilbert-mad Date: Sat, 26 Oct 2024 20:01:58 -0500 Subject: [PATCH 13/21] version tracking --- CHANGELOG.md | 22 +++++++++++++++++++ compiler-core/src/analyse.rs | 8 +++++++ compiler-core/src/ast.rs | 1 + compiler-core/src/error.rs | 2 +- compiler-core/src/parse.rs | 2 ++ ...deprecation_attribute_on_type_variant.snap | 10 ++++++++- ..._parse__tests__record_access_no_label.snap | 2 ++ compiler-core/src/type_/error.rs | 2 ++ ...m_types__deprecated_all_varients_type.snap | 2 +- compiler-core/src/warning.rs | 3 +++ 10 files changed, 51 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05f6ff6f953..77b0cb1c46a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,28 @@ ### Compiler +- The compiler now allows deprecating specific constructors of a custom type using the `@deprecated` attribute: + + ```gleam + // Updated `Number` to `RealNumber`s only + pub type RealNumber { + @deprecated("`I` am not a real number") + I + One + // ... + } + + pub fn to_num(n: RealNumber) -> Int { + case n { + I -> calc_i(give: n), // Warning: deprecated value `I` + One -> 1 + // .. + } + } + ``` + + ([Iesha](https://github.com/wilbert-mad)) + - The compiler now prints correctly qualified or aliased type names when printing type errors. diff --git a/compiler-core/src/analyse.rs b/compiler-core/src/analyse.rs index f5915671b23..08ae335ca15 100644 --- a/compiler-core/src/analyse.rs +++ b/compiler-core/src/analyse.rs @@ -833,8 +833,15 @@ impl<'a, A> ModuleAnalyzer<'a, A> { arguments: args, documentation, deprecation: constructor_deprecation, + attributes_location, }| { self.check_name_case(name_location, &name, Named::CustomTypeVariant); + if constructor_deprecation.is_deprecated() { + self.track_feature_usage( + FeatureKind::ConstructorWithDeprecatedAnnotation, + attributes_location.expect("Check value must exist and be deprecated"), + ); + } let preregistered_fn = environment .get_variable(&name) @@ -870,6 +877,7 @@ impl<'a, A> ModuleAnalyzer<'a, A> { arguments: args, documentation, deprecation: constructor_deprecation, + attributes_location, } }, ) diff --git a/compiler-core/src/ast.rs b/compiler-core/src/ast.rs index fd83f898519..1acb00e36e7 100644 --- a/compiler-core/src/ast.rs +++ b/compiler-core/src/ast.rs @@ -233,6 +233,7 @@ pub struct RecordConstructor { pub arguments: Vec>, pub documentation: Option<(u32, EcoString)>, pub deprecation: Deprecation, + pub attributes_location: Option, } impl RecordConstructor { diff --git a/compiler-core/src/error.rs b/compiler-core/src/error.rs index 8ff1e5fe64d..250deb6880e 100644 --- a/compiler-core/src/error.rs +++ b/compiler-core/src/error.rs @@ -3139,7 +3139,7 @@ Try: _{}", kind_str.to_title_case(), name.to_snake_case()), } "); Diagnostic { - title: "Can't deprecate all variants of a type.".into(), + title: "Deprecating all variants of a type is not allowed.".into(), text, hint: None, level: Level::Error, diff --git a/compiler-core/src/parse.rs b/compiler-core/src/parse.rs index 7c306fb0f98..fc425856abc 100644 --- a/compiler-core/src/parse.rs +++ b/compiler-core/src/parse.rs @@ -2168,6 +2168,7 @@ where let documentation = p.take_documentation(c_s); let (args, args_e) = Parser::parse_type_constructor_args(p)?; let end = args_e.max(c_e); + let is_deprecated = attributes.deprecated.is_deprecated(); Ok(Some(RecordConstructor { location: SrcSpan { start: c_s, end }, name_location: SrcSpan { @@ -2178,6 +2179,7 @@ where arguments: args, documentation, deprecation: attributes.deprecated, + attributes_location: if is_deprecated { attr_loc } else { None }, })) } else { Ok(None) diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_type_variant.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_type_variant.snap index 397339a6b33..b2616653d81 100644 --- a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_type_variant.snap +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_type_variant.snap @@ -1,6 +1,6 @@ --- source: compiler-core/src/parse/tests.rs -assertion_line: 1526 +assertion_line: 1512 expression: "\ntype Wibble {\n @deprecated(\"1\")\n Wibble1\n Wibble2\n}\n" --- Parsed { @@ -39,6 +39,12 @@ Parsed { deprecation: Deprecated { message: "1", }, + attributes_location: Some( + SrcSpan { + start: 19, + end: 35, + }, + ), }, RecordConstructor { location: SrcSpan { @@ -53,6 +59,7 @@ Parsed { arguments: [], documentation: None, deprecation: NotDeprecated, + attributes_location: None, }, ], documentation: None, @@ -87,3 +94,4 @@ Parsed { ], }, } + diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__record_access_no_label.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__record_access_no_label.snap index ad0330040fa..3878fb683b3 100644 --- a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__record_access_no_label.snap +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__record_access_no_label.snap @@ -1,5 +1,6 @@ --- source: compiler-core/src/parse/tests.rs +assertion_line: 1150 expression: "\ntype Wibble {\n Wibble(wibble: String)\n}\n\nfn wobble() {\n Wibble(\"a\").\n}\n" --- Parsed { @@ -65,6 +66,7 @@ Parsed { ], documentation: None, deprecation: NotDeprecated, + attributes_location: None, }, ], documentation: None, diff --git a/compiler-core/src/type_/error.rs b/compiler-core/src/type_/error.rs index 70dcf8b5840..6316952185b 100644 --- a/compiler-core/src/type_/error.rs +++ b/compiler-core/src/type_/error.rs @@ -874,6 +874,7 @@ pub enum FeatureKind { AtInJavascriptModules, RecordUpdateVariantInference, RecordAccessVariantInference, + ConstructorWithDeprecatedAnnotation, } impl FeatureKind { @@ -888,6 +889,7 @@ impl FeatureKind { FeatureKind::UnannotatedUtf8StringSegment => Version::new(1, 5, 0), FeatureKind::RecordUpdateVariantInference | FeatureKind::RecordAccessVariantInference => Version::new(1, 6, 0), + FeatureKind::ConstructorWithDeprecatedAnnotation => Version::new(1, 6, 0), } } } diff --git a/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_all_varients_type.snap b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_all_varients_type.snap index 1eb9855c7ff..8f793dc79e5 100644 --- a/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_all_varients_type.snap +++ b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_all_varients_type.snap @@ -3,7 +3,7 @@ source: compiler-core/src/type_/tests/custom_types.rs assertion_line: 35 expression: "\npub type Numbers {\n @deprecated(\"1\")\n One\n @deprecated(\"2\")\n Two\n}\n" --- -error: Can't deprecate all variants of a type. +error: Deprecating all variants of a type is not allowed. ┌─ /src/one/two.gleam:2:1 │ 2 │ pub type Numbers { diff --git a/compiler-core/src/warning.rs b/compiler-core/src/warning.rs index 9196a897120..14f7f5da71e 100644 --- a/compiler-core/src/warning.rs +++ b/compiler-core/src/warning.rs @@ -1033,6 +1033,9 @@ See: https://tour.gleam.run/functions/pipelines/", FeatureKind::RecordAccessVariantInference => { "Field access on custom types when the variant is known was" } + FeatureKind::ConstructorWithDeprecatedAnnotation => { + "The constructor's `@deprecated` annotation was" + } }; Diagnostic { From cc9f6380f8eeb109da4332dae856c748e7d72afd Mon Sep 17 00:00:00 2001 From: Wilbert-mad Date: Mon, 4 Nov 2024 20:25:18 -0600 Subject: [PATCH 14/21] suggested fixes --- CHANGELOG.md | 23 +++++++------- compiler-core/src/analyse.rs | 24 +++++++++++++-- compiler-core/src/ast.rs | 1 - compiler-core/src/error.rs | 30 +++++++++++++++---- compiler-core/src/parse.rs | 24 +++++++-------- ...deprecation_attribute_on_type_variant.snap | 8 ----- ..._parse__tests__record_access_no_label.snap | 1 - compiler-core/src/type_/error.rs | 11 +++++-- compiler-core/src/type_/tests/custom_types.rs | 4 +-- ...epreacted_type_deprecate_varient_err.snap} | 12 ++++---- ...m_types__deprecated_all_varients_type.snap | 10 +++---- 11 files changed, 89 insertions(+), 59 deletions(-) rename compiler-core/src/type_/tests/snapshots/{gleam_core__type___tests__custom_types__depreacted_constructor_deprecate_all_varients.snap => gleam_core__type___tests__custom_types__depreacted_type_deprecate_varient_err.snap} (52%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77b0cb1c46a..1ec2f56445b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,23 +51,20 @@ ### Compiler -- The compiler now allows deprecating specific constructors of a custom type using the `@deprecated` attribute: +- The compiler now allows deprecating specific constructor variants using the `@deprecated` attribute: ```gleam - // Updated `Number` to `RealNumber`s only - pub type RealNumber { - @deprecated("`I` am not a real number") - I - One - // ... + /// from hashing dependency -> + pub type HashAlgor { + @deprecated("unsafe encription") + MD5 + SHA224 + SHA512 } - pub fn to_num(n: RealNumber) -> Int { - case n { - I -> calc_i(give: n), // Warning: deprecated value `I` - One -> 1 - // .. - } + pub fn hash_password(input: String) -> String { + let results = hashing_dep.hash_input(input:, algo: MD5) // warning: MD5 is depreacated + results.hash } ``` diff --git a/compiler-core/src/analyse.rs b/compiler-core/src/analyse.rs index 08ae335ca15..3f6b925de59 100644 --- a/compiler-core/src/analyse.rs +++ b/compiler-core/src/analyse.rs @@ -833,13 +833,12 @@ impl<'a, A> ModuleAnalyzer<'a, A> { arguments: args, documentation, deprecation: constructor_deprecation, - attributes_location, }| { self.check_name_case(name_location, &name, Named::CustomTypeVariant); if constructor_deprecation.is_deprecated() { self.track_feature_usage( FeatureKind::ConstructorWithDeprecatedAnnotation, - attributes_location.expect("Check value must exist and be deprecated"), + location, ); } @@ -877,7 +876,6 @@ impl<'a, A> ModuleAnalyzer<'a, A> { arguments: args, documentation, deprecation: constructor_deprecation, - attributes_location, } }, ) @@ -898,6 +896,26 @@ impl<'a, A> ModuleAnalyzer<'a, A> { .error(Error::AllVariantsConstructorDeprecated { location }); } + // if any constructor record/varient is deprecated while + // the type is deprecated as a whole--is considered an error. + if deprecation.is_deprecated() + && !constructors.is_empty() + && constructors + .iter() + .any(|record| record.deprecation.is_deprecated()) + { + // report error on all variants attibuted with deprecated + constructors + .iter() + .filter(|record| record.deprecation.is_deprecated()) + .for_each(|record| { + self.problems + .error(Error::VariantDeprecatedOnDeprecatedConstructor { + location: record.location, + }); + }); + } + Ok(Definition::CustomType(CustomType { documentation: doc, location, diff --git a/compiler-core/src/ast.rs b/compiler-core/src/ast.rs index 1acb00e36e7..fd83f898519 100644 --- a/compiler-core/src/ast.rs +++ b/compiler-core/src/ast.rs @@ -233,7 +233,6 @@ pub struct RecordConstructor { pub arguments: Vec>, pub documentation: Option<(u32, EcoString)>, pub deprecation: Deprecation, - pub attributes_location: Option, } impl RecordConstructor { diff --git a/compiler-core/src/error.rs b/compiler-core/src/error.rs index 250deb6880e..c7639113e10 100644 --- a/compiler-core/src/error.rs +++ b/compiler-core/src/error.rs @@ -3132,11 +3132,11 @@ Try: _{}", kind_str.to_title_case(), name.to_snake_case()), TypeError::AllVariantsConstructorDeprecated { location } => { let text = String::from("Consider deprecating the type as a whole. - @deprecated(\"message\") - type Wibble { - Wobble1 - Wobble2 - } + @deprecated(\"message\") + type Wibble { + Wobble1 + Wobble2 + } "); Diagnostic { title: "Deprecating all variants of a type is not allowed.".into(), @@ -3154,6 +3154,26 @@ Try: _{}", kind_str.to_title_case(), name.to_snake_case()), }) } } + , + TypeError::VariantDeprecatedOnDeprecatedConstructor{location}=> { + let text = String::from("Consider removing the deprecation attribute on the type's variant."); + + Diagnostic { + title: "Deprecating variants of a type that is deprecated is not allowed".into(), + text, + hint: None, + level: Level::Error, + location: Some(Location { + label: Label { + text: None, + span: *location, + }, + path: path.clone(), + src: src.clone(), + extra_labels: vec![], + }) + } + } } }).collect_vec(), diff --git a/compiler-core/src/parse.rs b/compiler-core/src/parse.rs index fc425856abc..1c85d1448d3 100644 --- a/compiler-core/src/parse.rs +++ b/compiler-core/src/parse.rs @@ -2149,26 +2149,25 @@ where let mut attributes = Attributes::default(); let attr_loc = Parser::parse_attributes(p, &mut attributes)?; - // Expecting all but the deprecated atterbutes to be default - if attr_loc.is_some() // only if attributes are present - && (attributes.external_erlang.is_some() + if let Some(attr_span) = attr_loc { + // Expecting all but the deprecated atterbutes to be default + if attributes.external_erlang.is_some() || attributes.external_javascript.is_some() || attributes.target.is_some() - || attributes.internal != InternalAttribute::Missing) - { - let attr_span = attr_loc - .expect("RecordConstructor musn't be None already checked if None"); - return parse_error( - ParseErrorType::UnknownAttributeRecordConstructor, - attr_span, - ); + || attributes.internal != InternalAttribute::Missing + { + return parse_error( + ParseErrorType::UnknownAttributeRecordConstructor, + attr_span, + ); + } } if let Some((c_s, c_n, c_e)) = Parser::maybe_upname(p) { let documentation = p.take_documentation(c_s); let (args, args_e) = Parser::parse_type_constructor_args(p)?; let end = args_e.max(c_e); - let is_deprecated = attributes.deprecated.is_deprecated(); + // let is_deprecated = attributes.deprecated.is_deprecated(); Ok(Some(RecordConstructor { location: SrcSpan { start: c_s, end }, name_location: SrcSpan { @@ -2179,7 +2178,6 @@ where arguments: args, documentation, deprecation: attributes.deprecated, - attributes_location: if is_deprecated { attr_loc } else { None }, })) } else { Ok(None) diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_type_variant.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_type_variant.snap index b2616653d81..abba03775c8 100644 --- a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_type_variant.snap +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__deprecation_attribute_on_type_variant.snap @@ -39,12 +39,6 @@ Parsed { deprecation: Deprecated { message: "1", }, - attributes_location: Some( - SrcSpan { - start: 19, - end: 35, - }, - ), }, RecordConstructor { location: SrcSpan { @@ -59,7 +53,6 @@ Parsed { arguments: [], documentation: None, deprecation: NotDeprecated, - attributes_location: None, }, ], documentation: None, @@ -94,4 +87,3 @@ Parsed { ], }, } - diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__record_access_no_label.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__record_access_no_label.snap index 3878fb683b3..bca7d937524 100644 --- a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__record_access_no_label.snap +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__record_access_no_label.snap @@ -66,7 +66,6 @@ Parsed { ], documentation: None, deprecation: NotDeprecated, - attributes_location: None, }, ], documentation: None, diff --git a/compiler-core/src/type_/error.rs b/compiler-core/src/type_/error.rs index 6316952185b..bb6d4cb0be2 100644 --- a/compiler-core/src/type_/error.rs +++ b/compiler-core/src/type_/error.rs @@ -562,7 +562,7 @@ pub enum Error { name: EcoString, }, - /// Occers when all the variant type of a custom type are deprecated + /// Occers when all the variant types of a custom type are deprecated /// /// ```gleam /// type Wibble { @@ -575,6 +575,12 @@ pub enum Error { AllVariantsConstructorDeprecated { location: SrcSpan, }, + + /// Occers when any varient of a custom type is deprecated while + /// the custom type itself is deprecated + VariantDeprecatedOnDeprecatedConstructor { + location: SrcSpan, + }, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -989,7 +995,8 @@ impl Error { | Error::UseFnDoesntTakeCallback { location, .. } | Error::UseFnIncorrectArity { location, .. } | Error::BadName { location, .. } - | Error::AllVariantsConstructorDeprecated { location } => location.start, + | Error::AllVariantsConstructorDeprecated { location } + | Error::VariantDeprecatedOnDeprecatedConstructor { location } => location.start, Error::UnknownLabels { unknown, .. } => { unknown.iter().map(|(_, s)| s.start).min().unwrap_or(0) } diff --git a/compiler-core/src/type_/tests/custom_types.rs b/compiler-core/src/type_/tests/custom_types.rs index 6cb35ae8521..adff45a09d3 100644 --- a/compiler-core/src/type_/tests/custom_types.rs +++ b/compiler-core/src/type_/tests/custom_types.rs @@ -64,8 +64,8 @@ pub fn num() { } #[test] -fn depreacted_constructor_deprecate_all_varients() { - assert_warning!( +fn depreacted_type_deprecate_varient_err() { + assert_module_error!( r#" @deprecated("2") pub type Numbers { diff --git a/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__depreacted_constructor_deprecate_all_varients.snap b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__depreacted_type_deprecate_varient_err.snap similarity index 52% rename from compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__depreacted_constructor_deprecate_all_varients.snap rename to compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__depreacted_type_deprecate_varient_err.snap index dfe4b317529..cb843d11d7e 100644 --- a/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__depreacted_constructor_deprecate_all_varients.snap +++ b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__depreacted_type_deprecate_varient_err.snap @@ -3,10 +3,10 @@ source: compiler-core/src/type_/tests/custom_types.rs assertion_line: 68 expression: "\n@deprecated(\"2\")\npub type Numbers {\n @deprecated(\"1\")\n One\n Two\n}\n\npub fn num() {\n let _two = Two\n Nil\n}\n" --- -warning: Deprecated value used - ┌─ /src/warning/wrn.gleam:10:14 - │ -10 │ let _two = Two - │ ^^^ This value has been deprecated +error: Deprecating variants of a type that is deprecated is not allowed + ┌─ /src/one/two.gleam:5:3 + │ +5 │ One + │ ^^^ -It was deprecated with this message: 2 +Consider removing the deprecation attribute on the type's variant. diff --git a/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_all_varients_type.snap b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_all_varients_type.snap index 8f793dc79e5..b59283838ec 100644 --- a/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_all_varients_type.snap +++ b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_all_varients_type.snap @@ -11,8 +11,8 @@ error: Deprecating all variants of a type is not allowed. Consider deprecating the type as a whole. - @deprecated("message") - type Wibble { - Wobble1 - Wobble2 - } + @deprecated("message") + type Wibble { + Wobble1 + Wobble2 + } From 62671abdf2adc351ea7d6f048833c01af6230d53 Mon Sep 17 00:00:00 2001 From: Wilbert-mad Date: Mon, 4 Nov 2024 20:30:00 -0600 Subject: [PATCH 15/21] fix --- CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ec2f56445b..4d157cc2fba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,7 +54,6 @@ - The compiler now allows deprecating specific constructor variants using the `@deprecated` attribute: ```gleam - /// from hashing dependency -> pub type HashAlgor { @deprecated("unsafe encription") MD5 @@ -63,7 +62,7 @@ } pub fn hash_password(input: String) -> String { - let results = hashing_dep.hash_input(input:, algo: MD5) // warning: MD5 is depreacated + let results = hashing_lib.hash_input(input:, algo: MD5) // warning: MD5 is depreacated results.hash } ``` From d1b7f145a933bf1746b8392c61c4fca029ebc5fa Mon Sep 17 00:00:00 2001 From: Wilbert-mad Date: Mon, 4 Nov 2024 20:30:42 -0600 Subject: [PATCH 16/21] fix --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d157cc2fba..64ea6b79efd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,7 +51,7 @@ ### Compiler -- The compiler now allows deprecating specific constructor variants using the `@deprecated` attribute: +- The compiler now allows deprecating specific custome type variants using the `@deprecated` attribute: ```gleam pub type HashAlgor { From be82f56c4b8f1b7644764184109d5340c80db94f Mon Sep 17 00:00:00 2001 From: Wilbert-mad Date: Wed, 6 Nov 2024 18:42:29 -0600 Subject: [PATCH 17/21] fix comments --- compiler-core/src/analyse.rs | 2 +- compiler-core/src/parse.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler-core/src/analyse.rs b/compiler-core/src/analyse.rs index 3f6b925de59..a6641aa98b9 100644 --- a/compiler-core/src/analyse.rs +++ b/compiler-core/src/analyse.rs @@ -897,7 +897,7 @@ impl<'a, A> ModuleAnalyzer<'a, A> { } // if any constructor record/varient is deprecated while - // the type is deprecated as a whole--is considered an error. + // the type is deprecated as a whole that is considered an error. if deprecation.is_deprecated() && !constructors.is_empty() && constructors diff --git a/compiler-core/src/parse.rs b/compiler-core/src/parse.rs index 1c85d1448d3..c50dfc36000 100644 --- a/compiler-core/src/parse.rs +++ b/compiler-core/src/parse.rs @@ -2167,7 +2167,6 @@ where let documentation = p.take_documentation(c_s); let (args, args_e) = Parser::parse_type_constructor_args(p)?; let end = args_e.max(c_e); - // let is_deprecated = attributes.deprecated.is_deprecated(); Ok(Some(RecordConstructor { location: SrcSpan { start: c_s, end }, name_location: SrcSpan { From 035dbbf64b8dc8f5e53294321ce6ddb7f1c645e9 Mon Sep 17 00:00:00 2001 From: Wilbert-mad Date: Sat, 9 Nov 2024 11:38:01 -0600 Subject: [PATCH 18/21] fix: suggested fixes --- compiler-core/src/analyse.rs | 12 +++++----- compiler-core/src/error.rs | 15 +++++++------ compiler-core/src/parse.rs | 2 +- compiler-core/src/parse/error.rs | 19 ++-------------- ...s__external_attribute_on_type_variant.snap | 11 +++++++++- ...s__internal_attribute_on_type_variant.snap | 11 +++++++++- ...deprecation_attribute_on_type_variant.snap | 13 ++++++++++- ...nsupported_attributes_on_type_variant.snap | 13 ++++++++++- ...sts__target_attribute_on_type_variant.snap | 11 +++++++++- compiler-core/src/type_/error.rs | 15 ++++++------- ...depreacted_type_deprecate_varient_err.snap | 22 +++++++++++++++++-- ...m_types__deprecated_all_varients_type.snap | 13 ++++++++++- ...ustom_types__deprecated_varients_type.snap | 16 ++++++++++++++ compiler-core/src/warning.rs | 4 ++-- 14 files changed, 128 insertions(+), 49 deletions(-) diff --git a/compiler-core/src/analyse.rs b/compiler-core/src/analyse.rs index a6641aa98b9..dfafbb9da80 100644 --- a/compiler-core/src/analyse.rs +++ b/compiler-core/src/analyse.rs @@ -837,7 +837,7 @@ impl<'a, A> ModuleAnalyzer<'a, A> { self.check_name_case(name_location, &name, Named::CustomTypeVariant); if constructor_deprecation.is_deprecated() { self.track_feature_usage( - FeatureKind::ConstructorWithDeprecatedAnnotation, + FeatureKind::VariantWithDeprecatedAnnotation, location, ); } @@ -886,17 +886,17 @@ impl<'a, A> ModuleAnalyzer<'a, A> { .parameters .clone(); - // check if all constructors are deprecated if so error + // Check if all constructors are deprecated if so error. if !constructors.is_empty() && constructors .iter() .all(|record| record.deprecation.is_deprecated()) { self.problems - .error(Error::AllVariantsConstructorDeprecated { location }); + .error(Error::AllVariantsDeprecated { location }); } - // if any constructor record/varient is deprecated while + // If any constructor record/varient is deprecated while // the type is deprecated as a whole that is considered an error. if deprecation.is_deprecated() && !constructors.is_empty() @@ -904,13 +904,13 @@ impl<'a, A> ModuleAnalyzer<'a, A> { .iter() .any(|record| record.deprecation.is_deprecated()) { - // report error on all variants attibuted with deprecated + // Report error on all variants attibuted with deprecated constructors .iter() .filter(|record| record.deprecation.is_deprecated()) .for_each(|record| { self.problems - .error(Error::VariantDeprecatedOnDeprecatedConstructor { + .error(Error::DeprecatedVariantOnDeprecatedType { location: record.location, }); }); diff --git a/compiler-core/src/error.rs b/compiler-core/src/error.rs index c7639113e10..ab9ccd9eac3 100644 --- a/compiler-core/src/error.rs +++ b/compiler-core/src/error.rs @@ -3129,7 +3129,7 @@ Try: _{}", kind_str.to_title_case(), name.to_snake_case()), }), } }, - TypeError::AllVariantsConstructorDeprecated { location } => { + TypeError::AllVariantsDeprecated { location } => { let text = String::from("Consider deprecating the type as a whole. @deprecated(\"message\") @@ -3139,7 +3139,7 @@ Try: _{}", kind_str.to_title_case(), name.to_snake_case()), } "); Diagnostic { - title: "Deprecating all variants of a type is not allowed.".into(), + title: "All variants of custom type deprecated.".into(), text, hint: None, level: Level::Error, @@ -3153,13 +3153,14 @@ Try: _{}", kind_str.to_title_case(), name.to_snake_case()), extra_labels: vec![], }) } - } - , - TypeError::VariantDeprecatedOnDeprecatedConstructor{location}=> { - let text = String::from("Consider removing the deprecation attribute on the type's variant."); + }, + TypeError::DeprecatedVariantOnDeprecatedType{ location } => { + let text = wrap("This custom type has already been deprecated, so deprecating \ +one of its variants does nothing. +Consider removing the deprecation attribute on the variant."); Diagnostic { - title: "Deprecating variants of a type that is deprecated is not allowed".into(), + title: "Custom type already deprecated".into(), text, hint: None, level: Level::Error, diff --git a/compiler-core/src/parse.rs b/compiler-core/src/parse.rs index c50dfc36000..1fddcf93242 100644 --- a/compiler-core/src/parse.rs +++ b/compiler-core/src/parse.rs @@ -2157,7 +2157,7 @@ where || attributes.internal != InternalAttribute::Missing { return parse_error( - ParseErrorType::UnknownAttributeRecordConstructor, + ParseErrorType::UnknownAttributeRecordVariant, attr_span, ); } diff --git a/compiler-core/src/parse/error.rs b/compiler-core/src/parse/error.rs index 94b2cc5cecc..d31c125609a 100644 --- a/compiler-core/src/parse/error.rs +++ b/compiler-core/src/parse/error.rs @@ -327,22 +327,7 @@ utf16_codepoint, utf32_codepoint, signed, unsigned, big, little, native, size, u "Hint: If a type is not generic you should omit the `()`.".into(), ], ), - ParseErrorType::UnknownAttributeRecordConstructor => ( - "Variant attribute(s) are unknow.", - vec!["Try `@deprecated`.".into()], - ), - ParseErrorType::AllVariantRecordConstructorDeprecated => ( - "Can't deprecate all variants of a type.", - vec![ - "Consider deprecating the type as a whole:".into(), - "@deprecated(\"message\")".into(), - "type Wibble {".into(), - " Wobble1".into(), - " Wobble2".into(), - "}".into(), - ], - ), - ParseErrorType::UnknownAttributeRecordConstructor => { + ParseErrorType::UnknownAttributeRecordVariant => { ("This attribute cannot be used on a type variant.", vec![]) } } @@ -416,7 +401,7 @@ pub enum ParseErrorType { ConstantRecordConstructorNoArguments, // const x = Record() TypeConstructorNoArguments, // let a : Int() TypeDefinitionNoArguments, // pub type Wibble() { ... } - UnknownAttributeRecordConstructor, // an attribute was used that is not know for a custom type constructor + UnknownAttributeRecordVariant, // an attribute was used that is not know for a custom type variant } impl LexicalError { diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__external_attribute_on_type_variant.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__external_attribute_on_type_variant.snap index ed6d1abdec4..5d027ce4e53 100644 --- a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__external_attribute_on_type_variant.snap +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__external_attribute_on_type_variant.snap @@ -1,8 +1,17 @@ --- source: compiler-core/src/parse/tests.rs -assertion_line: 1577 +assertion_line: 1631 expression: "\ntype Wibble {\n @external(erlang, \"one\", \"two\")\n Wibble1\n}\n" --- +----- SOURCE CODE + +type Wibble { + @external(erlang, "one", "two") + Wibble1 +} + + +----- ERROR error: Syntax error ┌─ /src/parse/error.gleam:3:5 │ diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__internal_attribute_on_type_variant.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__internal_attribute_on_type_variant.snap index 721b445cc9d..47d7f7c1ef7 100644 --- a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__internal_attribute_on_type_variant.snap +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__internal_attribute_on_type_variant.snap @@ -1,8 +1,17 @@ --- source: compiler-core/src/parse/tests.rs -assertion_line: 1565 +assertion_line: 1619 expression: "\ntype Wibble {\n @internal\n Wibble1\n}\n" --- +----- SOURCE CODE + +type Wibble { + @internal + Wibble1 +} + + +----- ERROR error: Syntax error ┌─ /src/parse/error.gleam:3:5 │ diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_deprecation_attribute_on_type_variant.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_deprecation_attribute_on_type_variant.snap index be9923be162..12be640d8f8 100644 --- a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_deprecation_attribute_on_type_variant.snap +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_deprecation_attribute_on_type_variant.snap @@ -1,8 +1,19 @@ --- source: compiler-core/src/parse/tests.rs -assertion_line: 1539 +assertion_line: 1593 expression: "\ntype Wibble {\n @deprecated(\"1\")\n @deprecated(\"2\")\n Wibble1\n Wibble2\n}\n" --- +----- SOURCE CODE + +type Wibble { + @deprecated("1") + @deprecated("2") + Wibble1 + Wibble2 +} + + +----- ERROR error: Syntax error ┌─ /src/parse/error.gleam:4:5 │ diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_unsupported_attributes_on_type_variant.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_unsupported_attributes_on_type_variant.snap index 9bf67052b73..764fd098bfd 100644 --- a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_unsupported_attributes_on_type_variant.snap +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__multiple_unsupported_attributes_on_type_variant.snap @@ -1,8 +1,19 @@ --- source: compiler-core/src/parse/tests.rs -assertion_line: 1589 +assertion_line: 1643 expression: "\ntype Wibble {\n @external(erlang, \"one\", \"two\")\n @target(erlang)\n @internal\n Wibble1\n}\n" --- +----- SOURCE CODE + +type Wibble { + @external(erlang, "one", "two") + @target(erlang) + @internal + Wibble1 +} + + +----- ERROR error: Syntax error ┌─ /src/parse/error.gleam:3:5 │ diff --git a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__target_attribute_on_type_variant.snap b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__target_attribute_on_type_variant.snap index bdf16eeca70..6f9c1a27f81 100644 --- a/compiler-core/src/parse/snapshots/gleam_core__parse__tests__target_attribute_on_type_variant.snap +++ b/compiler-core/src/parse/snapshots/gleam_core__parse__tests__target_attribute_on_type_variant.snap @@ -1,8 +1,17 @@ --- source: compiler-core/src/parse/tests.rs -assertion_line: 1553 +assertion_line: 1607 expression: "\ntype Wibble {\n @target(erlang)\n Wibble2\n}\n" --- +----- SOURCE CODE + +type Wibble { + @target(erlang) + Wibble2 +} + + +----- ERROR error: Syntax error ┌─ /src/parse/error.gleam:3:5 │ diff --git a/compiler-core/src/type_/error.rs b/compiler-core/src/type_/error.rs index bb6d4cb0be2..8bb53fb7f28 100644 --- a/compiler-core/src/type_/error.rs +++ b/compiler-core/src/type_/error.rs @@ -572,13 +572,13 @@ pub enum Error { /// Wobble1 /// } /// ``` - AllVariantsConstructorDeprecated { + AllVariantsDeprecated { location: SrcSpan, }, /// Occers when any varient of a custom type is deprecated while /// the custom type itself is deprecated - VariantDeprecatedOnDeprecatedConstructor { + DeprecatedVariantOnDeprecatedType { location: SrcSpan, }, } @@ -880,7 +880,7 @@ pub enum FeatureKind { AtInJavascriptModules, RecordUpdateVariantInference, RecordAccessVariantInference, - ConstructorWithDeprecatedAnnotation, + VariantWithDeprecatedAnnotation, } impl FeatureKind { @@ -894,12 +894,11 @@ impl FeatureKind { FeatureKind::ConstantStringConcatenation => Version::new(1, 4, 0), FeatureKind::UnannotatedUtf8StringSegment => Version::new(1, 5, 0), FeatureKind::RecordUpdateVariantInference - | FeatureKind::RecordAccessVariantInference => Version::new(1, 6, 0), - FeatureKind::ConstructorWithDeprecatedAnnotation => Version::new(1, 6, 0), + | FeatureKind::RecordAccessVariantInference + | FeatureKind::VariantWithDeprecatedAnnotation => Version::new(1, 6, 0), } } } - #[derive(Debug, Eq, PartialEq, Clone, Copy, serde::Serialize, serde::Deserialize)] pub enum PanicPosition { /// When the unreachable part is a function argument, this means that one @@ -995,8 +994,8 @@ impl Error { | Error::UseFnDoesntTakeCallback { location, .. } | Error::UseFnIncorrectArity { location, .. } | Error::BadName { location, .. } - | Error::AllVariantsConstructorDeprecated { location } - | Error::VariantDeprecatedOnDeprecatedConstructor { location } => location.start, + | Error::AllVariantsDeprecated { location } + | Error::DeprecatedVariantOnDeprecatedType { location } => location.start, Error::UnknownLabels { unknown, .. } => { unknown.iter().map(|(_, s)| s.start).min().unwrap_or(0) } diff --git a/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__depreacted_type_deprecate_varient_err.snap b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__depreacted_type_deprecate_varient_err.snap index cb843d11d7e..047e7ebaa53 100644 --- a/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__depreacted_type_deprecate_varient_err.snap +++ b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__depreacted_type_deprecate_varient_err.snap @@ -3,10 +3,28 @@ source: compiler-core/src/type_/tests/custom_types.rs assertion_line: 68 expression: "\n@deprecated(\"2\")\npub type Numbers {\n @deprecated(\"1\")\n One\n Two\n}\n\npub fn num() {\n let _two = Two\n Nil\n}\n" --- -error: Deprecating variants of a type that is deprecated is not allowed +----- SOURCE CODE + +@deprecated("2") +pub type Numbers { + @deprecated("1") + One + Two +} + +pub fn num() { + let _two = Two + Nil +} + + +----- ERROR +error: Custom type already deprecated ┌─ /src/one/two.gleam:5:3 │ 5 │ One │ ^^^ -Consider removing the deprecation attribute on the type's variant. +This custom type has already been deprecated, so deprecating one of its +variants does nothing. +Consider removing the deprecation attribute on the variant. diff --git a/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_all_varients_type.snap b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_all_varients_type.snap index b59283838ec..7e7aa1ee742 100644 --- a/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_all_varients_type.snap +++ b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_all_varients_type.snap @@ -3,7 +3,18 @@ source: compiler-core/src/type_/tests/custom_types.rs assertion_line: 35 expression: "\npub type Numbers {\n @deprecated(\"1\")\n One\n @deprecated(\"2\")\n Two\n}\n" --- -error: Deprecating all variants of a type is not allowed. +----- SOURCE CODE + +pub type Numbers { + @deprecated("1") + One + @deprecated("2") + Two +} + + +----- ERROR +error: All variants of custom type deprecated. ┌─ /src/one/two.gleam:2:1 │ 2 │ pub type Numbers { diff --git a/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_varients_type.snap b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_varients_type.snap index 9e42e9918eb..6d2dfdce3dd 100644 --- a/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_varients_type.snap +++ b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__custom_types__deprecated_varients_type.snap @@ -3,6 +3,22 @@ source: compiler-core/src/type_/tests/custom_types.rs assertion_line: 49 expression: "\npub type Numbers {\n @deprecated(\"1\")\n One\n Two\n}\n\npub fn num() {\n let _one = One\n let _two = Two\n Nil\n}\n" --- +----- SOURCE CODE + +pub type Numbers { + @deprecated("1") + One + Two +} + +pub fn num() { + let _one = One + let _two = Two + Nil +} + + +----- WARNING warning: Deprecated value used ┌─ /src/warning/wrn.gleam:9:14 │ diff --git a/compiler-core/src/warning.rs b/compiler-core/src/warning.rs index 14f7f5da71e..dc2918e9216 100644 --- a/compiler-core/src/warning.rs +++ b/compiler-core/src/warning.rs @@ -1033,8 +1033,8 @@ See: https://tour.gleam.run/functions/pipelines/", FeatureKind::RecordAccessVariantInference => { "Field access on custom types when the variant is known was" } - FeatureKind::ConstructorWithDeprecatedAnnotation => { - "The constructor's `@deprecated` annotation was" + FeatureKind::VariantWithDeprecatedAnnotation => { + "Deprecating individual custom type variants was" } }; From c12466cf7cf0df901c2b3480a1cdcbeedefa120a Mon Sep 17 00:00:00 2001 From: Wilbert-mad Date: Sun, 10 Nov 2024 22:38:04 -0600 Subject: [PATCH 19/21] fix --- compiler-core/src/parse/error.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler-core/src/parse/error.rs b/compiler-core/src/parse/error.rs index d31c125609a..48b015cf48f 100644 --- a/compiler-core/src/parse/error.rs +++ b/compiler-core/src/parse/error.rs @@ -328,7 +328,8 @@ utf16_codepoint, utf32_codepoint, signed, unsigned, big, little, native, size, u ], ), ParseErrorType::UnknownAttributeRecordVariant => { - ("This attribute cannot be used on a type variant.", vec![]) + "This attribute cannot be used on a variant.", + vec!["Hint: Did you mean `@deprecated`?".into()], } } } From f8280b99c5ac587e5ea4e31cfffd75eb0cf8942e Mon Sep 17 00:00:00 2001 From: Wilbert-mad Date: Sun, 10 Nov 2024 22:39:14 -0600 Subject: [PATCH 20/21] fix --- compiler-core/src/parse/error.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler-core/src/parse/error.rs b/compiler-core/src/parse/error.rs index 48b015cf48f..1440225e2d5 100644 --- a/compiler-core/src/parse/error.rs +++ b/compiler-core/src/parse/error.rs @@ -327,10 +327,10 @@ utf16_codepoint, utf32_codepoint, signed, unsigned, big, little, native, size, u "Hint: If a type is not generic you should omit the `()`.".into(), ], ), - ParseErrorType::UnknownAttributeRecordVariant => { + ParseErrorType::UnknownAttributeRecordVariant => ( "This attribute cannot be used on a variant.", vec!["Hint: Did you mean `@deprecated`?".into()], - } + ), } } } From 1a2407fd1a0501f380228c25484cf0677c4343a3 Mon Sep 17 00:00:00 2001 From: Wilbert-mad Date: Mon, 11 Nov 2024 19:07:30 -0600 Subject: [PATCH 21/21] feature increase version --- compiler-core/src/type_/error.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler-core/src/type_/error.rs b/compiler-core/src/type_/error.rs index 8bb53fb7f28..982ff5669ec 100644 --- a/compiler-core/src/type_/error.rs +++ b/compiler-core/src/type_/error.rs @@ -894,8 +894,8 @@ impl FeatureKind { FeatureKind::ConstantStringConcatenation => Version::new(1, 4, 0), FeatureKind::UnannotatedUtf8StringSegment => Version::new(1, 5, 0), FeatureKind::RecordUpdateVariantInference - | FeatureKind::RecordAccessVariantInference - | FeatureKind::VariantWithDeprecatedAnnotation => Version::new(1, 6, 0), + | FeatureKind::RecordAccessVariantInference => Version::new(1, 6, 0), + FeatureKind::VariantWithDeprecatedAnnotation => Version::new(1, 7, 0), } } }