-
-
Notifications
You must be signed in to change notification settings - Fork 78
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
type_mismatched_generic_lifetimes
lint. (#1039)
It catches structs, enums, and unions that have gained or lost generic lifetime parameters. Using such a type with a mismatching number of generic lifetime parameters is a compile error.
- Loading branch information
1 parent
ea70a4c
commit 649ae53
Showing
7 changed files
with
254 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
SemverQuery( | ||
id: "type_mismatched_generic_lifetimes", | ||
human_readable_name: "type now takes a different number of generic lifetimes", | ||
description: "A type now takes a different number of generic lifetime parameters, breaking uses of that type.", | ||
required_update: Major, | ||
lint_level: Deny, | ||
// The cargo SemVer reference only has entries for generic *type* parameters. | ||
// There's no passable place to link to when it comes to specifically lifetime parameters. | ||
reference_link: None, | ||
query: r#" | ||
{ | ||
CrateDiff { | ||
baseline { | ||
item { | ||
... on ImplOwner { | ||
visibility_limit @filter(op: "=", value: ["$public"]) | ||
name @output | ||
owner_type: __typename @tag @output | ||
importable_path { | ||
path @tag @output | ||
public_api @filter(op: "=", value: ["$true"]) | ||
} | ||
generic_parameter @fold | ||
@transform(op: "count") | ||
@tag(name: "old_lifetimes_count") | ||
@output(name: "old_lifetimes_count") { | ||
... on GenericLifetimeParameter { | ||
old_lifetimes: name @output | ||
} | ||
} | ||
} | ||
} | ||
} | ||
current { | ||
item { | ||
... on ImplOwner { | ||
visibility_limit @filter(op: "=", value: ["$public"]) @output | ||
__typename @filter(op: "=", value: ["%owner_type"]) | ||
importable_path { | ||
path @filter(op: "=", value: ["%path"]) | ||
public_api @filter(op: "=", value: ["$true"]) | ||
} | ||
generic_parameter @fold | ||
@transform(op: "count") | ||
@filter(op: "!=", value: ["%old_lifetimes_count"]) | ||
@output(name: "new_lifetimes_count") { | ||
... on GenericLifetimeParameter { | ||
new_lifetimes: name @output | ||
} | ||
} | ||
span_: span @optional { | ||
filename @output | ||
begin_line @output | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}"#, | ||
arguments: { | ||
"public": "public", | ||
"true": true, | ||
}, | ||
error_message: "A type now takes a different number of generic lifetime parameters. Uses of this type that name the previous number of parameters will be broken.", | ||
per_result_error_template: Some("{{owner_type}} {{name}} ({{old_lifetimes_count}} -> {{new_lifetimes_count}} lifetime params) in {{span_filename}}:{{span_begin_line}}"), | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
[package] | ||
publish = false | ||
name = "type_mismatched_generic_lifetimes" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] |
30 changes: 30 additions & 0 deletions
30
test_crates/type_mismatched_generic_lifetimes/new/src/lib.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
#![allow(dead_code)] | ||
|
||
pub struct Example<'a, 'b, 'c>(&'a i64, &'b i64, &'c i64); | ||
|
||
pub enum Either<'a, 'b, 'c> { | ||
Left(&'a i64), | ||
Right(&'b u64), | ||
Mid(&'c isize), | ||
} | ||
|
||
pub union OneOrTheOther<'a, 'b, 'c> { | ||
left: &'a i64, | ||
right: &'b u64, | ||
center: &'c isize, | ||
} | ||
|
||
// Renaming lifetimes while leaving them semantically identical is not breaking. | ||
// AFAIK there's no way to refer to a lifetime's defined name while using the type. | ||
pub struct RenamedLifetimes<'c, 'a>(&'c i64, &'a i64); | ||
|
||
// Attempting to specify lifetime parameters that don't exist is breaking. | ||
// This should be reported. | ||
pub struct NotGenericAnymore(&'static str); | ||
|
||
// This is breaking too and should be reported. The witness is just wrapping the type | ||
// in another type, at which point all generics must be specified. | ||
/// ```rust,compile_fail | ||
/// struct Witness(type_mismatched_generic_lifetimes::BecameGeneric); | ||
/// ``` | ||
pub struct BecameGeneric<'a>(String, &'a str); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
[package] | ||
publish = false | ||
name = "type_mismatched_generic_lifetimes" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] |
29 changes: 29 additions & 0 deletions
29
test_crates/type_mismatched_generic_lifetimes/old/src/lib.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#![allow(dead_code)] | ||
|
||
pub struct Example<'a, 'b>(&'a i64, &'b i64); | ||
|
||
#[non_exhaustive] | ||
pub enum Either<'a, 'b> { | ||
Left(&'a i64), | ||
Right(&'b u64), | ||
} | ||
|
||
pub union OneOrTheOther<'a, 'b> { | ||
left: &'a i64, | ||
right: &'b u64, | ||
} | ||
|
||
// Renaming lifetimes while leaving them semantically identical is not breaking. | ||
// AFAIK there's no way to refer to a lifetime's defined name while using the type. | ||
pub struct RenamedLifetimes<'a, 'b>(&'a i64, &'b i64); | ||
|
||
// Attempting to specify lifetime parameters that don't exist is breaking. | ||
// This should be reported. | ||
pub struct NotGenericAnymore<'a>(&'a str); | ||
|
||
// This is breaking too and should be reported. The witness is just wrapping the type | ||
// in another type, at which point all generics must be specified. | ||
/// ```rust | ||
/// struct Witness(type_mismatched_generic_lifetimes::BecameGeneric); | ||
/// ``` | ||
pub struct BecameGeneric(String); |
109 changes: 109 additions & 0 deletions
109
test_outputs/query_execution/type_mismatched_generic_lifetimes.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
--- | ||
source: src/query.rs | ||
expression: "&query_execution_results" | ||
snapshot_kind: text | ||
--- | ||
{ | ||
"./test_crates/type_mismatched_generic_lifetimes/": [ | ||
{ | ||
"name": String("Example"), | ||
"new_lifetimes": List([ | ||
String("\'a"), | ||
String("\'b"), | ||
String("\'c"), | ||
]), | ||
"new_lifetimes_count": Uint64(3), | ||
"old_lifetimes": List([ | ||
String("\'a"), | ||
String("\'b"), | ||
]), | ||
"old_lifetimes_count": Uint64(2), | ||
"owner_type": String("Struct"), | ||
"path": List([ | ||
String("type_mismatched_generic_lifetimes"), | ||
String("Example"), | ||
]), | ||
"span_begin_line": Uint64(3), | ||
"span_filename": String("src/lib.rs"), | ||
"visibility_limit": String("public"), | ||
}, | ||
{ | ||
"name": String("Either"), | ||
"new_lifetimes": List([ | ||
String("\'a"), | ||
String("\'b"), | ||
String("\'c"), | ||
]), | ||
"new_lifetimes_count": Uint64(3), | ||
"old_lifetimes": List([ | ||
String("\'a"), | ||
String("\'b"), | ||
]), | ||
"old_lifetimes_count": Uint64(2), | ||
"owner_type": String("Enum"), | ||
"path": List([ | ||
String("type_mismatched_generic_lifetimes"), | ||
String("Either"), | ||
]), | ||
"span_begin_line": Uint64(5), | ||
"span_filename": String("src/lib.rs"), | ||
"visibility_limit": String("public"), | ||
}, | ||
{ | ||
"name": String("OneOrTheOther"), | ||
"new_lifetimes": List([ | ||
String("\'a"), | ||
String("\'b"), | ||
String("\'c"), | ||
]), | ||
"new_lifetimes_count": Uint64(3), | ||
"old_lifetimes": List([ | ||
String("\'a"), | ||
String("\'b"), | ||
]), | ||
"old_lifetimes_count": Uint64(2), | ||
"owner_type": String("Union"), | ||
"path": List([ | ||
String("type_mismatched_generic_lifetimes"), | ||
String("OneOrTheOther"), | ||
]), | ||
"span_begin_line": Uint64(11), | ||
"span_filename": String("src/lib.rs"), | ||
"visibility_limit": String("public"), | ||
}, | ||
{ | ||
"name": String("NotGenericAnymore"), | ||
"new_lifetimes": List([]), | ||
"new_lifetimes_count": Uint64(0), | ||
"old_lifetimes": List([ | ||
String("\'a"), | ||
]), | ||
"old_lifetimes_count": Uint64(1), | ||
"owner_type": String("Struct"), | ||
"path": List([ | ||
String("type_mismatched_generic_lifetimes"), | ||
String("NotGenericAnymore"), | ||
]), | ||
"span_begin_line": Uint64(23), | ||
"span_filename": String("src/lib.rs"), | ||
"visibility_limit": String("public"), | ||
}, | ||
{ | ||
"name": String("BecameGeneric"), | ||
"new_lifetimes": List([ | ||
String("\'a"), | ||
]), | ||
"new_lifetimes_count": Uint64(1), | ||
"old_lifetimes": List([]), | ||
"old_lifetimes_count": Uint64(0), | ||
"owner_type": String("Struct"), | ||
"path": List([ | ||
String("type_mismatched_generic_lifetimes"), | ||
String("BecameGeneric"), | ||
]), | ||
"span_begin_line": Uint64(30), | ||
"span_filename": String("src/lib.rs"), | ||
"visibility_limit": String("public"), | ||
}, | ||
], | ||
} |