From 06b860c8fa74949dcf6be6087900c77e39389791 Mon Sep 17 00:00:00 2001 From: Predrag Gruevski <2348618+obi1kenobi@users.noreply.github.com> Date: Sat, 21 Dec 2024 18:20:16 -0500 Subject: [PATCH] Add matching lints for const-generics breakage in traits. (#1055) Add the `trait_allows_fewer_const_generic_params` and `trait_requires_more_const_generic_params` lints, which check for traits that now require more, or support fewer, const generics than they used to. These are parallel lints to the type-related ones merged shortly prior, just over traits instead of structs/enums/unions. --- ...rait_allows_fewer_const_generic_params.ron | 74 ++++++++++++++++++ ...ait_requires_more_const_generic_params.ron | 75 +++++++++++++++++++ src/query.rs | 2 + .../new/Cargo.toml | 7 ++ .../new/src/lib.rs | 5 ++ .../old/Cargo.toml | 7 ++ .../old/src/lib.rs | 5 ++ .../new/Cargo.toml | 7 ++ .../new/src/lib.rs | 8 ++ .../old/Cargo.toml | 7 ++ .../old/src/lib.rs | 8 ++ ...ait_allows_fewer_const_generic_params.snap | 60 +++++++++++++++ ...it_requires_more_const_generic_params.snap | 57 ++++++++++++++ 13 files changed, 322 insertions(+) create mode 100644 src/lints/trait_allows_fewer_const_generic_params.ron create mode 100644 src/lints/trait_requires_more_const_generic_params.ron create mode 100644 test_crates/trait_allows_fewer_const_generic_params/new/Cargo.toml create mode 100644 test_crates/trait_allows_fewer_const_generic_params/new/src/lib.rs create mode 100644 test_crates/trait_allows_fewer_const_generic_params/old/Cargo.toml create mode 100644 test_crates/trait_allows_fewer_const_generic_params/old/src/lib.rs create mode 100644 test_crates/trait_requires_more_const_generic_params/new/Cargo.toml create mode 100644 test_crates/trait_requires_more_const_generic_params/new/src/lib.rs create mode 100644 test_crates/trait_requires_more_const_generic_params/old/Cargo.toml create mode 100644 test_crates/trait_requires_more_const_generic_params/old/src/lib.rs create mode 100644 test_outputs/query_execution/trait_allows_fewer_const_generic_params.snap create mode 100644 test_outputs/query_execution/trait_requires_more_const_generic_params.snap diff --git a/src/lints/trait_allows_fewer_const_generic_params.ron b/src/lints/trait_allows_fewer_const_generic_params.ron new file mode 100644 index 00000000..9e7c5a3a --- /dev/null +++ b/src/lints/trait_allows_fewer_const_generic_params.ron @@ -0,0 +1,74 @@ +SemverQuery( + id: "trait_allows_fewer_const_generic_params", + human_readable_name: "trait now allows fewer const generic parameters", + description: "A trait now allows fewer const generic parameters than before.", + required_update: Major, + lint_level: Deny, + reference_link: Some("https://doc.rust-lang.org/reference/items/generics.html#const-generics"), + query: r#" + { + CrateDiff { + baseline { + item { + ... on Trait { + visibility_limit @filter(op: "=", value: ["$public"]) + name @output + + importable_path { + path @tag @output + public_api @filter(op: "=", value: ["$true"]) + } + + generic_parameter @fold + @transform(op: "count") + @tag(name: "old_allowed_const_count") + @output(name: "old_allowed_const_count") { + ... on GenericConstParameter { + old_allowed_consts: name @output + } + } + } + } + } + current { + item { + ... on Trait { + visibility_limit @filter(op: "=", value: ["$public"]) @output + + importable_path { + path @filter(op: "=", value: ["%path"]) + public_api @filter(op: "=", value: ["$true"]) + } + + generic_parameter @fold + @transform(op: "count") + @filter(op: "<", value: ["%old_allowed_const_count"]) + @output(name: "new_allowed_const_count") { + ... on GenericConstParameter { + new_allowed_consts: name @output + } + } + + span_: span @optional { + filename @output + begin_line @output + } + } + } + } + } + }"#, + arguments: { + "public": "public", + "true": true, + }, + error_message: "A trait now allows fewer const generic parameters than it used to. Uses of this trait that supplied all previously-supported const generics will be broken.", + per_result_error_template: Some("trait {{name}} allows {{old_allowed_const_count}} -> {{new_allowed_const_count}} const generics in {{span_filename}}:{{span_begin_line}}"), + // TODO: see https://github.com/obi1kenobi/cargo-semver-checks/blob/main/CONTRIBUTING.md#adding-a-witness + // for information about this field. + // + // The witness would be a trait bound with the old number + // of allowed const generics (including ones that provided default values), + // which will be too many generics for the new definition. + witness: None, +) diff --git a/src/lints/trait_requires_more_const_generic_params.ron b/src/lints/trait_requires_more_const_generic_params.ron new file mode 100644 index 00000000..3bd2c3f2 --- /dev/null +++ b/src/lints/trait_requires_more_const_generic_params.ron @@ -0,0 +1,75 @@ +SemverQuery( + id: "trait_requires_more_const_generic_params", + human_readable_name: "trait now requires more const generic parameters", + description: "A trait now requires more const generic parameters than before.", + required_update: Major, + lint_level: Deny, + reference_link: Some("https://doc.rust-lang.org/reference/items/generics.html#const-generics"), + query: r#" + { + CrateDiff { + baseline { + item { + ... on ImplOwner { + visibility_limit @filter(op: "=", value: ["$public"]) + name @output + + importable_path { + path @tag @output + public_api @filter(op: "=", value: ["$true"]) + } + + generic_parameter @fold + @transform(op: "count") + @tag(name: "old_required_const_count") + @output(name: "old_required_const_count") { + ... on GenericConstParameter { + old_required_consts: name @output + has_default @filter(op: "!=", value: ["$true"]) + } + } + } + } + } + current { + item { + ... on ImplOwner { + visibility_limit @filter(op: "=", value: ["$public"]) @output + + importable_path { + path @filter(op: "=", value: ["%path"]) + public_api @filter(op: "=", value: ["$true"]) + } + + generic_parameter @fold + @transform(op: "count") + @filter(op: ">", value: ["%old_required_const_count"]) + @output(name: "new_required_const_count") { + ... on GenericConstParameter { + new_required_consts: name @output + has_default @filter(op: "!=", value: ["$true"]) + } + } + + span_: span @optional { + filename @output + begin_line @output + } + } + } + } + } + }"#, + arguments: { + "public": "public", + "true": true, + }, + error_message: "A trait now requires more const generic parameters than it used to. Uses of this trait that supplied the previously-required number of const generics will be broken. To fix this, consider supplying default values for newly-added const generics.", + per_result_error_template: Some("trait {{name}} ({{old_required_const_count}} -> {{new_required_const_count}} required const generics) in {{span_filename}}:{{span_begin_line}}"), + // TODO: see https://github.com/obi1kenobi/cargo-semver-checks/blob/main/CONTRIBUTING.md#adding-a-witness + // for information about this field. + // + // The witness would be a type ascription with the old number + // of required const generics, which is insufficient for the new definition. + witness: None, +) diff --git a/src/query.rs b/src/query.rs index 1e18f5bd..088ce54f 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1196,6 +1196,7 @@ add_lints!( struct_with_pub_fields_changed_type, struct_with_no_pub_fields_changed_type, trait_added_supertrait, + trait_allows_fewer_const_generic_params, trait_associated_const_added, trait_associated_const_default_removed, trait_associated_const_now_doc_hidden, @@ -1217,6 +1218,7 @@ add_lints!( trait_removed_associated_constant, trait_removed_associated_type, trait_removed_supertrait, + trait_requires_more_const_generic_params, trait_unsafe_added, trait_unsafe_removed, tuple_struct_to_plain_struct, diff --git a/test_crates/trait_allows_fewer_const_generic_params/new/Cargo.toml b/test_crates/trait_allows_fewer_const_generic_params/new/Cargo.toml new file mode 100644 index 00000000..65b07565 --- /dev/null +++ b/test_crates/trait_allows_fewer_const_generic_params/new/Cargo.toml @@ -0,0 +1,7 @@ +[package] +publish = false +name = "trait_allows_fewer_const_generic_params" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/test_crates/trait_allows_fewer_const_generic_params/new/src/lib.rs b/test_crates/trait_allows_fewer_const_generic_params/new/src/lib.rs new file mode 100644 index 00000000..f9e47875 --- /dev/null +++ b/test_crates/trait_allows_fewer_const_generic_params/new/src/lib.rs @@ -0,0 +1,5 @@ +pub trait Example {} + +pub trait NotGenericAnymore {} + +pub trait NotGenericEither {} diff --git a/test_crates/trait_allows_fewer_const_generic_params/old/Cargo.toml b/test_crates/trait_allows_fewer_const_generic_params/old/Cargo.toml new file mode 100644 index 00000000..65b07565 --- /dev/null +++ b/test_crates/trait_allows_fewer_const_generic_params/old/Cargo.toml @@ -0,0 +1,7 @@ +[package] +publish = false +name = "trait_allows_fewer_const_generic_params" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/test_crates/trait_allows_fewer_const_generic_params/old/src/lib.rs b/test_crates/trait_allows_fewer_const_generic_params/old/src/lib.rs new file mode 100644 index 00000000..412adc1a --- /dev/null +++ b/test_crates/trait_allows_fewer_const_generic_params/old/src/lib.rs @@ -0,0 +1,5 @@ +pub trait Example {} + +pub trait NotGenericAnymore {} + +pub trait NotGenericEither {} diff --git a/test_crates/trait_requires_more_const_generic_params/new/Cargo.toml b/test_crates/trait_requires_more_const_generic_params/new/Cargo.toml new file mode 100644 index 00000000..965da1b6 --- /dev/null +++ b/test_crates/trait_requires_more_const_generic_params/new/Cargo.toml @@ -0,0 +1,7 @@ +[package] +publish = false +name = "trait_requires_more_const_generic_params" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/test_crates/trait_requires_more_const_generic_params/new/src/lib.rs b/test_crates/trait_requires_more_const_generic_params/new/src/lib.rs new file mode 100644 index 00000000..d931867f --- /dev/null +++ b/test_crates/trait_requires_more_const_generic_params/new/src/lib.rs @@ -0,0 +1,8 @@ +pub trait NotGeneric {} + +pub trait DefaultBecomesRequired {} + +pub trait ConstGenericAdded {} + +// This one isn't breaking, so it shouldn't be flagged! +pub trait DefaultedConstGenericAdded {} diff --git a/test_crates/trait_requires_more_const_generic_params/old/Cargo.toml b/test_crates/trait_requires_more_const_generic_params/old/Cargo.toml new file mode 100644 index 00000000..965da1b6 --- /dev/null +++ b/test_crates/trait_requires_more_const_generic_params/old/Cargo.toml @@ -0,0 +1,7 @@ +[package] +publish = false +name = "trait_requires_more_const_generic_params" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/test_crates/trait_requires_more_const_generic_params/old/src/lib.rs b/test_crates/trait_requires_more_const_generic_params/old/src/lib.rs new file mode 100644 index 00000000..f7473361 --- /dev/null +++ b/test_crates/trait_requires_more_const_generic_params/old/src/lib.rs @@ -0,0 +1,8 @@ +pub trait NotGeneric {} + +pub trait DefaultBecomesRequired {} + +pub trait ConstGenericAdded {} + +// This one isn't breaking, so it shouldn't be flagged! +pub trait DefaultedConstGenericAdded {} diff --git a/test_outputs/query_execution/trait_allows_fewer_const_generic_params.snap b/test_outputs/query_execution/trait_allows_fewer_const_generic_params.snap new file mode 100644 index 00000000..19119781 --- /dev/null +++ b/test_outputs/query_execution/trait_allows_fewer_const_generic_params.snap @@ -0,0 +1,60 @@ +--- +source: src/query.rs +expression: "&query_execution_results" +snapshot_kind: text +--- +{ + "./test_crates/trait_allows_fewer_const_generic_params/": [ + { + "name": String("Example"), + "new_allowed_const_count": Uint64(1), + "new_allowed_consts": List([ + String("N"), + ]), + "old_allowed_const_count": Uint64(2), + "old_allowed_consts": List([ + String("N"), + String("M"), + ]), + "path": List([ + String("trait_allows_fewer_const_generic_params"), + String("Example"), + ]), + "span_begin_line": Uint64(1), + "span_filename": String("src/lib.rs"), + "visibility_limit": String("public"), + }, + { + "name": String("NotGenericAnymore"), + "new_allowed_const_count": Uint64(0), + "new_allowed_consts": List([]), + "old_allowed_const_count": Uint64(1), + "old_allowed_consts": List([ + String("N"), + ]), + "path": List([ + String("trait_allows_fewer_const_generic_params"), + String("NotGenericAnymore"), + ]), + "span_begin_line": Uint64(3), + "span_filename": String("src/lib.rs"), + "visibility_limit": String("public"), + }, + { + "name": String("NotGenericEither"), + "new_allowed_const_count": Uint64(0), + "new_allowed_consts": List([]), + "old_allowed_const_count": Uint64(1), + "old_allowed_consts": List([ + String("N"), + ]), + "path": List([ + String("trait_allows_fewer_const_generic_params"), + String("NotGenericEither"), + ]), + "span_begin_line": Uint64(5), + "span_filename": String("src/lib.rs"), + "visibility_limit": String("public"), + }, + ], +} diff --git a/test_outputs/query_execution/trait_requires_more_const_generic_params.snap b/test_outputs/query_execution/trait_requires_more_const_generic_params.snap new file mode 100644 index 00000000..b150431d --- /dev/null +++ b/test_outputs/query_execution/trait_requires_more_const_generic_params.snap @@ -0,0 +1,57 @@ +--- +source: src/query.rs +expression: "&query_execution_results" +snapshot_kind: text +--- +{ + "./test_crates/type_requires_more_const_generic_params/": [ + { + "name": String("NotGeneric"), + "new_required_const_count": Uint64(1), + "new_required_consts": List([ + String("COUNT"), + ]), + "old_required_const_count": Uint64(0), + "old_required_consts": List([]), + "path": List([ + String("type_requires_more_const_generic_params"), + String("NotGeneric"), + ]), + "span_begin_line": Uint64(2), + "span_filename": String("src/lib.rs"), + "visibility_limit": String("public"), + }, + { + "name": String("DefaultBecomesRequired"), + "new_required_const_count": Uint64(1), + "new_required_consts": List([ + String("N"), + ]), + "old_required_const_count": Uint64(0), + "old_required_consts": List([]), + "path": List([ + String("type_requires_more_const_generic_params"), + String("DefaultBecomesRequired"), + ]), + "span_begin_line": Uint64(7), + "span_filename": String("src/lib.rs"), + "visibility_limit": String("public"), + }, + { + "name": String("ConstGenericAdded"), + "new_required_const_count": Uint64(1), + "new_required_consts": List([ + String("N"), + ]), + "old_required_const_count": Uint64(0), + "old_required_consts": List([]), + "path": List([ + String("type_requires_more_const_generic_params"), + String("ConstGenericAdded"), + ]), + "span_begin_line": Uint64(12), + "span_filename": String("src/lib.rs"), + "visibility_limit": String("public"), + }, + ], +}