From 3b2436c1361e03d52b4d5d9a188ea94909bd245a Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Tue, 23 Apr 2024 15:49:00 +0200 Subject: [PATCH 01/10] unroll first iter of checked_ilog loop to save one multiplication --- library/core/src/num/uint_macros.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index c13763243f031..a76b84e7e5412 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1093,9 +1093,12 @@ macro_rules! uint_impl { pub const fn checked_ilog(self, base: Self) -> Option { if self <= 0 || base <= 1 { None + } else if self < base { + Some(0) } else { - let mut n = 0; - let mut r = 1; + // Since base >= self, n >= 1 + let mut n = 1; + let mut r = base; // Optimization for 128 bit wide integers. if Self::BITS == 128 { From 245cc23a2f7d55c22437b2482f057fa44cce0624 Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Tue, 23 Apr 2024 18:31:57 +0200 Subject: [PATCH 02/10] add codegen test The test confirms that when val < base, we do not divide or multiply. --- tests/codegen/checked_ilog.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/codegen/checked_ilog.rs diff --git a/tests/codegen/checked_ilog.rs b/tests/codegen/checked_ilog.rs new file mode 100644 index 0000000000000..8f3c07119feeb --- /dev/null +++ b/tests/codegen/checked_ilog.rs @@ -0,0 +1,20 @@ +//@ compile-flags: -O + +#![crate_type = "lib"] + +// Ensure that when val < base, we do not divide or multiply. + +// CHECK-LABEL: @checked_ilog +// CHECK-SAME: (i16 noundef %val, i16 noundef %base) +#[no_mangle] +pub fn checked_ilog(val: u16, base: u16) -> Option { + // CHECK-NOT: udiv + // CHECK-NOT: mul + // CHECK: %[[IS_LESS:.+]] = icmp ult i16 %val, %base + // CHECK-NEXT: br i1 %[[IS_LESS]], label %[[TRUE:.+]], label %[[FALSE:.+]] + // CHECK: [[TRUE]]: + // CHECK-NOT: udiv + // CHECK-NOT: mul + // CHECK: ret { i32, i32 } + val.checked_ilog(base) +} From 0999039edb4e5400ff12cd13f3beac747726c74b Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 26 May 2024 00:17:38 +0000 Subject: [PATCH 03/10] cargo update Locking 15 packages to latest compatible versions Updating cc v1.0.97 -> v1.0.98 Updating crc32fast v1.4.0 -> v1.4.2 Updating crossbeam-channel v0.5.12 -> v0.5.13 Updating crossbeam-utils v0.8.19 -> v0.8.20 Updating getrandom v0.2.14 -> v0.2.15 Updating libz-sys v1.1.16 -> v1.1.18 Updating nu-ansi-term v0.49.0 -> v0.50.0 Updating parking_lot v0.12.2 -> v0.12.3 Updating proc-macro2 v1.0.82 -> v1.0.84 Updating r-efi v4.4.0 -> v4.5.0 Updating serde v1.0.202 -> v1.0.203 Updating serde_derive v1.0.202 -> v1.0.203 Updating spanned v0.2.0 -> v0.2.1 Updating syn v2.0.64 -> v2.0.66 Updating tracing-tree v0.3.0 -> v0.3.1 note: pass `--verbose` to see 80 unchanged dependencies behind latest --- Cargo.lock | 126 ++++++++++++++++++++++++++--------------------------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 92e6a22b4b916..780a9c0fdc571 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -257,7 +257,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -477,9 +477,9 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" [[package]] name = "cfg-if" @@ -593,7 +593,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -620,7 +620,7 @@ dependencies = [ "regex", "rustc_tools_util", "serde", - "syn 2.0.64", + "syn 2.0.66", "tempfile", "termize", "tokio", @@ -730,7 +730,7 @@ dependencies = [ "nom", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -854,18 +854,18 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-channel" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ "crossbeam-utils", ] @@ -891,9 +891,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crypto-common" @@ -966,7 +966,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -977,7 +977,7 @@ checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" dependencies = [ "darling_core", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1003,7 +1003,7 @@ version = "0.1.80" dependencies = [ "itertools 0.12.1", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1044,7 +1044,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1054,7 +1054,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" dependencies = [ "derive_builder_core", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1077,7 +1077,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1166,7 +1166,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1480,7 +1480,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1552,9 +1552,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -1710,7 +1710,7 @@ dependencies = [ "markup5ever 0.12.1", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1842,7 +1842,7 @@ checksum = "d2abdd3a62551e8337af119c5899e600ca0c88ec8f23a46c60ba216c803dcf1a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -2149,9 +2149,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.16" +version = "1.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9" +checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e" dependencies = [ "cc", "libc", @@ -2494,9 +2494,9 @@ dependencies = [ [[package]] name = "nu-ansi-term" -version = "0.49.0" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c073d3c1930d0751774acf49e66653acecb416c3a54c6ec095a9b11caddb5a68" +checksum = "dd2800e1520bdc966782168a627aa5d1ad92e33b984bf7c7615d31280c83ff14" dependencies = [ "windows-sys 0.48.0", ] @@ -2704,9 +2704,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -2786,7 +2786,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -2947,9 +2947,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6" dependencies = [ "unicode-ident", ] @@ -3032,9 +3032,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "4.4.0" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c47196f636c4cc0634b73b0405323d177753c2e15e866952c64ea22902567a34" +checksum = "e9e935efc5854715dfc0a4c9ef18dc69dee0ec3bf9cc3ab740db831c0fdd86a3" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -3835,7 +3835,7 @@ dependencies = [ "fluent-syntax", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "unic-langid", ] @@ -3969,7 +3969,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "synstructure", ] @@ -4116,7 +4116,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "synstructure", ] @@ -4694,7 +4694,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "synstructure", ] @@ -4792,7 +4792,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -4928,22 +4928,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.202" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.202" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -5055,9 +5055,9 @@ dependencies = [ [[package]] name = "spanned" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccdf4f5590b7e6fbd4f2e80d442789079a6fff7c12ef921a9de358b7b353098e" +checksum = "ed14ba8b4b82241bd5daba2c49185d4a0581a0058355fe96537338f002b8605d" dependencies = [ "bstr", "color-eyre", @@ -5237,9 +5237,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.64" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ad3dee41f36859875573074334c200d1add8e4a87bb37113ebd31d926b7b11f" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -5254,7 +5254,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -5399,7 +5399,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -5587,7 +5587,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -5642,11 +5642,11 @@ dependencies = [ [[package]] name = "tracing-tree" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65139ecd2c3f6484c3b99bc01c77afe21e95473630747c7aca525e78b0666675" +checksum = "b56c62d2c80033cb36fae448730a2f2ef99410fe3ecbffc916681a32f6807dbe" dependencies = [ - "nu-ansi-term 0.49.0", + "nu-ansi-term 0.50.0", "tracing-core", "tracing-log", "tracing-subscriber", @@ -5787,7 +5787,7 @@ checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.64", + "syn 2.0.66", "unic-langid-impl", ] @@ -6010,7 +6010,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "wasm-bindgen-shared", ] @@ -6032,7 +6032,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6113,7 +6113,7 @@ dependencies = [ "rayon", "serde", "serde_json", - "syn 2.0.64", + "syn 2.0.66", "windows-metadata", ] @@ -6335,7 +6335,7 @@ checksum = "9e6936f0cce458098a201c245a11bef556c6a0181129c7034d10d76d1ec3a2b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "synstructure", ] @@ -6356,7 +6356,7 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -6376,7 +6376,7 @@ checksum = "e6a647510471d372f2e6c2e6b7219e44d8c574d24fdc11c610a61455782f18c3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "synstructure", ] @@ -6399,5 +6399,5 @@ checksum = "7b4e5997cbf58990550ef1f0e5124a05e47e1ebd33a84af25739be6031a62c20" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] From 974a7f52b5a067147352763367f503fc2565b402 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 7 May 2024 14:12:37 +1000 Subject: [PATCH 04/10] Fix up comments. Wrap overly long ones, etc. --- compiler/rustc_lint/src/builtin.rs | 42 ++++++++++++-------- compiler/rustc_lint/src/context.rs | 3 +- compiler/rustc_lint/src/errors.rs | 2 +- compiler/rustc_lint/src/internal.rs | 14 +++---- compiler/rustc_lint/src/let_underscore.rs | 10 ++--- compiler/rustc_lint/src/levels.rs | 22 +++++----- compiler/rustc_lint/src/methods.rs | 6 +-- compiler/rustc_lint/src/non_local_def.rs | 2 +- compiler/rustc_lint/src/nonstandard_style.rs | 10 ++--- compiler/rustc_lint/src/unused.rs | 9 +++-- 10 files changed, 69 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 85d54ce563d2b..7135615c5a65c 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1494,8 +1494,9 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { let ty = cx.tcx.type_of(item.owner_id).skip_binder(); if ty.has_inherent_projections() { - // Bounds of type aliases that contain opaque types or inherent projections are respected. - // E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`, `type X = Type::Inherent;`. + // Bounds of type aliases that contain opaque types or inherent projections are + // respected. E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`, `type X = + // Type::Inherent;`. return; } @@ -2210,7 +2211,8 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { hir_generics.span.shrink_to_hi().to(where_span) }; - // Due to macro expansions, the `full_where_span` might not actually contain all predicates. + // Due to macro expansions, the `full_where_span` might not actually contain all + // predicates. if where_lint_spans.iter().all(|&sp| full_where_span.contains(sp)) { lint_spans.push(full_where_span); } else { @@ -2587,7 +2589,8 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { }; // So we have at least one potentially inhabited variant. Might we have two? let Some(second_variant) = potential_variants.next() else { - // There is only one potentially inhabited variant. So we can recursively check that variant! + // There is only one potentially inhabited variant. So we can recursively + // check that variant! return variant_find_init_error( cx, ty, @@ -2597,10 +2600,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { init, ); }; - // So we have at least two potentially inhabited variants. - // If we can prove that we have at least two *definitely* inhabited variants, - // then we have a tag and hence leaving this uninit is definitely disallowed. - // (Leaving it zeroed could be okay, depending on which variant is encoded as zero tag.) + // So we have at least two potentially inhabited variants. If we can prove that + // we have at least two *definitely* inhabited variants, then we have a tag and + // hence leaving this uninit is definitely disallowed. (Leaving it zeroed could + // be okay, depending on which variant is encoded as zero tag.) if init == InitKind::Uninit { let definitely_inhabited = (first_variant.1 as usize) + (second_variant.1 as usize) @@ -2811,7 +2814,8 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { let mut found_labels = Vec::new(); - // A semicolon might not actually be specified as a separator for all targets, but it seems like LLVM accepts it always + // A semicolon might not actually be specified as a separator for all targets, but + // it seems like LLVM accepts it always. let statements = template_str.split(|c| matches!(c, '\n' | ';')); for statement in statements { // If there's a comment, trim it from the statement @@ -2824,7 +2828,8 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { let mut chars = possible_label.chars(); let Some(start) = chars.next() else { - // Empty string means a leading ':' in this section, which is not a label. + // Empty string means a leading ':' in this section, which is not a + // label. break 'label_loop; }; @@ -2841,12 +2846,15 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { // Labels continue with ASCII alphanumeric characters, _, or $ for c in chars { - // Inside a template format arg, any character is permitted for the puproses of label detection - // because we assume that it can be replaced with some other valid label string later. - // `options(raw)` asm blocks cannot have format args, so they are excluded from this special case. + // Inside a template format arg, any character is permitted for the + // puproses of label detection because we assume that it can be + // replaced with some other valid label string later. `options(raw)` + // asm blocks cannot have format args, so they are excluded from this + // special case. if !raw && in_bracket { if c == '{' { - // Nested brackets are not allowed in format args, this cannot be a label. + // Nested brackets are not allowed in format args, this cannot + // be a label. break 'label_loop; } @@ -2859,7 +2867,8 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { in_bracket = true; } else { if !(c.is_ascii_alphanumeric() || matches!(c, '_' | '$')) { - // The potential label had an invalid character inside it, it cannot be a label. + // The potential label had an invalid character inside it, it + // cannot be a label. break 'label_loop; } } @@ -2878,7 +2887,8 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { .into_iter() .filter_map(|label| find_label_span(label)) .collect::>(); - // If there were labels but we couldn't find a span, combine the warnings and use the template span + // If there were labels but we couldn't find a span, combine the warnings and + // use the template span. let target_spans: MultiSpan = if spans.len() > 0 { spans.into() } else { (*template_span).into() }; diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index c23a67f613161..13ea7f7fad44d 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -94,7 +94,8 @@ enum TargetLint { /// A lint name that should give no warnings and have no effect. /// - /// This is used by rustc to avoid warning about old rustdoc lints before rustdoc registers them as tool lints. + /// This is used by rustc to avoid warning about old rustdoc lints before rustdoc registers + /// them as tool lints. Ignored, } diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs index c23d1221bc866..46dfaf0b83f95 100644 --- a/compiler/rustc_lint/src/errors.rs +++ b/compiler/rustc_lint/src/errors.rs @@ -16,7 +16,7 @@ pub struct OverruledAttribute<'a> { #[subdiagnostic] pub sub: OverruledAttributeSub, } -// + pub enum OverruledAttributeSub { DefaultSource { id: String }, NodeSource { span: Span, reason: Option }, diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 6e291a327fa68..9110cccdc46f0 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -18,11 +18,11 @@ use rustc_span::Span; use tracing::debug; declare_tool_lint! { - /// The `default_hash_type` lint detects use of [`std::collections::HashMap`]/[`std::collections::HashSet`], - /// suggesting the use of `FxHashMap`/`FxHashSet`. + /// The `default_hash_type` lint detects use of [`std::collections::HashMap`] and + /// [`std::collections::HashSet`], suggesting the use of `FxHashMap`/`FxHashSet`. /// - /// This can help as `FxHasher` can perform better than the default hasher. DOS protection is not - /// required as input is assumed to be trusted. + /// This can help as `FxHasher` can perform better than the default hasher. DOS protection is + /// not required as input is assumed to be trusted. pub rustc::DEFAULT_HASH_TYPES, Allow, "forbid HashMap and HashSet and suggest the FxHash* variants", @@ -35,7 +35,7 @@ impl LateLintPass<'_> for DefaultHashTypes { fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, hir_id: HirId) { let Res::Def(rustc_hir::def::DefKind::Struct, def_id) = path.res else { return }; if matches!(cx.tcx.hir_node(hir_id), Node::Item(Item { kind: ItemKind::Use(..), .. })) { - // don't lint imports, only actual usages + // Don't lint imports, only actual usages. return; } let preferred = match cx.tcx.get_diagnostic_name(def_id) { @@ -75,8 +75,8 @@ declare_tool_lint! { /// potential query instability, such as iterating over a `HashMap`. /// /// Due to the [incremental compilation](https://rustc-dev-guide.rust-lang.org/queries/incremental-compilation.html) model, - /// queries must return deterministic, stable results. `HashMap` iteration order can change between compilations, - /// and will introduce instability if query results expose the order. + /// queries must return deterministic, stable results. `HashMap` iteration order can change + /// between compilations, and will introduce instability if query results expose the order. pub rustc::POTENTIAL_QUERY_INSTABILITY, Allow, "require explicit opt-in when using potentially unstable methods or functions", diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index ea82fb9f26252..e6c274ec09a74 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -113,11 +113,11 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { let mut top_level = true; - // We recursively walk through all patterns, so that we can catch cases where the lock is nested in a pattern. - // For the basic `let_underscore_drop` lint, we only look at the top level, since there are many legitimate reasons - // to bind a sub-pattern to an `_`, if we're only interested in the rest. - // But with locks, we prefer having the chance of "false positives" over missing cases, since the effects can be - // quite catastrophic. + // We recursively walk through all patterns, so that we can catch cases where the lock is + // nested in a pattern. For the basic `let_underscore_drop` lint, we only look at the top + // level, since there are many legitimate reasons to bind a sub-pattern to an `_`, if we're + // only interested in the rest. But with locks, we prefer having the chance of "false + // positives" over missing cases, since the effects can be quite catastrophic. local.pat.walk_always(|pat| { let is_top_level = top_level; top_level = false; diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 98e321076c599..b42b62825d32a 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -750,7 +750,8 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { let level = match Level::from_attr(attr) { None => continue, - // This is the only lint level with a `LintExpectationId` that can be created from an attribute + // This is the only lint level with a `LintExpectationId` that can be created from + // an attribute. Some(Level::Expect(unstable_id)) if let Some(hir_id) = source_hir_id => { let LintExpectationId::Unstable { attr_id, lint_index } = unstable_id else { bug!("stable id Level::from_attr") @@ -760,8 +761,8 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { hir_id, attr_index: attr_index.try_into().unwrap(), lint_index, - // we pass the previous unstable attr_id such that we can trace the ast id when building a map - // to go from unstable to stable id. + // We pass the previous unstable attr_id such that we can trace the ast id + // when building a map to go from unstable to stable id. attr_id: Some(attr_id), }; @@ -860,13 +861,15 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { self.store.check_lint_name(&name, tool_name, self.registered_tools); match &lint_result { CheckLintNameResult::Ok(ids) => { - // This checks for instances where the user writes `#[expect(unfulfilled_lint_expectations)]` - // in that case we want to avoid overriding the lint level but instead add an expectation that - // can't be fulfilled. The lint message will include an explanation, that the + // This checks for instances where the user writes + // `#[expect(unfulfilled_lint_expectations)]` in that case we want to avoid + // overriding the lint level but instead add an expectation that can't be + // fulfilled. The lint message will include an explanation, that the // `unfulfilled_lint_expectations` lint can't be expected. if let Level::Expect(expect_id) = level { - // The `unfulfilled_lint_expectations` lint is not part of any lint groups. Therefore. we - // only need to check the slice if it contains a single lint. + // The `unfulfilled_lint_expectations` lint is not part of any lint + // groups. Therefore. we only need to check the slice if it contains a + // single lint. let is_unfulfilled_lint_expectations = match ids { [lint] => *lint == LintId::of(UNFULFILLED_LINT_EXPECTATIONS), _ => false, @@ -997,7 +1000,8 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { // we don't warn about the name change. if let CheckLintNameResult::Renamed(new_name) = lint_result { // Ignore any errors or warnings that happen because the new name is inaccurate - // NOTE: `new_name` already includes the tool name, so we don't have to add it again. + // NOTE: `new_name` already includes the tool name, so we don't have to add it + // again. let CheckLintNameResult::Ok(ids) = self.store.check_lint_name(&new_name, None, self.registered_tools) else { diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs index b93245d58d9d8..7a71fec769fec 100644 --- a/compiler/rustc_lint/src/methods.rs +++ b/compiler/rustc_lint/src/methods.rs @@ -25,9 +25,9 @@ declare_lint! { /// /// The inner pointer of a `CString` lives only as long as the `CString` it /// points to. Getting the inner pointer of a *temporary* `CString` allows the `CString` - /// to be dropped at the end of the statement, as it is not being referenced as far as the typesystem - /// is concerned. This means outside of the statement the pointer will point to freed memory, which - /// causes undefined behavior if the pointer is later dereferenced. + /// to be dropped at the end of the statement, as it is not being referenced as far as the + /// typesystem is concerned. This means outside of the statement the pointer will point to + /// freed memory, which causes undefined behavior if the pointer is later dereferenced. pub TEMPORARY_CSTRING_AS_PTR, Warn, "detects getting the inner pointer of a temporary `CString`" diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index b3e93748a1665..00e77b505998d 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -259,7 +259,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { } } -// Detecting if the impl definition is leaking outside of it's defining scope. +// Detecting if the impl definition is leaking outside of its defining scope. // // Rule: for each impl, instantiate all local types with inference vars and // then assemble candidates for that goal, if there are more than 1 (non-private diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index dbb0644cd63f6..d64f444716207 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -297,14 +297,14 @@ impl NonSnakeCase { // We cannot provide meaningful suggestions // if the characters are in the category of "Uppercase Letter". let sub = if name != sc { - // We have a valid span in almost all cases, but we don't have one when linting a crate - // name provided via the command line. + // We have a valid span in almost all cases, but we don't have one when linting a + // crate name provided via the command line. if !span.is_dummy() { let sc_ident = Ident::from_str_and_span(&sc, span); if sc_ident.is_reserved() { - // We shouldn't suggest a reserved identifier to fix non-snake-case identifiers. - // Instead, recommend renaming the identifier entirely or, if permitted, - // escaping it to create a raw identifier. + // We shouldn't suggest a reserved identifier to fix non-snake-case + // identifiers. Instead, recommend renaming the identifier entirely or, if + // permitted, escaping it to create a raw identifier. if sc_ident.name.can_be_raw() { NonSnakeCaseDiagSub::RenameOrConvertSuggestion { span, diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index a6993547c8fcf..c8da9f179e711 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -387,7 +387,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } } - // Returns whether further errors should be suppressed because either a lint has been emitted or the type should be ignored. + // Returns whether further errors should be suppressed because either a lint has been + // emitted or the type should be ignored. fn check_must_use_def( cx: &LateContext<'_>, def_id: DefId, @@ -677,7 +678,8 @@ trait UnusedDelimLint { return true; } - // Check if LHS needs parens to prevent false-positives in cases like `fn x() -> u8 { ({ 0 } + 1) }`. + // Check if LHS needs parens to prevent false-positives in cases like + // `fn x() -> u8 { ({ 0 } + 1) }`. // // FIXME: https://github.com/rust-lang/rust/issues/119426 // The syntax tree in this code is from after macro expansion, so the @@ -722,7 +724,8 @@ trait UnusedDelimLint { } } - // Check if RHS needs parens to prevent false-positives in cases like `if (() == return) {}`. + // Check if RHS needs parens to prevent false-positives in cases like `if (() == return) + // {}`. if !followed_by_block { return false; } From 943d3b1560f7985b302c19f8f57806d3b26e93db Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 8 May 2024 10:04:26 +1000 Subject: [PATCH 05/10] Reduce some `pub` exposure. --- compiler/rustc_lint/src/passes.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index d8ba84eb7a1a8..048f7547b01c5 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -237,5 +237,5 @@ macro_rules! declare_combined_early_lint_pass { } /// A lint pass boxed up as a trait object. -pub type EarlyLintPassObject = Box; -pub type LateLintPassObject<'tcx> = Box + 'tcx>; +pub(crate) type EarlyLintPassObject = Box; +pub(crate) type LateLintPassObject<'tcx> = Box + 'tcx>; From f279d3e16fa60b5874f7b8d27720afb686937667 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 7 May 2024 14:37:57 +1000 Subject: [PATCH 06/10] Tweak `CheckLintNameResult::Tool`. It has a clumsy type, with repeated `&'a [LintId]`, and sometimes requires an empty string that isn't used in the `Err`+`None` case. This commit splits it into two variants. --- compiler/rustc_lint/src/context.rs | 37 ++++++++++-------- compiler/rustc_lint/src/levels.rs | 60 +++++++++++++----------------- 2 files changed, 46 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 13ea7f7fad44d..adcd7944f9d01 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -127,12 +127,16 @@ pub enum CheckLintNameResult<'a> { Renamed(String), /// The lint has been removed due to the given reason. Removed(String), - /// The lint is from a tool. If the Option is None, then either - /// the lint does not exist in the tool or the code was not - /// compiled with the tool and therefore the lint was never - /// added to the `LintStore`. Otherwise the `LintId` will be - /// returned as if it where a rustc lint. - Tool(Result<&'a [LintId], (Option<&'a [LintId]>, String)>), + + /// The lint is from a tool. The `LintId` will be returned as if it were a + /// rustc lint. The `Option` indicates if the lint has been + /// renamed. + Tool(&'a [LintId], Option), + + /// The lint is from a tool. Either the lint does not exist in the tool or + /// the code was not compiled with the tool and therefore the lint was + /// never added to the `LintStore`. + MissingTool, } impl LintStore { @@ -385,14 +389,14 @@ impl LintStore { } else { // 2. The tool isn't currently running, so no lints will be registered. // To avoid giving a false positive, ignore all unknown lints. - CheckLintNameResult::Tool(Err((None, String::new()))) + CheckLintNameResult::MissingTool }; } Some(LintGroup { lint_ids, .. }) => { - return CheckLintNameResult::Tool(Ok(lint_ids)); + return CheckLintNameResult::Tool(lint_ids, None); } }, - Some(Id(id)) => return CheckLintNameResult::Tool(Ok(slice::from_ref(id))), + Some(Id(id)) => return CheckLintNameResult::Tool(slice::from_ref(id), None), // If the lint was registered as removed or renamed by the lint tool, we don't need // to treat tool_lints and rustc lints different and can use the code below. _ => {} @@ -412,7 +416,7 @@ impl LintStore { return if *silent { CheckLintNameResult::Ok(lint_ids) } else { - CheckLintNameResult::Tool(Err((Some(lint_ids), (*name).to_string()))) + CheckLintNameResult::Tool(lint_ids, Some((*name).to_string())) }; } CheckLintNameResult::Ok(lint_ids) @@ -473,17 +477,18 @@ impl LintStore { // Reaching this would be weird, but let's cover this case anyway if let Some(LintAlias { name, silent }) = depr { let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap(); - return if *silent { - CheckLintNameResult::Tool(Err((Some(lint_ids), complete_name))) + if *silent { + CheckLintNameResult::Tool(lint_ids, Some(complete_name)) } else { - CheckLintNameResult::Tool(Err((Some(lint_ids), (*name).to_string()))) - }; + CheckLintNameResult::Tool(lint_ids, Some((*name).to_string())) + } + } else { + CheckLintNameResult::Tool(lint_ids, Some(complete_name)) } - CheckLintNameResult::Tool(Err((Some(lint_ids), complete_name))) } }, Some(Id(id)) => { - CheckLintNameResult::Tool(Err((Some(slice::from_ref(id)), complete_name))) + CheckLintNameResult::Tool(slice::from_ref(id), Some(complete_name)) } Some(other) => { debug!("got renamed lint {:?}", other); diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index b42b62825d32a..ad4a2ddb270d9 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -593,7 +593,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { let lint = UnknownLintFromCommandLine { name, suggestion, requested_level }; self.emit_lint(UNKNOWN_LINTS, lint); } - CheckLintNameResult::Tool(Err((Some(_), ref replace))) => { + CheckLintNameResult::Tool(_, Some(ref replace)) => { let name = lint_name.clone(); let requested_level = RequestedLevel { level, lint_name }; let lint = DeprecatedLintNameFromCommandLine { name, replace, requested_level }; @@ -902,32 +902,20 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { } } - CheckLintNameResult::Tool(result) => { - match *result { - Ok(ids) => { + CheckLintNameResult::Tool(ids, new_lint_name) => { + let src = match new_lint_name { + None => { let complete_name = &format!("{}::{}", tool_ident.unwrap().name, name); - let src = LintLevelSource::Node { + LintLevelSource::Node { name: Symbol::intern(complete_name), span: sp, reason, - }; - for &id in ids { - if self.check_gated_lint(id, attr.span, false) { - self.insert_spec(id, (level, src)); - } - } - if let Level::Expect(expect_id) = level { - self.provider.push_expectation( - expect_id, - LintExpectation::new(reason, sp, false, tool_name), - ); } } - Err((Some(ids), ref new_lint_name)) => { - let lint = builtin::RENAMED_AND_REMOVED_LINTS; + Some(new_lint_name) => { self.emit_span_lint( - lint, + builtin::RENAMED_AND_REMOVED_LINTS, sp.into(), DeprecatedLintName { name, @@ -935,29 +923,31 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { replace: new_lint_name, }, ); - - let src = LintLevelSource::Node { + LintLevelSource::Node { name: Symbol::intern(new_lint_name), span: sp, reason, - }; - for id in ids { - self.insert_spec(*id, (level, src)); - } - if let Level::Expect(expect_id) = level { - self.provider.push_expectation( - expect_id, - LintExpectation::new(reason, sp, false, tool_name), - ); } } - Err((None, _)) => { - // If Tool(Err(None, _)) is returned, then either the lint does not - // exist in the tool or the code was not compiled with the tool and - // therefore the lint was never added to the `LintStore`. To detect - // this is the responsibility of the lint tool. + }; + for &id in *ids { + if self.check_gated_lint(id, attr.span, false) { + self.insert_spec(id, (level, src)); } } + if let Level::Expect(expect_id) = level { + self.provider.push_expectation( + expect_id, + LintExpectation::new(reason, sp, false, tool_name), + ); + } + } + + CheckLintNameResult::MissingTool => { + // If `MissingTool` is returned, then either the lint does not + // exist in the tool or the code was not compiled with the tool and + // therefore the lint was never added to the `LintStore`. To detect + // this is the responsibility of the lint tool. } &CheckLintNameResult::NoTool => { From a7e7848833d7a5a3f26249603ba3545ab18e7431 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 31 May 2024 17:02:27 +0200 Subject: [PATCH 07/10] Refactor --print=check-cfg test --- tests/run-make/print-check-cfg/rmake.rs | 150 ++++++++++++++---------- 1 file changed, 86 insertions(+), 64 deletions(-) diff --git a/tests/run-make/print-check-cfg/rmake.rs b/tests/run-make/print-check-cfg/rmake.rs index f7f5fcf2340bb..2d52216442653 100644 --- a/tests/run-make/print-check-cfg/rmake.rs +++ b/tests/run-make/print-check-cfg/rmake.rs @@ -8,61 +8,70 @@ use std::ops::Deref; use run_make_support::rustc; +struct CheckCfg { + args: &'static [&'static str], + contains: Contains, +} + +enum Contains { + Some { contains: &'static [&'static str], doesnt_contain: &'static [&'static str] }, + Only(&'static str), +} + fn main() { - check( - /*args*/ &[], - /*has_any*/ false, - /*has_any_any*/ true, - /*contains*/ &[], - ); - check( - /*args*/ &["--check-cfg=cfg()"], - /*has_any*/ false, - /*has_any_any*/ false, - /*contains*/ &["unix", "miri"], - ); - check( - /*args*/ &["--check-cfg=cfg(any())"], - /*has_any*/ true, - /*has_any_any*/ false, - /*contains*/ &["windows", "test"], - ); - check( - /*args*/ &["--check-cfg=cfg(feature)"], - /*has_any*/ false, - /*has_any_any*/ false, - /*contains*/ &["unix", "miri", "feature"], - ); - check( - /*args*/ &[r#"--check-cfg=cfg(feature, values(none(), "", "test", "lol"))"#], - /*has_any*/ false, - /*has_any_any*/ false, - /*contains*/ &["feature", "feature=\"\"", "feature=\"test\"", "feature=\"lol\""], - ); - check( - /*args*/ - &[ + check(CheckCfg { args: &[], contains: Contains::Only("any()=any()") }); + check(CheckCfg { + args: &["--check-cfg=cfg()"], + contains: Contains::Some { + contains: &["unix", "miri"], + doesnt_contain: &["any()", "any()=any()"], + }, + }); + check(CheckCfg { + args: &["--check-cfg=cfg(any())"], + contains: Contains::Some { + contains: &["any()", "unix", r#"target_feature="crt-static""#], + doesnt_contain: &["any()=any()"], + }, + }); + check(CheckCfg { + args: &["--check-cfg=cfg(feature)"], + contains: Contains::Some { + contains: &["unix", "miri", "feature"], + doesnt_contain: &["any()", "any()=any()", "feature=none()", "feature="], + }, + }); + check(CheckCfg { + args: &[r#"--check-cfg=cfg(feature, values(none(), "", "test", "lol"))"#], + contains: Contains::Some { + contains: &["feature", "feature=\"\"", "feature=\"test\"", "feature=\"lol\""], + doesnt_contain: &["any()", "any()=any()", "feature=none()", "feature="], + }, + }); + check(CheckCfg { + args: &[ r#"--check-cfg=cfg(feature, values(any()))"#, r#"--check-cfg=cfg(feature, values("tmp"))"#, ], - /*has_any*/ false, - /*has_any_any*/ false, - /*contains*/ &["unix", "miri", "feature=any()"], - ); - check( - /*args*/ - &[ + contains: Contains::Some { + contains: &["unix", "miri", "feature=any()"], + doesnt_contain: &["any()", "any()=any()", "feature", "feature=", "feature=\"tmp\""], + }, + }); + check(CheckCfg { + args: &[ r#"--check-cfg=cfg(has_foo, has_bar)"#, r#"--check-cfg=cfg(feature, values("tmp"))"#, r#"--check-cfg=cfg(feature, values("tmp"))"#, ], - /*has_any*/ false, - /*has_any_any*/ false, - /*contains*/ &["has_foo", "has_bar", "feature=\"tmp\""], - ); + contains: Contains::Some { + contains: &["has_foo", "has_bar", "feature=\"tmp\""], + doesnt_contain: &["any()", "any()=any()", "feature"], + }, + }); } -fn check(args: &[&str], has_any: bool, has_any_any: bool, contains: &[&str]) { +fn check(CheckCfg { args, contains }: CheckCfg) { let output = rustc() .input("lib.rs") .arg("-Zunstable-options") @@ -72,18 +81,11 @@ fn check(args: &[&str], has_any: bool, has_any_any: bool, contains: &[&str]) { let stdout = String::from_utf8(output.stdout).unwrap(); - let mut found_any = false; - let mut found_any_any = false; let mut found = HashSet::::new(); - let mut recorded = HashSet::::new(); for l in stdout.lines() { assert!(l == l.trim()); - if l == "any()" { - found_any = true; - } else if l == "any()=any()" { - found_any_any = true; - } else if let Some((left, right)) = l.split_once('=') { + if let Some((left, right)) = l.split_once('=') { if right != "any()" && right != "" { assert!(right.starts_with("\"")); assert!(right.ends_with("\"")); @@ -92,17 +94,37 @@ fn check(args: &[&str], has_any: bool, has_any_any: bool, contains: &[&str]) { } else { assert!(!l.contains("\"")); } - assert!(recorded.insert(l.to_string()), "{}", &l); - if contains.contains(&l) { - assert!(found.insert(l.to_string()), "{}", &l); - } + assert!(found.insert(l.to_string()), "{}", &l); } - let should_found = HashSet::::from_iter(contains.iter().map(|s| s.to_string())); - let diff: Vec<_> = should_found.difference(&found).collect(); - - assert_eq!(found_any, has_any); - assert_eq!(found_any_any, has_any_any); - assert_eq!(found_any_any, recorded.len() == 1); - assert!(diff.is_empty(), "{:?} != {:?} (~ {:?})", &should_found, &found, &diff); + match contains { + Contains::Some { contains, doesnt_contain } => { + { + let should_found = + HashSet::::from_iter(contains.iter().map(|s| s.to_string())); + let diff: Vec<_> = should_found.difference(&found).collect(); + assert!( + diff.is_empty(), + "should found: {:?}, didn't found {:?}", + &should_found, + &diff + ); + } + { + let should_not_find = + HashSet::::from_iter(doesnt_contain.iter().map(|s| s.to_string())); + let diff: Vec<_> = should_not_find.intersection(&found).collect(); + assert!( + diff.is_empty(), + "should not find {:?}, did found {:?}", + &should_not_find, + &diff + ); + } + } + Contains::Only(only) => { + assert!(found.contains(&only.to_string()), "{:?} != {:?}", &only, &found); + assert!(found.len() == 1, "len: {}, instead of 1", found.len()); + } + } } From 5cdec6582a6eab3b66b078cb858294792c096aa8 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sat, 1 Jun 2024 17:19:46 +0300 Subject: [PATCH 08/10] include missing submodule on bootstrap As of https://github.com/rust-lang/rust/pull/125408 PR, rustbook now relies on dependencies from the "src/doc/book" submodule. However, bootstrap does not automatically sync this submodule before reading metadata informations. And if the submodule is not present, reading metadata will fail because rustbook's dependencies will be missing. This change makes "src/doc/book" to be fetched/synced automatically before trying to read metadata. Signed-off-by: onur-ozkan --- src/bootstrap/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 8312885915c53..cde090637e01c 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -469,7 +469,8 @@ impl Build { // Make sure we update these before gathering metadata so we don't get an error about missing // Cargo.toml files. - let rust_submodules = ["src/tools/cargo", "library/backtrace", "library/stdarch"]; + let rust_submodules = + ["src/tools/cargo", "src/doc/book", "library/backtrace", "library/stdarch"]; for s in rust_submodules { build.update_submodule(Path::new(s)); } From ee47480f4cae83279d884d6bcc9e5e6ddf3334b8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 27 May 2024 18:32:17 -0400 Subject: [PATCH 09/10] Yeet PolyFnSig from Interner --- compiler/rustc_middle/src/ty/context.rs | 1 - compiler/rustc_middle/src/ty/structural_impls.rs | 12 ------------ compiler/rustc_type_ir/src/binder.rs | 15 ++++++++++++++- compiler/rustc_type_ir/src/interner.rs | 1 - compiler/rustc_type_ir/src/ty_kind.rs | 2 +- 5 files changed, 15 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c2219fba023bc..30dd887c88a2a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -113,7 +113,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type ErrorGuaranteed = ErrorGuaranteed; type BoundExistentialPredicates = &'tcx List>; - type PolyFnSig = PolyFnSig<'tcx>; type AllocId = crate::mir::interpret::AllocId; type Pat = Pattern<'tcx>; diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index af3aa3b56f7bb..90791bdd20dcd 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -259,18 +259,6 @@ impl<'tcx> DebugWithInfcx> for Region<'tcx> { } } -impl<'tcx, T: DebugWithInfcx>> DebugWithInfcx> for ty::Binder<'tcx, T> { - fn fmt>>( - this: WithInfcx<'_, Infcx, &Self>, - f: &mut core::fmt::Formatter<'_>, - ) -> core::fmt::Result { - f.debug_tuple("Binder") - .field(&this.map(|data| data.as_ref().skip_binder())) - .field(&this.data.bound_vars()) - .finish() - } -} - /////////////////////////////////////////////////////////////////////////// // Atomic structs // diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index e50d59ba5f0e6..9a2c9059967b1 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -8,11 +8,12 @@ use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_serialize::Decodable; use tracing::debug; +use crate::debug::{DebugWithInfcx, WithInfcx}; use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; use crate::inherent::*; use crate::lift::Lift; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; -use crate::{self as ty, Interner, SsoHashSet}; +use crate::{self as ty, InferCtxtLike, Interner, SsoHashSet}; /// Binder is a binder for higher-ranked lifetimes or types. It is part of the /// compiler's representation for things like `for<'a> Fn(&'a isize)` @@ -55,6 +56,18 @@ where } } +impl> DebugWithInfcx for ty::Binder { + fn fmt>( + this: WithInfcx<'_, Infcx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + f.debug_tuple("Binder") + .field(&this.map(|data| data.as_ref().skip_binder())) + .field(&this.data.bound_vars()) + .finish() + } +} + macro_rules! impl_binder_encode_decode { ($($t:ty),+ $(,)?) => { $( diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 2a228c973d34a..ca39318cc0c8b 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -69,7 +69,6 @@ pub trait Interner: // Things stored inside of tys type ErrorGuaranteed: Copy + Debug + Hash + Eq; type BoundExistentialPredicates: Copy + DebugWithInfcx + Hash + Eq; - type PolyFnSig: Copy + DebugWithInfcx + Hash + Eq; type AllocId: Copy + Debug + Hash + Eq; type Pat: Copy + Debug + Hash + Eq + DebugWithInfcx; type Safety: Safety; diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 38082bf3c16fb..aa285169f276d 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -141,7 +141,7 @@ pub enum TyKind { /// fn foo() -> i32 { 1 } /// let bar: fn() -> i32 = foo; /// ``` - FnPtr(I::PolyFnSig), + FnPtr(ty::Binder>), /// A trait object. Written as `dyn for<'b> Trait<'b, Assoc = u32> + Send + 'a`. Dynamic(I::BoundExistentialPredicates, I::Region, DynKind), From 5afdda1a2b8c8f230e62ea2126aad2310783facf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 31 May 2024 14:13:46 -0400 Subject: [PATCH 10/10] Uplift TypeRelation and Relate --- compiler/rustc_borrowck/src/type_check/mod.rs | 5 +- compiler/rustc_codegen_gcc/src/type_of.rs | 2 +- .../src/debuginfo/metadata.rs | 3 +- .../src/debuginfo/metadata/enums/cpp_like.rs | 2 +- .../src/debuginfo/metadata/enums/mod.rs | 2 +- compiler/rustc_codegen_llvm/src/type_of.rs | 2 +- .../src/interpret/discriminant.rs | 2 +- compiler/rustc_middle/src/mir/query.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 4 +- compiler/rustc_middle/src/ty/generic_args.rs | 69 +- compiler/rustc_middle/src/ty/layout.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 6 +- compiler/rustc_middle/src/ty/print/pretty.rs | 7 +- compiler/rustc_middle/src/ty/relate.rs | 22 - compiler/rustc_middle/src/ty/sty.rs | 725 ++---------------- compiler/rustc_mir_transform/src/coroutine.rs | 2 +- compiler/rustc_mir_transform/src/shim.rs | 4 +- compiler/rustc_mir_transform/src/validate.rs | 4 +- .../src/solve/assembly/structural_traits.rs | 8 +- .../rustc_trait_selection/src/traits/util.rs | 8 +- compiler/rustc_ty_utils/src/layout.rs | 3 +- compiler/rustc_type_ir/src/inherent.rs | 28 +- compiler/rustc_type_ir/src/interner.rs | 6 +- compiler/rustc_type_ir/src/predicate.rs | 2 +- compiler/rustc_type_ir/src/ty_kind.rs | 8 +- compiler/rustc_type_ir/src/ty_kind/closure.rs | 696 +++++++++++++++++ .../clippy/clippy_lints/src/eta_reduction.rs | 4 +- 27 files changed, 879 insertions(+), 749 deletions(-) create mode 100644 compiler/rustc_type_ir/src/ty_kind/closure.rs diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index a05fa967af03e..291d2782c32cc 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -27,8 +27,9 @@ use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{ - self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, Dynamic, - OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, + self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CoroutineArgsExt, + Dynamic, OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserType, + UserTypeAnnotationIndex, }; use rustc_middle::ty::{GenericArgsRef, UserArgs}; use rustc_middle::{bug, span_bug}; diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index 2155cabe171c2..a88d50cb43403 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -5,7 +5,7 @@ use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeM use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, Ty, TypeVisitableExt}; +use rustc_middle::ty::{self, CoroutineArgsExt, Ty, TypeVisitableExt}; use rustc_target::abi::call::{CastTarget, FnAbi, Reg}; use rustc_target::abi::{ self, Abi, Align, FieldsShape, Float, Int, Integer, PointeeInfo, Pointer, Size, TyAbiInterface, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 10d3c0d0e7443..a543ccbde0edf 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -31,7 +31,8 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::{ - self, AdtKind, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt, Visibility, + self, AdtKind, CoroutineArgsExt, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt, + Visibility, }; use rustc_session::config::{self, DebugInfo, Lto}; use rustc_span::symbol::Symbol; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs index 4edef14422e5f..12f98eef97d43 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs @@ -12,7 +12,7 @@ use rustc_middle::{ ty::{ self, layout::{LayoutOf, TyAndLayout}, - AdtDef, CoroutineArgs, Ty, + AdtDef, CoroutineArgs, CoroutineArgsExt, Ty, }, }; use rustc_target::abi::{Align, Endian, Size, TagEncoding, VariantIdx, Variants}; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs index bacd74f430f73..2b00bb14593e4 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -10,7 +10,7 @@ use rustc_middle::{ ty::{ self, layout::{IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout}, - AdtDef, CoroutineArgs, Ty, VariantDef, + AdtDef, CoroutineArgs, CoroutineArgsExt, Ty, VariantDef, }, }; use rustc_span::Symbol; diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 011d8ab57c75c..7be941ed74980 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -4,7 +4,7 @@ use rustc_codegen_ssa::traits::*; use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; -use rustc_middle::ty::{self, Ty, TypeVisitableExt}; +use rustc_middle::ty::{self, CoroutineArgsExt, Ty, TypeVisitableExt}; use rustc_target::abi::{Abi, Align, FieldsShape}; use rustc_target::abi::{Float, Int, Pointer}; use rustc_target::abi::{Scalar, Size, Variants}; diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index 224d17dbf52b3..67fbf9642bf0a 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -3,7 +3,7 @@ use rustc_middle::mir; use rustc_middle::span_bug; use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt}; -use rustc_middle::ty::{self, ScalarInt, Ty}; +use rustc_middle::ty::{self, CoroutineArgsExt, ScalarInt, Ty}; use rustc_target::abi::{self, TagEncoding}; use rustc_target::abi::{VariantIdx, Variants}; use tracing::{instrument, trace}; diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 9d70231be3b0c..46b38e4a6a60c 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -1,7 +1,7 @@ //! Values computed by queries that use MIR. use crate::mir; -use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt}; +use crate::ty::{self, CoroutineArgsExt, OpaqueHiddenType, Ty, TyCtxt}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::LocalDefId; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 30dd887c88a2a..47f66c6440627 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -90,7 +90,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type AdtDef = ty::AdtDef<'tcx>; type GenericArgs = ty::GenericArgsRef<'tcx>; - type OwnItemArgs = &'tcx [ty::GenericArg<'tcx>]; + type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>]; type GenericArg = ty::GenericArg<'tcx>; type Term = ty::Term<'tcx>; @@ -190,7 +190,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self, def_id: Self::DefId, args: Self::GenericArgs, - ) -> (rustc_type_ir::TraitRef, Self::OwnItemArgs) { + ) -> (rustc_type_ir::TraitRef, Self::GenericArgsSlice) { assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst); let trait_def_id = self.parent(def_id); assert_matches!(self.def_kind(trait_def_id), DefKind::Trait); diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 7a516b9f2c809..c3ab755175d80 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -2,9 +2,10 @@ use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable}; -use crate::ty::sty::{ClosureArgs, CoroutineArgs, CoroutineClosureArgs, InlineConstArgs}; use crate::ty::visit::{TypeVisitable, TypeVisitor}; -use crate::ty::{self, Lift, List, Ty, TyCtxt}; +use crate::ty::{ + self, ClosureArgs, CoroutineArgs, CoroutineClosureArgs, InlineConstArgs, Lift, List, Ty, TyCtxt, +}; use rustc_ast_ir::visit::VisitorResult; use rustc_ast_ir::walk_visitable_list; @@ -56,6 +57,64 @@ impl<'tcx> rustc_type_ir::inherent::GenericArgs> for ty::GenericArg ) -> ty::GenericArgsRef<'tcx> { ty::GenericArgs::extend_with_error(tcx, def_id, original_args) } + + fn split_closure_args(self) -> ty::ClosureArgsParts> { + match self[..] { + [ref parent_args @ .., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => { + ty::ClosureArgsParts { + parent_args, + closure_kind_ty: closure_kind_ty.expect_ty(), + closure_sig_as_fn_ptr_ty: closure_sig_as_fn_ptr_ty.expect_ty(), + tupled_upvars_ty: tupled_upvars_ty.expect_ty(), + } + } + _ => bug!("closure args missing synthetics"), + } + } + + fn split_coroutine_closure_args(self) -> ty::CoroutineClosureArgsParts> { + match self[..] { + [ + ref parent_args @ .., + closure_kind_ty, + signature_parts_ty, + tupled_upvars_ty, + coroutine_captures_by_ref_ty, + coroutine_witness_ty, + ] => ty::CoroutineClosureArgsParts { + parent_args, + closure_kind_ty: closure_kind_ty.expect_ty(), + signature_parts_ty: signature_parts_ty.expect_ty(), + tupled_upvars_ty: tupled_upvars_ty.expect_ty(), + coroutine_captures_by_ref_ty: coroutine_captures_by_ref_ty.expect_ty(), + coroutine_witness_ty: coroutine_witness_ty.expect_ty(), + }, + _ => bug!("closure args missing synthetics"), + } + } + + fn split_coroutine_args(self) -> ty::CoroutineArgsParts> { + match self[..] { + [ + ref parent_args @ .., + kind_ty, + resume_ty, + yield_ty, + return_ty, + witness, + tupled_upvars_ty, + ] => ty::CoroutineArgsParts { + parent_args, + kind_ty: kind_ty.expect_ty(), + resume_ty: resume_ty.expect_ty(), + yield_ty: yield_ty.expect_ty(), + return_ty: return_ty.expect_ty(), + witness: witness.expect_ty(), + tupled_upvars_ty: tupled_upvars_ty.expect_ty(), + }, + _ => bug!("coroutine args missing synthetics"), + } + } } impl<'tcx> rustc_type_ir::inherent::IntoKind for GenericArg<'tcx> { @@ -295,7 +354,7 @@ impl<'tcx> GenericArgs<'tcx> { /// Closure args have a particular structure controlled by the /// compiler that encodes information like the signature and closure kind; /// see `ty::ClosureArgs` struct for more comments. - pub fn as_closure(&'tcx self) -> ClosureArgs<'tcx> { + pub fn as_closure(&'tcx self) -> ClosureArgs> { ClosureArgs { args: self } } @@ -303,7 +362,7 @@ impl<'tcx> GenericArgs<'tcx> { /// Coroutine-closure args have a particular structure controlled by the /// compiler that encodes information like the signature and closure kind; /// see `ty::CoroutineClosureArgs` struct for more comments. - pub fn as_coroutine_closure(&'tcx self) -> CoroutineClosureArgs<'tcx> { + pub fn as_coroutine_closure(&'tcx self) -> CoroutineClosureArgs> { CoroutineClosureArgs { args: self } } @@ -311,7 +370,7 @@ impl<'tcx> GenericArgs<'tcx> { /// Coroutine args have a particular structure controlled by the /// compiler that encodes information like the signature and coroutine kind; /// see `ty::CoroutineArgs` struct for more comments. - pub fn as_coroutine(&'tcx self) -> CoroutineArgs<'tcx> { + pub fn as_coroutine(&'tcx self) -> CoroutineArgs> { CoroutineArgs { args: self } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 60ce87440328b..3c84ee5e7347f 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2,7 +2,7 @@ use crate::error::UnsupportedFnAbi; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::query::TyCtxtAt; use crate::ty::normalize_erasing_regions::NormalizationError; -use crate::ty::{self, Ty, TyCtxt, TypeVisitableExt}; +use crate::ty::{self, CoroutineArgsExt, Ty, TyCtxt, TypeVisitableExt}; use rustc_error_messages::DiagMessage; use rustc_errors::{ Diag, DiagArgValue, DiagCtxt, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 90c154233dabb..2643ce976ded1 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -113,10 +113,8 @@ pub use self::region::{ pub use self::rvalue_scopes::RvalueScopes; pub use self::sty::{ AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig, - ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, CoroutineClosureArgs, - CoroutineClosureArgsParts, CoroutineClosureSignature, EarlyBinder, FnSig, GenSig, - InlineConstArgs, InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut, - UpvarArgs, VarianceDiagInfo, + CoroutineArgsExt, EarlyBinder, FnSig, InlineConstArgs, InlineConstArgsParts, ParamConst, + ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo, }; pub use self::trait_def::TraitDef; pub use self::typeck_results::{ diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 83790db992600..126da2f5a7c57 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1938,7 +1938,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { Ok(()) } - fn pretty_closure_as_impl(&mut self, closure: ty::ClosureArgs<'tcx>) -> Result<(), PrintError> { + fn pretty_closure_as_impl( + &mut self, + closure: ty::ClosureArgs>, + ) -> Result<(), PrintError> { let sig = closure.sig(); let kind = closure.kind_ty().to_opt_closure_kind().unwrap_or(ty::ClosureKind::Fn); @@ -2973,7 +2976,7 @@ impl<'tcx> ty::PolyTraitPredicate<'tcx> { #[derive(Debug, Copy, Clone, Lift)] pub struct PrintClosureAsImpl<'tcx> { - pub closure: ty::ClosureArgs<'tcx>, + pub closure: ty::ClosureArgs>, } macro_rules! forward_display_to_print { diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index f02b4849f83dd..b417985889094 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -756,28 +756,6 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List> { } } -impl<'tcx> Relate<'tcx> for ty::ClosureArgs<'tcx> { - fn relate>( - relation: &mut R, - a: ty::ClosureArgs<'tcx>, - b: ty::ClosureArgs<'tcx>, - ) -> RelateResult<'tcx, ty::ClosureArgs<'tcx>> { - let args = relate_args_invariantly(relation, a.args, b.args)?; - Ok(ty::ClosureArgs { args }) - } -} - -impl<'tcx> Relate<'tcx> for ty::CoroutineArgs<'tcx> { - fn relate>( - relation: &mut R, - a: ty::CoroutineArgs<'tcx>, - b: ty::CoroutineArgs<'tcx>, - ) -> RelateResult<'tcx, ty::CoroutineArgs<'tcx>> { - let args = relate_args_invariantly(relation, a.args, b.args)?; - Ok(ty::CoroutineArgs { args }) - } -} - impl<'tcx> Relate<'tcx> for GenericArgsRef<'tcx> { fn relate>( relation: &mut R, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 5f7385fccc989..5fcd2105122aa 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -16,7 +16,7 @@ use rustc_errors::{ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::LangItem; -use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable}; +use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable, TypeFoldable}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; @@ -30,7 +30,6 @@ use ty::util::{AsyncDropGlueMorphology, IntTypeExt}; use rustc_type_ir::TyKind::*; use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind}; -use super::fold::FnMutDelegate; use super::GenericParamDefKind; // Re-export and re-parameterize some `I = TyCtxt<'tcx>` types here @@ -60,670 +59,14 @@ impl<'tcx> Article for TyKind<'tcx> { } } -/// A closure can be modeled as a struct that looks like: -/// ```ignore (illustrative) -/// struct Closure<'l0...'li, T0...Tj, CK, CS, U>(...U); -/// ``` -/// where: -/// -/// - 'l0...'li and T0...Tj are the generic parameters -/// in scope on the function that defined the closure, -/// - CK represents the *closure kind* (Fn vs FnMut vs FnOnce). This -/// is rather hackily encoded via a scalar type. See -/// `Ty::to_opt_closure_kind` for details. -/// - CS represents the *closure signature*, representing as a `fn()` -/// type. For example, `fn(u32, u32) -> u32` would mean that the closure -/// implements `CK<(u32, u32), Output = u32>`, where `CK` is the trait -/// specified above. -/// - U is a type parameter representing the types of its upvars, tupled up -/// (borrowed, if appropriate; that is, if a U field represents a by-ref upvar, -/// and the up-var has the type `Foo`, then that field of U will be `&Foo`). -/// -/// So, for example, given this function: -/// ```ignore (illustrative) -/// fn foo<'a, T>(data: &'a mut T) { -/// do(|| data.count += 1) -/// } -/// ``` -/// the type of the closure would be something like: -/// ```ignore (illustrative) -/// struct Closure<'a, T, U>(...U); -/// ``` -/// Note that the type of the upvar is not specified in the struct. -/// You may wonder how the impl would then be able to use the upvar, -/// if it doesn't know it's type? The answer is that the impl is -/// (conceptually) not fully generic over Closure but rather tied to -/// instances with the expected upvar types: -/// ```ignore (illustrative) -/// impl<'b, 'a, T> FnMut() for Closure<'a, T, (&'b mut &'a mut T,)> { -/// ... -/// } -/// ``` -/// You can see that the *impl* fully specified the type of the upvar -/// and thus knows full well that `data` has type `&'b mut &'a mut T`. -/// (Here, I am assuming that `data` is mut-borrowed.) -/// -/// Now, the last question you may ask is: Why include the upvar types -/// in an extra type parameter? The reason for this design is that the -/// upvar types can reference lifetimes that are internal to the -/// creating function. In my example above, for example, the lifetime -/// `'b` represents the scope of the closure itself; this is some -/// subset of `foo`, probably just the scope of the call to the to -/// `do()`. If we just had the lifetime/type parameters from the -/// enclosing function, we couldn't name this lifetime `'b`. Note that -/// there can also be lifetimes in the types of the upvars themselves, -/// if one of them happens to be a reference to something that the -/// creating fn owns. -/// -/// OK, you say, so why not create a more minimal set of parameters -/// that just includes the extra lifetime parameters? The answer is -/// primarily that it would be hard --- we don't know at the time when -/// we create the closure type what the full types of the upvars are, -/// nor do we know which are borrowed and which are not. In this -/// design, we can just supply a fresh type parameter and figure that -/// out later. -/// -/// All right, you say, but why include the type parameters from the -/// original function then? The answer is that codegen may need them -/// when monomorphizing, and they may not appear in the upvars. A -/// closure could capture no variables but still make use of some -/// in-scope type parameter with a bound (e.g., if our example above -/// had an extra `U: Default`, and the closure called `U::default()`). -/// -/// There is another reason. This design (implicitly) prohibits -/// closures from capturing themselves (except via a trait -/// object). This simplifies closure inference considerably, since it -/// means that when we infer the kind of a closure or its upvars, we -/// don't have to handle cycles where the decisions we make for -/// closure C wind up influencing the decisions we ought to make for -/// closure C (which would then require fixed point iteration to -/// handle). Plus it fixes an ICE. :P -/// -/// ## Coroutines -/// -/// Coroutines are handled similarly in `CoroutineArgs`. The set of -/// type parameters is similar, but `CK` and `CS` are replaced by the -/// following type parameters: -/// -/// * `GS`: The coroutine's "resume type", which is the type of the -/// argument passed to `resume`, and the type of `yield` expressions -/// inside the coroutine. -/// * `GY`: The "yield type", which is the type of values passed to -/// `yield` inside the coroutine. -/// * `GR`: The "return type", which is the type of value returned upon -/// completion of the coroutine. -/// * `GW`: The "coroutine witness". -#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable, Lift)] -pub struct ClosureArgs<'tcx> { - /// Lifetime and type parameters from the enclosing function, - /// concatenated with a tuple containing the types of the upvars. - /// - /// These are separated out because codegen wants to pass them around - /// when monomorphizing. - pub args: GenericArgsRef<'tcx>, -} - -/// Struct returned by `split()`. -pub struct ClosureArgsParts<'tcx> { - /// This is the args of the typeck root. - pub parent_args: &'tcx [GenericArg<'tcx>], - /// Represents the maximum calling capability of the closure. - pub closure_kind_ty: Ty<'tcx>, - /// Captures the closure's signature. This closure signature is "tupled", and - /// thus has a peculiar signature of `extern "rust-call" fn((Args, ...)) -> Ty`. - pub closure_sig_as_fn_ptr_ty: Ty<'tcx>, - /// The upvars captured by the closure. Remains an inference variable - /// until the upvar analysis, which happens late in HIR typeck. - pub tupled_upvars_ty: Ty<'tcx>, -} - -impl<'tcx> ClosureArgs<'tcx> { - /// Construct `ClosureArgs` from `ClosureArgsParts`, containing `Args` - /// for the closure parent, alongside additional closure-specific components. - pub fn new(tcx: TyCtxt<'tcx>, parts: ClosureArgsParts<'tcx>) -> ClosureArgs<'tcx> { - ClosureArgs { - args: tcx.mk_args_from_iter(parts.parent_args.iter().copied().chain([ - parts.closure_kind_ty.into(), - parts.closure_sig_as_fn_ptr_ty.into(), - parts.tupled_upvars_ty.into(), - ])), - } - } - - /// Divides the closure args into their respective components. - /// The ordering assumed here must match that used by `ClosureArgs::new` above. - fn split(self) -> ClosureArgsParts<'tcx> { - match self.args[..] { - [ref parent_args @ .., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => { - ClosureArgsParts { - parent_args, - closure_kind_ty: closure_kind_ty.expect_ty(), - closure_sig_as_fn_ptr_ty: closure_sig_as_fn_ptr_ty.expect_ty(), - tupled_upvars_ty: tupled_upvars_ty.expect_ty(), - } - } - _ => bug!("closure args missing synthetics"), - } - } - - /// Returns the generic parameters of the closure's parent. - pub fn parent_args(self) -> &'tcx [GenericArg<'tcx>] { - self.split().parent_args - } - - /// Returns an iterator over the list of types of captured paths by the closure. - /// In case there was a type error in figuring out the types of the captured path, an - /// empty iterator is returned. - #[inline] - pub fn upvar_tys(self) -> &'tcx List> { - match *self.tupled_upvars_ty().kind() { - TyKind::Error(_) => ty::List::empty(), - TyKind::Tuple(tys) => tys, - TyKind::Infer(_) => bug!("upvar_tys called before capture types are inferred"), - ty => bug!("Unexpected representation of upvar types tuple {:?}", ty), - } - } - - /// Returns the tuple type representing the upvars for this closure. - #[inline] - pub fn tupled_upvars_ty(self) -> Ty<'tcx> { - self.split().tupled_upvars_ty - } - - /// Returns the closure kind for this closure; may return a type - /// variable during inference. To get the closure kind during - /// inference, use `infcx.closure_kind(args)`. - pub fn kind_ty(self) -> Ty<'tcx> { - self.split().closure_kind_ty - } - - /// Returns the `fn` pointer type representing the closure signature for this - /// closure. - // FIXME(eddyb) this should be unnecessary, as the shallowly resolved - // type is known at the time of the creation of `ClosureArgs`, - // see `rustc_hir_analysis::check::closure`. - pub fn sig_as_fn_ptr_ty(self) -> Ty<'tcx> { - self.split().closure_sig_as_fn_ptr_ty - } - - /// Returns the closure kind for this closure; only usable outside - /// of an inference context, because in that context we know that - /// there are no type variables. - /// - /// If you have an inference context, use `infcx.closure_kind()`. - pub fn kind(self) -> ty::ClosureKind { - self.kind_ty().to_opt_closure_kind().unwrap() - } - - /// Extracts the signature from the closure. - pub fn sig(self) -> ty::PolyFnSig<'tcx> { - match *self.sig_as_fn_ptr_ty().kind() { - ty::FnPtr(sig) => sig, - ty => bug!("closure_sig_as_fn_ptr_ty is not a fn-ptr: {ty:?}"), - } - } - - pub fn print_as_impl_trait(self) -> ty::print::PrintClosureAsImpl<'tcx> { - ty::print::PrintClosureAsImpl { closure: self } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable, Lift)] -pub struct CoroutineClosureArgs<'tcx> { - pub args: GenericArgsRef<'tcx>, -} - -/// See docs for explanation of how each argument is used. -/// -/// See [`CoroutineClosureSignature`] for how these arguments are put together -/// to make a callable [`FnSig`] suitable for typeck and borrowck. -pub struct CoroutineClosureArgsParts<'tcx> { - /// This is the args of the typeck root. - pub parent_args: &'tcx [GenericArg<'tcx>], - /// Represents the maximum calling capability of the closure. - pub closure_kind_ty: Ty<'tcx>, - /// Represents all of the relevant parts of the coroutine returned by this - /// coroutine-closure. This signature parts type will have the general - /// shape of `fn(tupled_inputs, resume_ty) -> (return_ty, yield_ty)`, where - /// `resume_ty`, `return_ty`, and `yield_ty` are the respective types for the - /// coroutine returned by the coroutine-closure. - /// - /// Use `coroutine_closure_sig` to break up this type rather than using it - /// yourself. - pub signature_parts_ty: Ty<'tcx>, - /// The upvars captured by the closure. Remains an inference variable - /// until the upvar analysis, which happens late in HIR typeck. - pub tupled_upvars_ty: Ty<'tcx>, - /// a function pointer that has the shape `for<'env> fn() -> (&'env T, ...)`. - /// This allows us to represent the binder of the self-captures of the closure. - /// - /// For example, if the coroutine returned by the closure borrows `String` - /// from the closure's upvars, this will be `for<'env> fn() -> (&'env String,)`, - /// while the `tupled_upvars_ty`, representing the by-move version of the same - /// captures, will be `(String,)`. - pub coroutine_captures_by_ref_ty: Ty<'tcx>, - /// Witness type returned by the generator produced by this coroutine-closure. - pub coroutine_witness_ty: Ty<'tcx>, -} - -impl<'tcx> CoroutineClosureArgs<'tcx> { - pub fn new( - tcx: TyCtxt<'tcx>, - parts: CoroutineClosureArgsParts<'tcx>, - ) -> CoroutineClosureArgs<'tcx> { - CoroutineClosureArgs { - args: tcx.mk_args_from_iter(parts.parent_args.iter().copied().chain([ - parts.closure_kind_ty.into(), - parts.signature_parts_ty.into(), - parts.tupled_upvars_ty.into(), - parts.coroutine_captures_by_ref_ty.into(), - parts.coroutine_witness_ty.into(), - ])), - } - } - - fn split(self) -> CoroutineClosureArgsParts<'tcx> { - match self.args[..] { - [ - ref parent_args @ .., - closure_kind_ty, - signature_parts_ty, - tupled_upvars_ty, - coroutine_captures_by_ref_ty, - coroutine_witness_ty, - ] => CoroutineClosureArgsParts { - parent_args, - closure_kind_ty: closure_kind_ty.expect_ty(), - signature_parts_ty: signature_parts_ty.expect_ty(), - tupled_upvars_ty: tupled_upvars_ty.expect_ty(), - coroutine_captures_by_ref_ty: coroutine_captures_by_ref_ty.expect_ty(), - coroutine_witness_ty: coroutine_witness_ty.expect_ty(), - }, - _ => bug!("closure args missing synthetics"), - } - } - - pub fn parent_args(self) -> &'tcx [GenericArg<'tcx>] { - self.split().parent_args - } - - #[inline] - pub fn upvar_tys(self) -> &'tcx List> { - match self.tupled_upvars_ty().kind() { - TyKind::Error(_) => ty::List::empty(), - TyKind::Tuple(..) => self.tupled_upvars_ty().tuple_fields(), - TyKind::Infer(_) => bug!("upvar_tys called before capture types are inferred"), - ty => bug!("Unexpected representation of upvar types tuple {:?}", ty), - } - } - - #[inline] - pub fn tupled_upvars_ty(self) -> Ty<'tcx> { - self.split().tupled_upvars_ty - } - - pub fn kind_ty(self) -> Ty<'tcx> { - self.split().closure_kind_ty - } - - pub fn kind(self) -> ty::ClosureKind { - self.kind_ty().to_opt_closure_kind().unwrap() - } - - pub fn signature_parts_ty(self) -> Ty<'tcx> { - self.split().signature_parts_ty - } - - pub fn coroutine_closure_sig(self) -> Binder<'tcx, CoroutineClosureSignature<'tcx>> { - let interior = self.coroutine_witness_ty(); - let ty::FnPtr(sig) = self.signature_parts_ty().kind() else { bug!() }; - sig.map_bound(|sig| { - let [resume_ty, tupled_inputs_ty] = *sig.inputs() else { - bug!(); - }; - let [yield_ty, return_ty] = **sig.output().tuple_fields() else { bug!() }; - CoroutineClosureSignature { - interior, - tupled_inputs_ty, - resume_ty, - yield_ty, - return_ty, - c_variadic: sig.c_variadic, - safety: sig.safety, - abi: sig.abi, - } - }) - } - - pub fn coroutine_captures_by_ref_ty(self) -> Ty<'tcx> { - self.split().coroutine_captures_by_ref_ty - } - - pub fn coroutine_witness_ty(self) -> Ty<'tcx> { - self.split().coroutine_witness_ty - } - - pub fn has_self_borrows(&self) -> bool { - match self.coroutine_captures_by_ref_ty().kind() { - ty::FnPtr(sig) => sig - .skip_binder() - .visit_with(&mut HasRegionsBoundAt { binder: ty::INNERMOST }) - .is_break(), - ty::Error(_) => true, - _ => bug!(), - } - } -} -/// Unlike `has_escaping_bound_vars` or `outermost_exclusive_binder`, this will -/// detect only regions bound *at* the debruijn index. -struct HasRegionsBoundAt { - binder: ty::DebruijnIndex, -} -// FIXME: Could be optimized to not walk into components with no escaping bound vars. -impl<'tcx> TypeVisitor> for HasRegionsBoundAt { - type Result = ControlFlow<()>; - fn visit_binder>>( - &mut self, - t: &ty::Binder<'tcx, T>, - ) -> Self::Result { - self.binder.shift_in(1); - t.super_visit_with(self)?; - self.binder.shift_out(1); - ControlFlow::Continue(()) - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result { - if let ty::ReBound(binder, _) = *r - && self.binder == binder - { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(()) - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)] -pub struct CoroutineClosureSignature<'tcx> { - pub interior: Ty<'tcx>, - pub tupled_inputs_ty: Ty<'tcx>, - pub resume_ty: Ty<'tcx>, - pub yield_ty: Ty<'tcx>, - pub return_ty: Ty<'tcx>, - - // Like the `fn_sig_as_fn_ptr_ty` of a regular closure, these types - // never actually differ. But we save them rather than recreating them - // from scratch just for good measure. - /// Always false - pub c_variadic: bool, - /// Always [`hir::Safety::Safe`] - pub safety: hir::Safety, - /// Always [`abi::Abi::RustCall`] - pub abi: abi::Abi, -} - -impl<'tcx> CoroutineClosureSignature<'tcx> { - /// Construct a coroutine from the closure signature. Since a coroutine signature - /// is agnostic to the type of generator that is returned (by-ref/by-move), - /// the caller must specify what "flavor" of generator that they'd like to - /// create. Additionally, they must manually compute the upvars of the closure. - /// - /// This helper is not really meant to be used directly except for early on - /// during typeck, when we want to put inference vars into the kind and upvars tys. - /// When the kind and upvars are known, use the other helper functions. - pub fn to_coroutine( - self, - tcx: TyCtxt<'tcx>, - parent_args: &'tcx [GenericArg<'tcx>], - coroutine_kind_ty: Ty<'tcx>, - coroutine_def_id: DefId, - tupled_upvars_ty: Ty<'tcx>, - ) -> Ty<'tcx> { - let coroutine_args = ty::CoroutineArgs::new( - tcx, - ty::CoroutineArgsParts { - parent_args, - kind_ty: coroutine_kind_ty, - resume_ty: self.resume_ty, - yield_ty: self.yield_ty, - return_ty: self.return_ty, - witness: self.interior, - tupled_upvars_ty, - }, - ); - - Ty::new_coroutine(tcx, coroutine_def_id, coroutine_args.args) - } - - /// Given known upvars and a [`ClosureKind`](ty::ClosureKind), compute the coroutine - /// returned by that corresponding async fn trait. - /// - /// This function expects the upvars to have been computed already, and doesn't check - /// that the `ClosureKind` is actually supported by the coroutine-closure. - pub fn to_coroutine_given_kind_and_upvars( - self, - tcx: TyCtxt<'tcx>, - parent_args: &'tcx [GenericArg<'tcx>], - coroutine_def_id: DefId, - goal_kind: ty::ClosureKind, - env_region: ty::Region<'tcx>, - closure_tupled_upvars_ty: Ty<'tcx>, - coroutine_captures_by_ref_ty: Ty<'tcx>, - ) -> Ty<'tcx> { - let tupled_upvars_ty = Self::tupled_upvars_by_closure_kind( - tcx, - goal_kind, - self.tupled_inputs_ty, - closure_tupled_upvars_ty, - coroutine_captures_by_ref_ty, - env_region, - ); - - self.to_coroutine( - tcx, - parent_args, - Ty::from_coroutine_closure_kind(tcx, goal_kind), - coroutine_def_id, - tupled_upvars_ty, - ) - } - - /// Compute the tupled upvars that a coroutine-closure's output coroutine - /// would return for the given `ClosureKind`. - /// - /// When `ClosureKind` is `FnMut`/`Fn`, then this will use the "captures by ref" - /// to return a set of upvars which are borrowed with the given `env_region`. - /// - /// This ensures that the `AsyncFn::call` will return a coroutine whose upvars' - /// lifetimes are related to the lifetime of the borrow on the closure made for - /// the call. This allows borrowck to enforce the self-borrows correctly. - pub fn tupled_upvars_by_closure_kind( - tcx: TyCtxt<'tcx>, - kind: ty::ClosureKind, - tupled_inputs_ty: Ty<'tcx>, - closure_tupled_upvars_ty: Ty<'tcx>, - coroutine_captures_by_ref_ty: Ty<'tcx>, - env_region: ty::Region<'tcx>, - ) -> Ty<'tcx> { - match kind { - ty::ClosureKind::Fn | ty::ClosureKind::FnMut => { - let ty::FnPtr(sig) = *coroutine_captures_by_ref_ty.kind() else { - bug!(); - }; - let coroutine_captures_by_ref_ty = tcx.replace_escaping_bound_vars_uncached( - sig.output().skip_binder(), - FnMutDelegate { - consts: &mut |c, t| ty::Const::new_bound(tcx, ty::INNERMOST, c, t), - types: &mut |t| Ty::new_bound(tcx, ty::INNERMOST, t), - regions: &mut |_| env_region, - }, - ); - Ty::new_tup_from_iter( - tcx, - tupled_inputs_ty - .tuple_fields() - .iter() - .chain(coroutine_captures_by_ref_ty.tuple_fields()), - ) - } - ty::ClosureKind::FnOnce => Ty::new_tup_from_iter( - tcx, - tupled_inputs_ty - .tuple_fields() - .iter() - .chain(closure_tupled_upvars_ty.tuple_fields()), - ), - } - } -} -/// Similar to `ClosureArgs`; see the above documentation for more. -#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)] -pub struct CoroutineArgs<'tcx> { - pub args: GenericArgsRef<'tcx>, -} - -pub struct CoroutineArgsParts<'tcx> { - /// This is the args of the typeck root. - pub parent_args: &'tcx [GenericArg<'tcx>], - - /// The coroutines returned by a coroutine-closure's `AsyncFnOnce`/`AsyncFnMut` - /// implementations must be distinguished since the former takes the closure's - /// upvars by move, and the latter takes the closure's upvars by ref. - /// - /// This field distinguishes these fields so that codegen can select the right - /// body for the coroutine. This has the same type representation as the closure - /// kind: `i8`/`i16`/`i32`. - /// - /// For regular coroutines, this field will always just be `()`. - pub kind_ty: Ty<'tcx>, - - pub resume_ty: Ty<'tcx>, - pub yield_ty: Ty<'tcx>, - pub return_ty: Ty<'tcx>, - - /// The interior type of the coroutine. - /// Represents all types that are stored in locals - /// in the coroutine's body. - pub witness: Ty<'tcx>, - - /// The upvars captured by the closure. Remains an inference variable - /// until the upvar analysis, which happens late in HIR typeck. - pub tupled_upvars_ty: Ty<'tcx>, -} - -impl<'tcx> CoroutineArgs<'tcx> { - /// Construct `CoroutineArgs` from `CoroutineArgsParts`, containing `Args` - /// for the coroutine parent, alongside additional coroutine-specific components. - pub fn new(tcx: TyCtxt<'tcx>, parts: CoroutineArgsParts<'tcx>) -> CoroutineArgs<'tcx> { - CoroutineArgs { - args: tcx.mk_args_from_iter(parts.parent_args.iter().copied().chain([ - parts.kind_ty.into(), - parts.resume_ty.into(), - parts.yield_ty.into(), - parts.return_ty.into(), - parts.witness.into(), - parts.tupled_upvars_ty.into(), - ])), - } - } - - /// Divides the coroutine args into their respective components. - /// The ordering assumed here must match that used by `CoroutineArgs::new` above. - fn split(self) -> CoroutineArgsParts<'tcx> { - match self.args[..] { - [ - ref parent_args @ .., - kind_ty, - resume_ty, - yield_ty, - return_ty, - witness, - tupled_upvars_ty, - ] => CoroutineArgsParts { - parent_args, - kind_ty: kind_ty.expect_ty(), - resume_ty: resume_ty.expect_ty(), - yield_ty: yield_ty.expect_ty(), - return_ty: return_ty.expect_ty(), - witness: witness.expect_ty(), - tupled_upvars_ty: tupled_upvars_ty.expect_ty(), - }, - _ => bug!("coroutine args missing synthetics"), - } - } - - /// Returns the generic parameters of the coroutine's parent. - pub fn parent_args(self) -> &'tcx [GenericArg<'tcx>] { - self.split().parent_args - } - - // Returns the kind of the coroutine. See docs on the `kind_ty` field. - pub fn kind_ty(self) -> Ty<'tcx> { - self.split().kind_ty - } - - /// This describes the types that can be contained in a coroutine. - /// It will be a type variable initially and unified in the last stages of typeck of a body. - /// It contains a tuple of all the types that could end up on a coroutine frame. - /// The state transformation MIR pass may only produce layouts which mention types - /// in this tuple. Upvars are not counted here. - pub fn witness(self) -> Ty<'tcx> { - self.split().witness - } - - /// Returns an iterator over the list of types of captured paths by the coroutine. - /// In case there was a type error in figuring out the types of the captured path, an - /// empty iterator is returned. - #[inline] - pub fn upvar_tys(self) -> &'tcx List> { - match *self.tupled_upvars_ty().kind() { - TyKind::Error(_) => ty::List::empty(), - TyKind::Tuple(tys) => tys, - TyKind::Infer(_) => bug!("upvar_tys called before capture types are inferred"), - ty => bug!("Unexpected representation of upvar types tuple {:?}", ty), - } - } - - /// Returns the tuple type representing the upvars for this coroutine. - #[inline] - pub fn tupled_upvars_ty(self) -> Ty<'tcx> { - self.split().tupled_upvars_ty - } - - /// Returns the type representing the resume type of the coroutine. - pub fn resume_ty(self) -> Ty<'tcx> { - self.split().resume_ty - } - - /// Returns the type representing the yield type of the coroutine. - pub fn yield_ty(self) -> Ty<'tcx> { - self.split().yield_ty - } - - /// Returns the type representing the return type of the coroutine. - pub fn return_ty(self) -> Ty<'tcx> { - self.split().return_ty - } - - /// Returns the "coroutine signature", which consists of its resume, yield - /// and return types. - pub fn sig(self) -> GenSig<'tcx> { - let parts = self.split(); - ty::GenSig { - resume_ty: parts.resume_ty, - yield_ty: parts.yield_ty, - return_ty: parts.return_ty, - } - } -} - -impl<'tcx> CoroutineArgs<'tcx> { +#[extension(pub trait CoroutineArgsExt<'tcx>)] +impl<'tcx> ty::CoroutineArgs> { /// Coroutine has not been resumed yet. - pub const UNRESUMED: usize = 0; + const UNRESUMED: usize = 0; /// Coroutine has returned or is completed. - pub const RETURNED: usize = 1; + const RETURNED: usize = 1; /// Coroutine has been poisoned. - pub const POISONED: usize = 2; + const POISONED: usize = 2; const UNRESUMED_NAME: &'static str = "Unresumed"; const RETURNED_NAME: &'static str = "Returned"; @@ -731,7 +74,7 @@ impl<'tcx> CoroutineArgs<'tcx> { /// The valid variant indices of this coroutine. #[inline] - pub fn variant_range(&self, def_id: DefId, tcx: TyCtxt<'tcx>) -> Range { + fn variant_range(&self, def_id: DefId, tcx: TyCtxt<'tcx>) -> Range { // FIXME requires optimized MIR FIRST_VARIANT ..tcx.coroutine_layout(def_id, tcx.types.unit).unwrap().variant_fields.next_index() @@ -740,7 +83,7 @@ impl<'tcx> CoroutineArgs<'tcx> { /// The discriminant for the given variant. Panics if the `variant_index` is /// out of range. #[inline] - pub fn discriminant_for_variant( + fn discriminant_for_variant( &self, def_id: DefId, tcx: TyCtxt<'tcx>, @@ -755,7 +98,7 @@ impl<'tcx> CoroutineArgs<'tcx> { /// The set of all discriminants for the coroutine, enumerated with their /// variant indices. #[inline] - pub fn discriminants( + fn discriminants( self, def_id: DefId, tcx: TyCtxt<'tcx>, @@ -767,7 +110,7 @@ impl<'tcx> CoroutineArgs<'tcx> { /// Calls `f` with a reference to the name of the enumerator for the given /// variant `v`. - pub fn variant_name(v: VariantIdx) -> Cow<'static, str> { + fn variant_name(v: VariantIdx) -> Cow<'static, str> { match v.as_usize() { Self::UNRESUMED => Cow::from(Self::UNRESUMED_NAME), Self::RETURNED => Cow::from(Self::RETURNED_NAME), @@ -778,7 +121,7 @@ impl<'tcx> CoroutineArgs<'tcx> { /// The type of the state discriminant used in the coroutine type. #[inline] - pub fn discr_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + fn discr_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { tcx.types.u32 } @@ -789,7 +132,7 @@ impl<'tcx> CoroutineArgs<'tcx> { /// The locals are grouped by their variant number. Note that some locals may /// be repeated in multiple variants. #[inline] - pub fn state_tys( + fn state_tys( self, def_id: DefId, tcx: TyCtxt<'tcx>, @@ -805,7 +148,7 @@ impl<'tcx> CoroutineArgs<'tcx> { /// This is the types of the fields of a coroutine which are not stored in a /// variant. #[inline] - pub fn prefix_tys(self) -> &'tcx List> { + fn prefix_tys(self) -> &'tcx List> { self.upvar_tys() } } @@ -938,13 +281,6 @@ impl BoundVariableKind { } } -#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] -pub struct GenSig<'tcx> { - pub resume_ty: Ty<'tcx>, - pub yield_ty: Ty<'tcx>, - pub return_ty: Ty<'tcx>, -} - pub type PolyFnSig<'tcx> = Binder<'tcx, FnSig<'tcx>>; pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder<'tcx, FnSig<'tcx>>>; @@ -1451,6 +787,41 @@ impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> { ) -> Self { Ty::new_alias(interner, kind, alias_ty) } + + fn new_coroutine( + interner: TyCtxt<'tcx>, + def_id: DefId, + args: ty::GenericArgsRef<'tcx>, + ) -> Self { + Ty::new_coroutine(interner, def_id, args) + } + + fn new_tup_from_iter(interner: TyCtxt<'tcx>, iter: It) -> T::Output + where + It: Iterator, + T: CollectAndApply, + { + Ty::new_tup_from_iter(interner, iter) + } + + fn tuple_fields(self) -> &'tcx ty::List> { + self.tuple_fields() + } + + fn to_opt_closure_kind(self) -> Option { + self.to_opt_closure_kind() + } + + fn from_closure_kind(interner: TyCtxt<'tcx>, kind: ty::ClosureKind) -> Self { + Ty::from_closure_kind(interner, kind) + } + + fn from_coroutine_closure_kind( + interner: TyCtxt<'tcx>, + kind: rustc_type_ir::ClosureKind, + ) -> Self { + Ty::from_coroutine_closure_kind(interner, kind) + } } /// Type utilities diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index a3e6e5a5a915c..ade2ac0080e5d 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -69,7 +69,7 @@ use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::CoroutineArgs; use rustc_middle::ty::InstanceDef; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, CoroutineArgsExt, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::impls::{ MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive, diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index dcf54ad2cfc8f..d03c2d18c0c35 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -4,7 +4,7 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::mir::*; use rustc_middle::query::Providers; use rustc_middle::ty::GenericArgs; -use rustc_middle::ty::{self, CoroutineArgs, EarlyBinder, Ty, TyCtxt}; +use rustc_middle::ty::{self, CoroutineArgs, CoroutineArgsExt, EarlyBinder, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; @@ -634,7 +634,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { dest: Place<'tcx>, src: Place<'tcx>, coroutine_def_id: DefId, - args: CoroutineArgs<'tcx>, + args: CoroutineArgs>, ) { self.block(vec![], TerminatorKind::Goto { target: self.block_index_offset(3) }, false); let unwind = self.block(vec![], TerminatorKind::UnwindResume, true); diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 851e16559580e..5e83a6f373aad 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -8,7 +8,9 @@ use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt, Variance}; +use rustc_middle::ty::{ + self, CoroutineArgsExt, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt, Variance, +}; use rustc_middle::{bug, span_bug}; use rustc_target::abi::{Size, FIRST_VARIANT}; use rustc_target::spec::abi::Abi; diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 08796ef3109e4..48acf2a4e996e 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -554,8 +554,8 @@ fn coroutine_closure_to_certain_coroutine<'tcx>( goal_kind: ty::ClosureKind, goal_region: ty::Region<'tcx>, def_id: DefId, - args: ty::CoroutineClosureArgs<'tcx>, - sig: ty::CoroutineClosureSignature<'tcx>, + args: ty::CoroutineClosureArgs>, + sig: ty::CoroutineClosureSignature>, ) -> Ty<'tcx> { sig.to_coroutine_given_kind_and_upvars( tcx, @@ -578,8 +578,8 @@ fn coroutine_closure_to_ambiguous_coroutine<'tcx>( goal_kind: ty::ClosureKind, goal_region: ty::Region<'tcx>, def_id: DefId, - args: ty::CoroutineClosureArgs<'tcx>, - sig: ty::CoroutineClosureSignature<'tcx>, + args: ty::CoroutineClosureArgs>, + sig: ty::CoroutineClosureSignature>, ) -> Ty<'tcx> { let upvars_projection_def_id = tcx.require_lang_item(LangItem::AsyncFnKindUpvars, None); let tupled_upvars_ty = Ty::new_projection( diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 445fa1761b9fc..8619c5ef77f67 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -295,7 +295,7 @@ pub fn coroutine_trait_ref_and_outputs<'tcx>( tcx: TyCtxt<'tcx>, fn_trait_def_id: DefId, self_ty: Ty<'tcx>, - sig: ty::GenSig<'tcx>, + sig: ty::GenSig>, ) -> (ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>) { assert!(!self_ty.has_escaping_bound_vars()); let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, sig.resume_ty]); @@ -306,7 +306,7 @@ pub fn future_trait_ref_and_outputs<'tcx>( tcx: TyCtxt<'tcx>, fn_trait_def_id: DefId, self_ty: Ty<'tcx>, - sig: ty::GenSig<'tcx>, + sig: ty::GenSig>, ) -> (ty::TraitRef<'tcx>, Ty<'tcx>) { assert!(!self_ty.has_escaping_bound_vars()); let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty]); @@ -317,7 +317,7 @@ pub fn iterator_trait_ref_and_outputs<'tcx>( tcx: TyCtxt<'tcx>, iterator_def_id: DefId, self_ty: Ty<'tcx>, - sig: ty::GenSig<'tcx>, + sig: ty::GenSig>, ) -> (ty::TraitRef<'tcx>, Ty<'tcx>) { assert!(!self_ty.has_escaping_bound_vars()); let trait_ref = ty::TraitRef::new(tcx, iterator_def_id, [self_ty]); @@ -328,7 +328,7 @@ pub fn async_iterator_trait_ref_and_outputs<'tcx>( tcx: TyCtxt<'tcx>, async_iterator_def_id: DefId, self_ty: Ty<'tcx>, - sig: ty::GenSig<'tcx>, + sig: ty::GenSig>, ) -> (ty::TraitRef<'tcx>, Ty<'tcx>) { assert!(!self_ty.has_escaping_bound_vars()); let trait_ref = ty::TraitRef::new(tcx, async_iterator_def_id, [self_ty]); diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 1dee14fae57e3..6045abc50a9da 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -10,7 +10,8 @@ use rustc_middle::ty::layout::{ }; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ - self, AdtDef, EarlyBinder, FieldDef, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, + self, AdtDef, CoroutineArgsExt, EarlyBinder, FieldDef, GenericArgsRef, Ty, TyCtxt, + TypeVisitableExt, }; use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo}; use rustc_span::sym; diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 7b1dfecfee2e0..f305ed9b5d77d 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -9,7 +9,7 @@ use std::ops::Deref; use crate::fold::{TypeFoldable, TypeSuperFoldable}; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; -use crate::{self as ty, DebugWithInfcx, Interner, UpcastFrom}; +use crate::{self as ty, CollectAndApply, DebugWithInfcx, Interner, UpcastFrom}; pub trait Ty>: Copy @@ -34,6 +34,21 @@ pub trait Ty>: fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy) -> Self; + + fn new_coroutine(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + + fn new_tup_from_iter(interner: I, iter: It) -> T::Output + where + It: Iterator, + T: CollectAndApply; + + fn tuple_fields(self) -> I::Tys; + + fn to_opt_closure_kind(self) -> Option; + + fn from_closure_kind(interner: I, kind: ty::ClosureKind) -> Self; + + fn from_coroutine_closure_kind(interner: I, kind: ty::ClosureKind) -> Self; } pub trait Tys>: @@ -43,17 +58,18 @@ pub trait Tys>: + Eq + IntoIterator + Deref> - + TypeVisitable + + TypeFoldable + + Default { fn split_inputs_and_output(self) -> (I::FnInputTys, I::Ty); } -pub trait Abi>: Copy + Debug + Hash + Eq { +pub trait Abi>: Copy + Debug + Hash + Eq + TypeVisitable { /// Whether this ABI is `extern "Rust"`. fn is_rust(self) -> bool; } -pub trait Safety>: Copy + Debug + Hash + Eq { +pub trait Safety>: Copy + Debug + Hash + Eq + TypeVisitable { fn is_safe(self) -> bool; fn prefix_str(self) -> &'static str; @@ -129,6 +145,10 @@ pub trait GenericArgs>: def_id: I::DefId, original_args: &[I::GenericArg], ) -> I::GenericArgs; + + fn split_closure_args(self) -> ty::ClosureArgsParts; + fn split_coroutine_closure_args(self) -> ty::CoroutineClosureArgsParts; + fn split_coroutine_args(self) -> ty::CoroutineArgsParts; } pub trait Predicate>: diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index ca39318cc0c8b..6ebb434299b30 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -29,9 +29,7 @@ pub trait Interner: type AdtDef: Copy + Debug + Hash + Eq; type GenericArgs: GenericArgs; - /// The slice of args for a specific item. For a GAT like `type Foo<'a>`, it will be `['a]`, - /// not including the args from the parent item (trait or impl). - type OwnItemArgs: Copy + Debug + Hash + Eq; + type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref; type GenericArg: Copy + DebugWithInfcx + Hash @@ -111,7 +109,7 @@ pub trait Interner: self, def_id: Self::DefId, args: Self::GenericArgs, - ) -> (ty::TraitRef, Self::OwnItemArgs); + ) -> (ty::TraitRef, Self::GenericArgsSlice); fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs; fn mk_args_from_iter(self, args: impl Iterator) -> Self::GenericArgs; diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 48a6f79993cc6..e7039583c91c7 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -604,7 +604,7 @@ impl AliasTerm { /// For example, if this is a projection of `::Item<'a>`, /// then this function would return a `T: StreamingIterator` trait reference and /// `['a]` as the own args. - pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef, I::OwnItemArgs) { + pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef, I::GenericArgsSlice) { interner.trait_ref_and_own_args_for_alias(self.def_id, self.args) } diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index aa285169f276d..6569f3123aa92 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -7,13 +7,15 @@ use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEn use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use std::fmt; +pub use self::closure::*; +use self::TyKind::*; use crate::inherent::*; use crate::{self as ty, DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx}; -use self::TyKind::*; - use rustc_ast_ir::Mutability; +mod closure; + /// Specifies how a trait object is represented. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] @@ -514,7 +516,7 @@ impl AliasTy { /// For example, if this is a projection of `::Item<'a>`, /// then this function would return a `T: StreamingIterator` trait reference and /// `['a]` as the own args. - pub fn trait_ref_and_own_args(self, interner: I) -> (ty::TraitRef, I::OwnItemArgs) { + pub fn trait_ref_and_own_args(self, interner: I) -> (ty::TraitRef, I::GenericArgsSlice) { debug_assert_eq!(self.kind(interner), AliasTyKind::Projection); interner.trait_ref_and_own_args_for_alias(self.def_id, self.args) } diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs new file mode 100644 index 0000000000000..e2ca1cc05b7e8 --- /dev/null +++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs @@ -0,0 +1,696 @@ +use std::ops::ControlFlow; + +use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; + +use crate::fold::{shift_region, TypeFoldable, TypeFolder, TypeSuperFoldable}; +use crate::inherent::*; +use crate::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; +use crate::{self as ty, Interner}; + +/// A closure can be modeled as a struct that looks like: +/// ```ignore (illustrative) +/// struct Closure<'l0...'li, T0...Tj, CK, CS, U>(...U); +/// ``` +/// where: +/// +/// - 'l0...'li and T0...Tj are the generic parameters +/// in scope on the function that defined the closure, +/// - CK represents the *closure kind* (Fn vs FnMut vs FnOnce). This +/// is rather hackily encoded via a scalar type. See +/// `Ty::to_opt_closure_kind` for details. +/// - CS represents the *closure signature*, representing as a `fn()` +/// type. For example, `fn(u32, u32) -> u32` would mean that the closure +/// implements `CK<(u32, u32), Output = u32>`, where `CK` is the trait +/// specified above. +/// - U is a type parameter representing the types of its upvars, tupled up +/// (borrowed, if appropriate; that is, if a U field represents a by-ref upvar, +/// and the up-var has the type `Foo`, then that field of U will be `&Foo`). +/// +/// So, for example, given this function: +/// ```ignore (illustrative) +/// fn foo<'a, T>(data: &'a mut T) { +/// do(|| data.count += 1) +/// } +/// ``` +/// the type of the closure would be something like: +/// ```ignore (illustrative) +/// struct Closure<'a, T, U>(...U); +/// ``` +/// Note that the type of the upvar is not specified in the struct. +/// You may wonder how the impl would then be able to use the upvar, +/// if it doesn't know it's type? The answer is that the impl is +/// (conceptually) not fully generic over Closure but rather tied to +/// instances with the expected upvar types: +/// ```ignore (illustrative) +/// impl<'b, 'a, T> FnMut() for Closure<'a, T, (&'b mut &'a mut T,)> { +/// ... +/// } +/// ``` +/// You can see that the *impl* fully specified the type of the upvar +/// and thus knows full well that `data` has type `&'b mut &'a mut T`. +/// (Here, I am assuming that `data` is mut-borrowed.) +/// +/// Now, the last question you may ask is: Why include the upvar types +/// in an extra type parameter? The reason for this design is that the +/// upvar types can reference lifetimes that are internal to the +/// creating function. In my example above, for example, the lifetime +/// `'b` represents the scope of the closure itself; this is some +/// subset of `foo`, probably just the scope of the call to the to +/// `do()`. If we just had the lifetime/type parameters from the +/// enclosing function, we couldn't name this lifetime `'b`. Note that +/// there can also be lifetimes in the types of the upvars themselves, +/// if one of them happens to be a reference to something that the +/// creating fn owns. +/// +/// OK, you say, so why not create a more minimal set of parameters +/// that just includes the extra lifetime parameters? The answer is +/// primarily that it would be hard --- we don't know at the time when +/// we create the closure type what the full types of the upvars are, +/// nor do we know which are borrowed and which are not. In this +/// design, we can just supply a fresh type parameter and figure that +/// out later. +/// +/// All right, you say, but why include the type parameters from the +/// original function then? The answer is that codegen may need them +/// when monomorphizing, and they may not appear in the upvars. A +/// closure could capture no variables but still make use of some +/// in-scope type parameter with a bound (e.g., if our example above +/// had an extra `U: Default`, and the closure called `U::default()`). +/// +/// There is another reason. This design (implicitly) prohibits +/// closures from capturing themselves (except via a trait +/// object). This simplifies closure inference considerably, since it +/// means that when we infer the kind of a closure or its upvars, we +/// don't have to handle cycles where the decisions we make for +/// closure C wind up influencing the decisions we ought to make for +/// closure C (which would then require fixed point iteration to +/// handle). Plus it fixes an ICE. :P +/// +/// ## Coroutines +/// +/// Coroutines are handled similarly in `CoroutineArgs`. The set of +/// type parameters is similar, but `CK` and `CS` are replaced by the +/// following type parameters: +/// +/// * `GS`: The coroutine's "resume type", which is the type of the +/// argument passed to `resume`, and the type of `yield` expressions +/// inside the coroutine. +/// * `GY`: The "yield type", which is the type of values passed to +/// `yield` inside the coroutine. +/// * `GR`: The "return type", which is the type of value returned upon +/// completion of the coroutine. +/// * `GW`: The "coroutine witness". +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +pub struct ClosureArgs { + /// Lifetime and type parameters from the enclosing function, + /// concatenated with a tuple containing the types of the upvars. + /// + /// These are separated out because codegen wants to pass them around + /// when monomorphizing. + pub args: I::GenericArgs, +} + +/// Struct returned by `split()`. +pub struct ClosureArgsParts { + /// This is the args of the typeck root. + pub parent_args: I::GenericArgsSlice, + /// Represents the maximum calling capability of the closure. + pub closure_kind_ty: I::Ty, + /// Captures the closure's signature. This closure signature is "tupled", and + /// thus has a peculiar signature of `extern "rust-call" fn((Args, ...)) -> Ty`. + pub closure_sig_as_fn_ptr_ty: I::Ty, + /// The upvars captured by the closure. Remains an inference variable + /// until the upvar analysis, which happens late in HIR typeck. + pub tupled_upvars_ty: I::Ty, +} + +impl ClosureArgs { + /// Construct `ClosureArgs` from `ClosureArgsParts`, containing `Args` + /// for the closure parent, alongside additional closure-specific components. + pub fn new(tcx: I, parts: ClosureArgsParts) -> ClosureArgs { + ClosureArgs { + args: tcx.mk_args_from_iter(parts.parent_args.iter().copied().chain([ + parts.closure_kind_ty.into(), + parts.closure_sig_as_fn_ptr_ty.into(), + parts.tupled_upvars_ty.into(), + ])), + } + } + + /// Divides the closure args into their respective components. + /// The ordering assumed here must match that used by `ClosureArgs::new` above. + fn split(self) -> ClosureArgsParts { + self.args.split_closure_args() + } + + /// Returns the generic parameters of the closure's parent. + pub fn parent_args(self) -> I::GenericArgsSlice { + self.split().parent_args + } + + /// Returns an iterator over the list of types of captured paths by the closure. + /// In case there was a type error in figuring out the types of the captured path, an + /// empty iterator is returned. + #[inline] + pub fn upvar_tys(self) -> I::Tys { + match self.tupled_upvars_ty().kind() { + ty::Error(_) => Default::default(), + ty::Tuple(tys) => tys, + ty::Infer(_) => panic!("upvar_tys called before capture types are inferred"), + ty => panic!("Unexpected representation of upvar types tuple {:?}", ty), + } + } + + /// Returns the tuple type representing the upvars for this closure. + #[inline] + pub fn tupled_upvars_ty(self) -> I::Ty { + self.split().tupled_upvars_ty + } + + /// Returns the closure kind for this closure; may return a type + /// variable during inference. To get the closure kind during + /// inference, use `infcx.closure_kind(args)`. + pub fn kind_ty(self) -> I::Ty { + self.split().closure_kind_ty + } + + /// Returns the `fn` pointer type representing the closure signature for this + /// closure. + // FIXME(eddyb) this should be unnecessary, as the shallowly resolved + // type is known at the time of the creation of `ClosureArgs`, + // see `rustc_hir_analysis::check::closure`. + pub fn sig_as_fn_ptr_ty(self) -> I::Ty { + self.split().closure_sig_as_fn_ptr_ty + } + + /// Returns the closure kind for this closure; only usable outside + /// of an inference context, because in that context we know that + /// there are no type variables. + /// + /// If you have an inference context, use `infcx.closure_kind()`. + pub fn kind(self) -> ty::ClosureKind { + self.kind_ty().to_opt_closure_kind().unwrap() + } + + /// Extracts the signature from the closure. + pub fn sig(self) -> ty::Binder> { + match self.sig_as_fn_ptr_ty().kind() { + ty::FnPtr(sig) => sig, + ty => panic!("closure_sig_as_fn_ptr_ty is not a fn-ptr: {ty:?}"), + } + } +} + +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +pub struct CoroutineClosureArgs { + pub args: I::GenericArgs, +} + +/// See docs for explanation of how each argument is used. +/// +/// See [`CoroutineClosureSignature`] for how these arguments are put together +/// to make a callable [`FnSig`] suitable for typeck and borrowck. +pub struct CoroutineClosureArgsParts { + /// This is the args of the typeck root. + pub parent_args: I::GenericArgsSlice, + /// Represents the maximum calling capability of the closure. + pub closure_kind_ty: I::Ty, + /// Represents all of the relevant parts of the coroutine returned by this + /// coroutine-closure. This signature parts type will have the general + /// shape of `fn(tupled_inputs, resume_ty) -> (return_ty, yield_ty)`, where + /// `resume_ty`, `return_ty`, and `yield_ty` are the respective types for the + /// coroutine returned by the coroutine-closure. + /// + /// Use `coroutine_closure_sig` to break up this type rather than using it + /// yourself. + pub signature_parts_ty: I::Ty, + /// The upvars captured by the closure. Remains an inference variable + /// until the upvar analysis, which happens late in HIR typeck. + pub tupled_upvars_ty: I::Ty, + /// a function pointer that has the shape `for<'env> fn() -> (&'env T, ...)`. + /// This allows us to represent the binder of the self-captures of the closure. + /// + /// For example, if the coroutine returned by the closure borrows `String` + /// from the closure's upvars, this will be `for<'env> fn() -> (&'env String,)`, + /// while the `tupled_upvars_ty`, representing the by-move version of the same + /// captures, will be `(String,)`. + pub coroutine_captures_by_ref_ty: I::Ty, + /// Witness type returned by the generator produced by this coroutine-closure. + pub coroutine_witness_ty: I::Ty, +} + +impl CoroutineClosureArgs { + pub fn new(tcx: I, parts: CoroutineClosureArgsParts) -> CoroutineClosureArgs { + CoroutineClosureArgs { + args: tcx.mk_args_from_iter(parts.parent_args.iter().copied().chain([ + parts.closure_kind_ty.into(), + parts.signature_parts_ty.into(), + parts.tupled_upvars_ty.into(), + parts.coroutine_captures_by_ref_ty.into(), + parts.coroutine_witness_ty.into(), + ])), + } + } + + fn split(self) -> CoroutineClosureArgsParts { + self.args.split_coroutine_closure_args() + } + + pub fn parent_args(self) -> I::GenericArgsSlice { + self.split().parent_args + } + + #[inline] + pub fn upvar_tys(self) -> I::Tys { + match self.tupled_upvars_ty().kind() { + ty::Error(_) => Default::default(), + ty::Tuple(..) => self.tupled_upvars_ty().tuple_fields(), + ty::Infer(_) => panic!("upvar_tys called before capture types are inferred"), + ty => panic!("Unexpected representation of upvar types tuple {:?}", ty), + } + } + + #[inline] + pub fn tupled_upvars_ty(self) -> I::Ty { + self.split().tupled_upvars_ty + } + + pub fn kind_ty(self) -> I::Ty { + self.split().closure_kind_ty + } + + pub fn kind(self) -> ty::ClosureKind { + self.kind_ty().to_opt_closure_kind().unwrap() + } + + pub fn signature_parts_ty(self) -> I::Ty { + self.split().signature_parts_ty + } + + pub fn coroutine_closure_sig(self) -> ty::Binder> { + let interior = self.coroutine_witness_ty(); + let ty::FnPtr(sig) = self.signature_parts_ty().kind() else { panic!() }; + sig.map_bound(|sig| { + let [resume_ty, tupled_inputs_ty] = *sig.inputs() else { + panic!(); + }; + let [yield_ty, return_ty] = **sig.output().tuple_fields() else { panic!() }; + CoroutineClosureSignature { + interior, + tupled_inputs_ty, + resume_ty, + yield_ty, + return_ty, + c_variadic: sig.c_variadic, + safety: sig.safety, + abi: sig.abi, + } + }) + } + + pub fn coroutine_captures_by_ref_ty(self) -> I::Ty { + self.split().coroutine_captures_by_ref_ty + } + + pub fn coroutine_witness_ty(self) -> I::Ty { + self.split().coroutine_witness_ty + } + + pub fn has_self_borrows(&self) -> bool { + match self.coroutine_captures_by_ref_ty().kind() { + ty::FnPtr(sig) => sig + .skip_binder() + .visit_with(&mut HasRegionsBoundAt { binder: ty::INNERMOST }) + .is_break(), + ty::Error(_) => true, + _ => panic!(), + } + } +} + +/// Unlike `has_escaping_bound_vars` or `outermost_exclusive_binder`, this will +/// detect only regions bound *at* the debruijn index. +struct HasRegionsBoundAt { + binder: ty::DebruijnIndex, +} +// FIXME: Could be optimized to not walk into components with no escaping bound vars. +impl TypeVisitor for HasRegionsBoundAt { + type Result = ControlFlow<()>; + fn visit_binder>(&mut self, t: &ty::Binder) -> Self::Result { + self.binder.shift_in(1); + t.super_visit_with(self)?; + self.binder.shift_out(1); + ControlFlow::Continue(()) + } + + fn visit_region(&mut self, r: I::Region) -> Self::Result { + if matches!(r.kind(), ty::ReBound(binder, _) if self.binder == binder) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + } +} + +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +pub struct CoroutineClosureSignature { + pub interior: I::Ty, + pub tupled_inputs_ty: I::Ty, + pub resume_ty: I::Ty, + pub yield_ty: I::Ty, + pub return_ty: I::Ty, + + // Like the `fn_sig_as_fn_ptr_ty` of a regular closure, these types + // never actually differ. But we save them rather than recreating them + // from scratch just for good measure. + /// Always false + pub c_variadic: bool, + /// Always `Normal` (safe) + pub safety: I::Safety, + /// Always `RustCall` + pub abi: I::Abi, +} + +impl CoroutineClosureSignature { + /// Construct a coroutine from the closure signature. Since a coroutine signature + /// is agnostic to the type of generator that is returned (by-ref/by-move), + /// the caller must specify what "flavor" of generator that they'd like to + /// create. Additionally, they must manually compute the upvars of the closure. + /// + /// This helper is not really meant to be used directly except for early on + /// during typeck, when we want to put inference vars into the kind and upvars tys. + /// When the kind and upvars are known, use the other helper functions. + pub fn to_coroutine( + self, + tcx: I, + parent_args: I::GenericArgsSlice, + coroutine_kind_ty: I::Ty, + coroutine_def_id: I::DefId, + tupled_upvars_ty: I::Ty, + ) -> I::Ty { + let coroutine_args = ty::CoroutineArgs::new( + tcx, + ty::CoroutineArgsParts { + parent_args, + kind_ty: coroutine_kind_ty, + resume_ty: self.resume_ty, + yield_ty: self.yield_ty, + return_ty: self.return_ty, + witness: self.interior, + tupled_upvars_ty, + }, + ); + + Ty::new_coroutine(tcx, coroutine_def_id, coroutine_args.args) + } + + /// Given known upvars and a [`ClosureKind`](ty::ClosureKind), compute the coroutine + /// returned by that corresponding async fn trait. + /// + /// This function expects the upvars to have been computed already, and doesn't check + /// that the `ClosureKind` is actually supported by the coroutine-closure. + pub fn to_coroutine_given_kind_and_upvars( + self, + tcx: I, + parent_args: I::GenericArgsSlice, + coroutine_def_id: I::DefId, + goal_kind: ty::ClosureKind, + env_region: I::Region, + closure_tupled_upvars_ty: I::Ty, + coroutine_captures_by_ref_ty: I::Ty, + ) -> I::Ty { + let tupled_upvars_ty = Self::tupled_upvars_by_closure_kind( + tcx, + goal_kind, + self.tupled_inputs_ty, + closure_tupled_upvars_ty, + coroutine_captures_by_ref_ty, + env_region, + ); + + self.to_coroutine( + tcx, + parent_args, + Ty::from_coroutine_closure_kind(tcx, goal_kind), + coroutine_def_id, + tupled_upvars_ty, + ) + } + + /// Compute the tupled upvars that a coroutine-closure's output coroutine + /// would return for the given `ClosureKind`. + /// + /// When `ClosureKind` is `FnMut`/`Fn`, then this will use the "captures by ref" + /// to return a set of upvars which are borrowed with the given `env_region`. + /// + /// This ensures that the `AsyncFn::call` will return a coroutine whose upvars' + /// lifetimes are related to the lifetime of the borrow on the closure made for + /// the call. This allows borrowck to enforce the self-borrows correctly. + pub fn tupled_upvars_by_closure_kind( + tcx: I, + kind: ty::ClosureKind, + tupled_inputs_ty: I::Ty, + closure_tupled_upvars_ty: I::Ty, + coroutine_captures_by_ref_ty: I::Ty, + env_region: I::Region, + ) -> I::Ty { + match kind { + ty::ClosureKind::Fn | ty::ClosureKind::FnMut => { + let ty::FnPtr(sig) = coroutine_captures_by_ref_ty.kind() else { + panic!(); + }; + let coroutine_captures_by_ref_ty = + sig.output().skip_binder().fold_with(&mut FoldEscapingRegions { + interner: tcx, + region: env_region, + debruijn: ty::INNERMOST, + }); + Ty::new_tup_from_iter( + tcx, + tupled_inputs_ty + .tuple_fields() + .into_iter() + .chain(coroutine_captures_by_ref_ty.tuple_fields()), + ) + } + ty::ClosureKind::FnOnce => Ty::new_tup_from_iter( + tcx, + tupled_inputs_ty + .tuple_fields() + .into_iter() + .chain(closure_tupled_upvars_ty.tuple_fields()), + ), + } + } +} + +/// Instantiates a `for<'env> ...` binder with a specific region. +// FIXME(async_closures): Get rid of this in favor of `BoundVarReplacerDelegate` +// when that is uplifted. +struct FoldEscapingRegions { + interner: I, + debruijn: ty::DebruijnIndex, + region: I::Region, +} + +impl TypeFolder for FoldEscapingRegions { + fn interner(&self) -> I { + self.interner + } + + fn fold_binder(&mut self, t: ty::Binder) -> ty::Binder + where + T: TypeFoldable, + { + self.debruijn.shift_in(1); + let result = t.super_fold_with(self); + self.debruijn.shift_out(1); + result + } + + fn fold_region(&mut self, r: ::Region) -> ::Region { + if let ty::ReBound(debruijn, _) = r.kind() { + assert!( + debruijn <= self.debruijn, + "cannot instantiate binder with escaping bound vars" + ); + if self.debruijn == debruijn { + shift_region(self.interner, self.region, self.debruijn.as_u32()) + } else { + r + } + } else { + r + } + } +} + +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +pub struct GenSig { + pub resume_ty: I::Ty, + pub yield_ty: I::Ty, + pub return_ty: I::Ty, +} + +/// Similar to `ClosureArgs`; see the above documentation for more. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +pub struct CoroutineArgs { + pub args: I::GenericArgs, +} + +pub struct CoroutineArgsParts { + /// This is the args of the typeck root. + pub parent_args: I::GenericArgsSlice, + + /// The coroutines returned by a coroutine-closure's `AsyncFnOnce`/`AsyncFnMut` + /// implementations must be distinguished since the former takes the closure's + /// upvars by move, and the latter takes the closure's upvars by ref. + /// + /// This field distinguishes these fields so that codegen can select the right + /// body for the coroutine. This has the same type representation as the closure + /// kind: `i8`/`i16`/`i32`. + /// + /// For regular coroutines, this field will always just be `()`. + pub kind_ty: I::Ty, + + pub resume_ty: I::Ty, + pub yield_ty: I::Ty, + pub return_ty: I::Ty, + + /// The interior type of the coroutine. + /// Represents all types that are stored in locals + /// in the coroutine's body. + pub witness: I::Ty, + + /// The upvars captured by the closure. Remains an inference variable + /// until the upvar analysis, which happens late in HIR typeck. + pub tupled_upvars_ty: I::Ty, +} + +impl CoroutineArgs { + /// Construct `CoroutineArgs` from `CoroutineArgsParts`, containing `Args` + /// for the coroutine parent, alongside additional coroutine-specific components. + pub fn new(tcx: I, parts: CoroutineArgsParts) -> CoroutineArgs { + CoroutineArgs { + args: tcx.mk_args_from_iter(parts.parent_args.iter().copied().chain([ + parts.kind_ty.into(), + parts.resume_ty.into(), + parts.yield_ty.into(), + parts.return_ty.into(), + parts.witness.into(), + parts.tupled_upvars_ty.into(), + ])), + } + } + + /// Divides the coroutine args into their respective components. + /// The ordering assumed here must match that used by `CoroutineArgs::new` above. + fn split(self) -> CoroutineArgsParts { + self.args.split_coroutine_args() + } + + /// Returns the generic parameters of the coroutine's parent. + pub fn parent_args(self) -> I::GenericArgsSlice { + self.split().parent_args + } + + // Returns the kind of the coroutine. See docs on the `kind_ty` field. + pub fn kind_ty(self) -> I::Ty { + self.split().kind_ty + } + + /// This describes the types that can be contained in a coroutine. + /// It will be a type variable initially and unified in the last stages of typeck of a body. + /// It contains a tuple of all the types that could end up on a coroutine frame. + /// The state transformation MIR pass may only produce layouts which mention types + /// in this tuple. Upvars are not counted here. + pub fn witness(self) -> I::Ty { + self.split().witness + } + + /// Returns an iterator over the list of types of captured paths by the coroutine. + /// In case there was a type error in figuring out the types of the captured path, an + /// empty iterator is returned. + #[inline] + pub fn upvar_tys(self) -> I::Tys { + match self.tupled_upvars_ty().kind() { + ty::Error(_) => Default::default(), + ty::Tuple(tys) => tys, + ty::Infer(_) => panic!("upvar_tys called before capture types are inferred"), + ty => panic!("Unexpected representation of upvar types tuple {:?}", ty), + } + } + + /// Returns the tuple type representing the upvars for this coroutine. + #[inline] + pub fn tupled_upvars_ty(self) -> I::Ty { + self.split().tupled_upvars_ty + } + + /// Returns the type representing the resume type of the coroutine. + pub fn resume_ty(self) -> I::Ty { + self.split().resume_ty + } + + /// Returns the type representing the yield type of the coroutine. + pub fn yield_ty(self) -> I::Ty { + self.split().yield_ty + } + + /// Returns the type representing the return type of the coroutine. + pub fn return_ty(self) -> I::Ty { + self.split().return_ty + } + + /// Returns the "coroutine signature", which consists of its resume, yield + /// and return types. + pub fn sig(self) -> GenSig { + let parts = self.split(); + GenSig { resume_ty: parts.resume_ty, yield_ty: parts.yield_ty, return_ty: parts.return_ty } + } +} diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index b58018ca0353b..48c4c4206fe88 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -10,7 +10,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{ self, Binder, ClosureArgs, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, RegionKind, Ty, - TypeVisitableExt, TypeckResults, + TypeVisitableExt, TypeckResults, TyCtxt, }; use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; @@ -240,7 +240,7 @@ fn check_inputs( }) } -fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure: ClosureArgs<'tcx>, call_sig: FnSig<'_>) -> bool { +fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure: ClosureArgs>, call_sig: FnSig<'_>) -> bool { call_sig.safety == Safety::Safe && !has_late_bound_to_non_late_bound_regions( cx.tcx.signature_unclosure(closure.sig(), Safety::Safe).skip_binder(),