diff --git a/Cargo.lock b/Cargo.lock index 9d1481ec768d..241a37588b40 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -266,7 +266,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -601,9 +601,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.5" +version = "4.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2020fa13af48afc65a9a87335bda648309ab3d154cd03c7ff95b378c7ed39c4" +checksum = "fbca90c87c2a04da41e95d1856e8bcd22f159bdbfa147314d2ce5218057b0e58" dependencies = [ "clap", ] @@ -617,7 +617,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -644,7 +644,7 @@ dependencies = [ "regex", "rustc_tools_util", "serde", - "syn 2.0.66", + "syn 2.0.67", "tempfile", "termize", "tokio", @@ -755,7 +755,7 @@ dependencies = [ "nom", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -991,7 +991,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -1002,7 +1002,7 @@ checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" dependencies = [ "darling_core", "quote", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -1028,7 +1028,7 @@ version = "0.1.81" dependencies = [ "itertools", "quote", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -1069,7 +1069,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -1079,7 +1079,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" dependencies = [ "derive_builder_core", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -1090,7 +1090,7 @@ checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -1102,7 +1102,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -1180,13 +1180,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -1506,7 +1506,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -1739,7 +1739,7 @@ dependencies = [ "markup5ever", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -1780,18 +1780,6 @@ dependencies = [ "cc", ] -[[package]] -name = "icu_collections" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", - "zerovec", -] - [[package]] name = "icu_list" version = "1.5.0" @@ -1845,51 +1833,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" -[[package]] -name = "icu_normalizer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" - -[[package]] -name = "icu_properties" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f8ac670d7422d7f76b32e17a5db556510825b29ec9154f235977c9caba61036" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locid_transform", - "icu_properties_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" - [[package]] name = "icu_provider" version = "1.5.0" @@ -1928,7 +1871,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -1939,14 +1882,12 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "1.0.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4716a3a0933a1d01c2f72450e89596eb51dd34ef3c211ccd875acdf1f8fe47ed" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ - "icu_normalizer", - "icu_properties", - "smallvec", - "utf8_iter", + "unicode-bidi", + "unicode-normalization", ] [[package]] @@ -2146,9 +2087,9 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "leb128" @@ -2521,9 +2462,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", "compiler_builtins", @@ -2949,7 +2890,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -3141,9 +3082,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.85" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -4045,7 +3986,7 @@ dependencies = [ "fluent-syntax", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", "unic-langid", ] @@ -4179,7 +4120,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -4326,7 +4267,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", "synstructure", ] @@ -4905,7 +4846,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", "synstructure", ] @@ -5003,7 +4944,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -5153,7 +5094,7 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -5446,9 +5387,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.66" +version = "2.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "ff8655ed1d86f3af4ee3fd3263786bc14245ad17c4c7e85ba7187fb3ae028c90" dependencies = [ "proc-macro2", "quote", @@ -5463,7 +5404,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -5640,7 +5581,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -5678,6 +5619,7 @@ dependencies = [ name = "tidy" version = "0.1.0" dependencies = [ + "build_helper", "cargo_metadata 0.15.4", "fluent-syntax", "ignore", @@ -5854,7 +5796,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -6054,7 +5996,7 @@ checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.66", + "syn 2.0.67", "unic-langid-impl", ] @@ -6074,6 +6016,12 @@ dependencies = [ "ucd-parse", ] +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -6175,9 +6123,9 @@ dependencies = [ [[package]] name = "url" -version = "2.5.1" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c25da092f0a868cdf09e8674cd3b7ef3a7d92a24253e663a2fb85e2496de56" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", @@ -6190,24 +6138,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8-width" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - [[package]] name = "utf8parse" version = "0.2.2" @@ -6292,7 +6228,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", "wasm-bindgen-shared", ] @@ -6314,7 +6250,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6395,7 +6331,7 @@ dependencies = [ "rayon", "serde", "serde_json", - "syn 2.0.66", + "syn 2.0.67", "windows-metadata", ] @@ -6571,12 +6507,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - [[package]] name = "writeable" version = "0.5.5" @@ -6647,7 +6577,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", "synstructure", ] @@ -6668,7 +6598,7 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", ] [[package]] @@ -6688,7 +6618,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", "synstructure", ] @@ -6711,5 +6641,5 @@ checksum = "97cf56601ee5052b4417d90c8755c6683473c926039908196cf35d99f893ebe7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.67", ] diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index cc66cc87652d..efe195661521 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -1,6 +1,8 @@ pub use BinOpToken::*; pub use LitKind::*; pub use Nonterminal::*; +pub use NtExprKind::*; +pub use NtPatKind::*; pub use TokenKind::*; use crate::ast; @@ -871,6 +873,27 @@ impl PartialEq for Token { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable)] +pub enum NtPatKind { + // Matches or-patterns. Was written using `pat` in edition 2021 or later. + PatWithOr, + // Doesn't match or-patterns. + // - `inferred`: was written using `pat` in edition 2015 or 2018. + // - `!inferred`: was written using `pat_param`. + PatParam { inferred: bool }, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable)] +pub enum NtExprKind { + // Matches expressions using the post-edition 2024. Was written using + // `expr` in edition 2024 or later. + Expr, + // Matches expressions using the pre-edition 2024 rules. + // - `inferred`: was written using `expr` in edition 2021 or earlier. + // - `!inferred`: was written using `expr_2021`. + Expr2021 { inferred: bool }, +} + #[derive(Clone, Encodable, Decodable)] /// For interpolation during macro expansion. pub enum Nonterminal { @@ -892,19 +915,8 @@ pub enum NonterminalKind { Item, Block, Stmt, - PatParam { - /// Keep track of whether the user used `:pat_param` or `:pat` and we inferred it from the - /// edition of the span. This is used for diagnostics. - inferred: bool, - }, - PatWithOr, - Expr, - /// Matches an expression using the rules from edition 2021 and earlier. - Expr2021 { - /// Keep track of whether the user used `:expr` or `:expr_2021` and we inferred it from the - /// edition of the span. This is used for diagnostics AND feature gating. - inferred: bool, - }, + Pat(NtPatKind), + Expr(NtExprKind), Ty, Ident, Lifetime, @@ -926,20 +938,22 @@ impl NonterminalKind { sym::item => NonterminalKind::Item, sym::block => NonterminalKind::Block, sym::stmt => NonterminalKind::Stmt, - sym::pat => match edition() { - Edition::Edition2015 | Edition::Edition2018 => { - NonterminalKind::PatParam { inferred: true } + sym::pat => { + if edition().at_least_rust_2021() { + NonterminalKind::Pat(PatWithOr) + } else { + NonterminalKind::Pat(PatParam { inferred: true }) } - Edition::Edition2021 | Edition::Edition2024 => NonterminalKind::PatWithOr, - }, - sym::pat_param => NonterminalKind::PatParam { inferred: false }, - sym::expr => match edition() { - Edition::Edition2015 | Edition::Edition2018 | Edition::Edition2021 => { - NonterminalKind::Expr2021 { inferred: true } + } + sym::pat_param => NonterminalKind::Pat(PatParam { inferred: false }), + sym::expr => { + if edition().at_least_rust_2024() { + NonterminalKind::Expr(Expr) + } else { + NonterminalKind::Expr(Expr2021 { inferred: true }) } - Edition::Edition2024 => NonterminalKind::Expr, - }, - sym::expr_2021 => NonterminalKind::Expr2021 { inferred: false }, + } + sym::expr_2021 => NonterminalKind::Expr(Expr2021 { inferred: false }), sym::ty => NonterminalKind::Ty, sym::ident => NonterminalKind::Ident, sym::lifetime => NonterminalKind::Lifetime, @@ -951,15 +965,16 @@ impl NonterminalKind { _ => return None, }) } + fn symbol(self) -> Symbol { match self { NonterminalKind::Item => sym::item, NonterminalKind::Block => sym::block, NonterminalKind::Stmt => sym::stmt, - NonterminalKind::PatParam { inferred: false } => sym::pat_param, - NonterminalKind::PatParam { inferred: true } | NonterminalKind::PatWithOr => sym::pat, - NonterminalKind::Expr | NonterminalKind::Expr2021 { inferred: true } => sym::expr, - NonterminalKind::Expr2021 { inferred: false } => sym::expr_2021, + NonterminalKind::Pat(PatParam { inferred: true } | PatWithOr) => sym::pat, + NonterminalKind::Pat(PatParam { inferred: false }) => sym::pat_param, + NonterminalKind::Expr(Expr2021 { inferred: true } | Expr) => sym::expr, + NonterminalKind::Expr(Expr2021 { inferred: false }) => sym::expr_2021, NonterminalKind::Ty => sym::ty, NonterminalKind::Ident => sym::ident, NonterminalKind::Lifetime => sym::lifetime, diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index fff1bcd72bce..7da726ef4086 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -28,7 +28,7 @@ ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetim .label = {ast_passes_auto_super_lifetime} .suggestion = remove the super traits or lifetime bounds -ast_passes_bad_c_variadic = only foreign or `unsafe extern "C"` functions may be C-variadic +ast_passes_bad_c_variadic = only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg ast_passes_bare_fn_invalid_safety = function pointers cannot be declared with `safe` safety qualifier .suggestion = remove safe from this item diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index e89b412687d9..941bb78c0dd6 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -637,6 +637,7 @@ impl<'a> AstValidator<'a> { (Some(FnCtxt::Foreign), _) => return, (Some(FnCtxt::Free), Some(header)) => match header.ext { Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _) + | Extern::Explicit(StrLit { symbol_unescaped: sym::C_dash_unwind, .. }, _) | Extern::Implicit(_) if matches!(header.safety, Safety::Unsafe(_)) => { @@ -898,7 +899,7 @@ fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericPara impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_attribute(&mut self, attr: &Attribute) { - validate_attr::check_attr(&self.session.psess, attr); + validate_attr::check_attr(&self.features, &self.session.psess, attr); } fn visit_ty(&mut self, ty: &'a Ty) { diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index 3e6d0311b270..0bae1bd07a29 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -126,7 +126,7 @@ impl<'tcx> BorrowSet<'tcx> { ) -> Self { let mut visitor = GatherBorrows { tcx, - body: body, + body, location_map: Default::default(), activation_map: Default::default(), local_map: Default::default(), diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index c1f753282725..8a2936c26579 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -213,7 +213,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { via(msg_old), ); - if msg_new == "" { + if msg_new.is_empty() { // If `msg_new` is empty, then this isn't a borrow of a union field. err.span_label(span, format!("{kind_new} borrow occurs here")); err.span_label(old_span, format!("{kind_old} borrow occurs here")); diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index ec7d4582a601..f2b5ddcd7827 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -43,9 +43,9 @@ impl<'mir, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'mir, 'tcx> { } fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) { - state.borrows.clone_from(&self.borrows.entry_set_for_block(block)); - state.uninits.clone_from(&self.uninits.entry_set_for_block(block)); - state.ever_inits.clone_from(&self.ever_inits.entry_set_for_block(block)); + state.borrows.clone_from(self.borrows.entry_set_for_block(block)); + state.uninits.clone_from(self.uninits.entry_set_for_block(block)); + state.ever_inits.clone_from(self.ever_inits.entry_set_for_block(block)); } fn reconstruct_before_statement_effect( diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 67c11ff4a5bd..c214c52880a9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -895,7 +895,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { for alias_ty in alias_tys { if alias_ty.span.desugaring_kind().is_some() { // Skip `async` desugaring `impl Future`. - () } if let TyKind::TraitObject(_, lt, _) = alias_ty.kind { if lt.ident.name == kw::Empty { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 77fb9fb43151..25a0d40218bb 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -519,7 +519,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { } // Otherwise, let's descend into the referent types. - search_stack.push((*referent_ty, &referent_hir_ty.ty)); + search_stack.push((*referent_ty, referent_hir_ty.ty)); } // Match up something like `Foo<'1>` @@ -558,7 +558,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { } (ty::RawPtr(mut_ty, _), hir::TyKind::Ptr(mut_hir_ty)) => { - search_stack.push((*mut_ty, &mut_hir_ty.ty)); + search_stack.push((*mut_ty, mut_hir_ty.ty)); } _ => { @@ -652,7 +652,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?; let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region( self.infcx.tcx, - &self.upvars, + self.upvars, upvar_index, ); let region_name = self.synthesize_region_name(); @@ -717,7 +717,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { .output; span = output.span(); if let hir::FnRetTy::Return(ret) = output { - hir_ty = Some(self.get_future_inner_return_ty(*ret)); + hir_ty = Some(self.get_future_inner_return_ty(ret)); } " of async function" } @@ -958,7 +958,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { { let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region( self.infcx.tcx, - &self.upvars, + self.upvars, upvar_index, ); let region_name = self.synthesize_region_name(); diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 5d7ce548469f..923cf7e94057 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -114,7 +114,6 @@ pub(crate) fn compute_regions<'cx, 'tcx>( move_data, elements, upvars, - polonius_input, ); // Create the region inference context, taking ownership of the diff --git a/compiler/rustc_borrowck/src/polonius/mod.rs b/compiler/rustc_borrowck/src/polonius/mod.rs index 9984f76e6d44..c590104978c2 100644 --- a/compiler/rustc_borrowck/src/polonius/mod.rs +++ b/compiler/rustc_borrowck/src/polonius/mod.rs @@ -43,8 +43,8 @@ pub(crate) fn emit_facts<'tcx>( emit_universal_region_facts( all_facts, borrow_set, - &universal_regions, - &universal_region_relations, + universal_regions, + universal_region_relations, ); emit_cfg_and_loan_kills_facts(all_facts, tcx, location_table, body, borrow_set); emit_loan_invalidations_facts(all_facts, tcx, location_table, body, borrow_set); diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index bf1c1b1433ea..c56eaaff076c 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -344,7 +344,7 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) { for (reg_var_idx, scc_idx) in sccs.scc_indices().iter().enumerate() { let reg_var = ty::RegionVid::from_usize(reg_var_idx); - let origin = var_to_origin.get(®_var).unwrap_or_else(|| &RegionCtxt::Unknown); + let origin = var_to_origin.get(®_var).unwrap_or(&RegionCtxt::Unknown); components[scc_idx.as_usize()].insert((reg_var, *origin)); } @@ -2216,7 +2216,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // #114907 where this happens via liveness and dropck outlives results. // Therefore, we return a default value in case that happens, which should at worst emit a // suboptimal error, instead of the ICE. - self.universe_causes.get(&universe).cloned().unwrap_or_else(|| UniverseInfo::other()) + self.universe_causes.get(&universe).cloned().unwrap_or_else(UniverseInfo::other) } /// Tries to find the terminator of the loop in which the region 'r' resides. diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 51c3648d7307..67e5c8352df0 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -418,9 +418,7 @@ fn check_opaque_type_parameter_valid<'tcx>( let opaque_param = opaque_generics.param_at(i, tcx); let kind = opaque_param.kind.descr(); - if let Err(guar) = opaque_env.param_is_error(i) { - return Err(guar); - } + opaque_env.param_is_error(i)?; return Err(tcx.dcx().emit_err(NonGenericOpaqueTypeParam { ty: arg, diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index 8b863efad6ca..b777e01f7a6c 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -12,9 +12,7 @@ use rustc_mir_dataflow::ResultsCursor; use std::rc::Rc; use crate::{ - constraints::OutlivesConstraintSet, - facts::{AllFacts, AllFactsExt}, - region_infer::values::LivenessValues, + constraints::OutlivesConstraintSet, region_infer::values::LivenessValues, universal_regions::UniversalRegions, }; @@ -38,7 +36,6 @@ pub(super) fn generate<'mir, 'tcx>( elements: &Rc, flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, move_data: &MoveData<'tcx>, - use_polonius: bool, ) { debug!("liveness::generate"); @@ -49,11 +46,8 @@ pub(super) fn generate<'mir, 'tcx>( ); let (relevant_live_locals, boring_locals) = compute_relevant_live_locals(typeck.tcx(), &free_regions, body); - let facts_enabled = use_polonius || AllFacts::enabled(typeck.tcx()); - if facts_enabled { - polonius::populate_access_facts(typeck, body, move_data); - }; + polonius::populate_access_facts(typeck, body, move_data); trace::trace( typeck, diff --git a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs index d8f03a07a63c..a009e28a0ddd 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs @@ -87,10 +87,10 @@ pub(super) fn populate_access_facts<'a, 'tcx>( body: &Body<'tcx>, move_data: &MoveData<'tcx>, ) { - debug!("populate_access_facts()"); - let location_table = typeck.borrowck_context.location_table; - if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() { + debug!("populate_access_facts()"); + let location_table = typeck.borrowck_context.location_table; + let mut extractor = UseFactsExtractor { var_defined_at: &mut facts.var_defined_at, var_used_at: &mut facts.var_used_at, diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 50843c602cc8..359c4ea0eb1e 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -217,35 +217,52 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> { /// Add facts for all locals with free regions, since regions may outlive /// the function body only at certain nodes in the CFG. fn add_extra_drop_facts(&mut self, relevant_live_locals: &[Local]) -> Option<()> { - let drop_used = self - .cx - .typeck - .borrowck_context - .all_facts - .as_ref() - .map(|facts| facts.var_dropped_at.clone())?; + // This collect is more necessary than immediately apparent + // because these facts go into `add_drop_live_facts_for()`, + // which also writes to `all_facts`, and so this is genuinely + // a simulatneous overlapping mutable borrow. + // FIXME for future hackers: investigate whether this is + // actually necessary; these facts come from Polonius + // and probably maybe plausibly does not need to go back in. + // It may be necessary to just pick out the parts of + // `add_drop_live_facts_for()` that make sense. + let facts_to_add: Vec<_> = { + let drop_used = &self.cx.typeck.borrowck_context.all_facts.as_ref()?.var_dropped_at; - let relevant_live_locals: FxIndexSet<_> = relevant_live_locals.iter().copied().collect(); + let relevant_live_locals: FxIndexSet<_> = + relevant_live_locals.iter().copied().collect(); - let locations = IntervalSet::new(self.cx.elements.num_points()); + drop_used + .iter() + .filter_map(|(local, location_index)| { + let local_ty = self.cx.body.local_decls[*local].ty; + if relevant_live_locals.contains(local) || !local_ty.has_free_regions() { + return None; + } - for (local, location_index) in drop_used { - if !relevant_live_locals.contains(&local) { - let local_ty = self.cx.body.local_decls[local].ty; - if local_ty.has_free_regions() { let location = match self .cx .typeck .borrowck_context .location_table - .to_location(location_index) + .to_location(*location_index) { RichLocation::Start(l) => l, RichLocation::Mid(l) => l, }; - self.cx.add_drop_live_facts_for(local, local_ty, &[location], &locations); - } - } + + Some((*local, local_ty, location)) + }) + .collect() + }; + + // FIXME: these locations seem to have a special meaning (e.g. everywhere, at the end, ...), but I don't know which one. Please help me rename it to something descriptive! + // Also, if this IntervalSet is used in many places, it maybe should have a newtype'd + // name with a description of what it means for future mortals passing by. + let locations = IntervalSet::new(self.cx.elements.num_points()); + + for (local, local_ty, location) in facts_to_add { + self.cx.add_drop_live_facts_for(local, local_ty, &[location], &locations); } Some(()) } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index c7c1b2af6a7b..81bde14a82f4 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -133,7 +133,6 @@ pub(crate) fn type_check<'mir, 'tcx>( move_data: &MoveData<'tcx>, elements: &Rc, upvars: &[&ty::CapturedPlace<'tcx>], - use_polonius: bool, ) -> MirTypeckResults<'tcx> { let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body); let mut constraints = MirTypeckRegionConstraints { @@ -189,7 +188,7 @@ pub(crate) fn type_check<'mir, 'tcx>( checker.equate_inputs_and_outputs(body, universal_regions, &normalized_inputs_and_output); checker.check_signature_annotation(body); - liveness::generate(&mut checker, body, elements, flow_inits, move_data, use_polonius); + liveness::generate(&mut checker, body, elements, flow_inits, move_data); translate_outlives_facts(&mut checker); let opaque_type_values = infcx.take_opaque_types(); diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 2edb34e7c20d..06ca52b39032 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -271,9 +271,9 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attr let opts = &cx.sess().opts; // "mcount" function relies on stack pointer. // See . - if opts.unstable_opts.instrument_mcount || matches!(opts.cg.force_frame_pointers, Some(true)) { - fp = FramePointer::Always; + if opts.unstable_opts.instrument_mcount { + fp.ratchet(FramePointer::Always); } + fp.ratchet(opts.cg.force_frame_pointers); let attr_value = match fp { FramePointer::Always => "all", FramePointer::NonLeaf => "non-leaf", diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 1476fe285ef5..cd269810741e 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -89,6 +89,8 @@ const_eval_exact_div_has_remainder = const_eval_extern_static = cannot access extern static ({$did}) +const_eval_extern_type_field = `extern type` field does not have a known offset + const_eval_fn_ptr_call = function pointers need an RFC before allowed to be called in {const_eval_const_context}s const_eval_for_loop_into_iter_non_const = diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index c60df06bb0ef..d8efaa66415f 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -386,33 +386,8 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( CompileTimeMachine::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error), ); let res = ecx.load_mir(cid.instance.def, cid.promoted); - res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body)).map_err(|error| { - let (error, backtrace) = error.into_parts(); - backtrace.print_backtrace(); - - let (kind, instance) = if ecx.tcx.is_static(cid.instance.def_id()) { - ("static", String::new()) - } else { - // If the current item has generics, we'd like to enrich the message with the - // instance and its args: to show the actual compile-time values, in addition to - // the expression, leading to the const eval error. - let instance = &cid.instance; - if !instance.args.is_empty() { - let instance = with_no_trimmed_paths!(instance.to_string()); - ("const_with_path", instance) - } else { - ("const", String::new()) - } - }; - - super::report( - *ecx.tcx, - error, - DUMMY_SP, - || super::get_span_and_frames(ecx.tcx, ecx.stack()), - |span, frames| ConstEvalError { span, error_kind: kind, instance, frame_notes: frames }, - ) - }) + res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body)) + .map_err(|error| report_eval_error(&ecx, cid, error)) } #[inline(always)] @@ -438,23 +413,60 @@ fn const_validate_mplace<'tcx>( ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode) // Instead of just reporting the `InterpError` via the usual machinery, we give a more targeted // error about the validation failure. - .map_err(|error| report_validation_error(&ecx, error, alloc_id))?; + .map_err(|error| report_validation_error(&ecx, cid, error, alloc_id))?; inner = true; } Ok(()) } -#[inline(always)] -fn report_validation_error<'tcx>( +#[inline(never)] +fn report_eval_error<'tcx>( ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>, + cid: GlobalId<'tcx>, error: InterpErrorInfo<'tcx>, - alloc_id: AllocId, ) -> ErrorHandled { let (error, backtrace) = error.into_parts(); backtrace.print_backtrace(); - let ub_note = matches!(error, InterpError::UndefinedBehavior(_)).then(|| {}); + let (kind, instance) = if ecx.tcx.is_static(cid.instance.def_id()) { + ("static", String::new()) + } else { + // If the current item has generics, we'd like to enrich the message with the + // instance and its args: to show the actual compile-time values, in addition to + // the expression, leading to the const eval error. + let instance = &cid.instance; + if !instance.args.is_empty() { + let instance = with_no_trimmed_paths!(instance.to_string()); + ("const_with_path", instance) + } else { + ("const", String::new()) + } + }; + + super::report( + *ecx.tcx, + error, + DUMMY_SP, + || super::get_span_and_frames(ecx.tcx, ecx.stack()), + |span, frames| ConstEvalError { span, error_kind: kind, instance, frame_notes: frames }, + ) +} + +#[inline(never)] +fn report_validation_error<'tcx>( + ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>, + cid: GlobalId<'tcx>, + error: InterpErrorInfo<'tcx>, + alloc_id: AllocId, +) -> ErrorHandled { + if !matches!(error.kind(), InterpError::UndefinedBehavior(_)) { + // Some other error happened during validation, e.g. an unsupported operation. + return report_eval_error(ecx, cid, error); + } + + let (error, backtrace) = error.into_parts(); + backtrace.print_backtrace(); let bytes = ecx.print_alloc_bytes_for_diagnostics(alloc_id); let (size, align, _) = ecx.get_alloc_info(alloc_id); @@ -465,6 +477,6 @@ fn report_validation_error<'tcx>( error, DUMMY_SP, || crate::const_eval::get_span_and_frames(ecx.tcx, ecx.stack()), - move |span, frames| errors::ValidationFailure { span, ub_note, frames, raw_bytes }, + move |span, frames| errors::ValidationFailure { span, ub_note: (), frames, raw_bytes }, ) } diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 5fa48a59794b..292d6ba9d08a 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -425,7 +425,7 @@ pub struct ValidationFailure { #[primary_span] pub span: Span, #[note(const_eval_validation_failure_note)] - pub ub_note: Option<()>, + pub ub_note: (), #[subdiagnostic] pub frames: Vec, #[subdiagnostic] @@ -825,6 +825,7 @@ impl ReportErrorExt for UnsupportedOpInfo { use crate::fluent_generated::*; match self { UnsupportedOpInfo::Unsupported(s) => s.clone().into(), + UnsupportedOpInfo::ExternTypeField => const_eval_extern_type_field, UnsupportedOpInfo::UnsizedLocal => const_eval_unsized_local, UnsupportedOpInfo::OverwritePartialPointer(_) => const_eval_partial_pointer_overwrite, UnsupportedOpInfo::ReadPartialPointer(_) => const_eval_partial_pointer_copy, @@ -845,7 +846,10 @@ impl ReportErrorExt for UnsupportedOpInfo { // `ReadPointerAsInt(Some(info))` is never printed anyway, it only serves as an error to // be further processed by validity checking which then turns it into something nice to // print. So it's not worth the effort of having diagnostics that can print the `info`. - UnsizedLocal | Unsupported(_) | ReadPointerAsInt(_) => {} + UnsizedLocal + | UnsupportedOpInfo::ExternTypeField + | Unsupported(_) + | ReadPointerAsInt(_) => {} OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => { diag.arg("ptr", ptr); } diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index efa01b543426..cfa814c810af 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -21,7 +21,7 @@ use rustc_target::abi::{self, VariantIdx}; use tracing::{debug, instrument}; use super::{ - throw_ub, throw_unsup_format, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, + throw_ub, throw_unsup, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Provenance, Scalar, }; @@ -186,8 +186,8 @@ where (base_meta, offset) } None => { - // We don't know the alignment of this field, so we cannot adjust. - throw_unsup_format!("`extern type` does not have a known offset") + // We cannot know the alignment of this field, so we cannot adjust. + throw_unsup!(ExternTypeField) } } } else { diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index ca8b98849338..add48e1b186c 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -5,6 +5,7 @@ //! to be const-safe. use std::fmt::Write; +use std::hash::Hash; use std::num::NonZero; use either::{Left, Right}; @@ -17,7 +18,8 @@ use rustc_hir as hir; use rustc_middle::bug; use rustc_middle::mir::interpret::{ ExpectedKind, InterpError, InvalidMetaKind, Misalignment, PointerKind, Provenance, - ValidationErrorInfo, ValidationErrorKind, ValidationErrorKind::*, + UnsupportedOpInfo, ValidationErrorInfo, + ValidationErrorKind::{self, *}, }; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Ty}; @@ -26,8 +28,6 @@ use rustc_target::abi::{ Abi, FieldIdx, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange, }; -use std::hash::Hash; - use super::{ err_ub, format_interp_error, machine::AllocMap, throw_ub, AllocId, AllocKind, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, @@ -1028,7 +1028,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Err(err) if matches!( err.kind(), - err_ub!(ValidationError { .. }) | InterpError::InvalidProgram(_) + err_ub!(ValidationError { .. }) + | InterpError::InvalidProgram(_) + | InterpError::Unsupported(UnsupportedOpInfo::ExternTypeField) ) => { Err(err) diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 6113580491ef..cc0b110d2bc6 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -61,6 +61,9 @@ expand_feature_removed = expand_glob_delegation_outside_impls = glob delegation is only supported in impls +expand_glob_delegation_traitless_qpath = + qualified path without a trait in glob delegation + expand_helper_attribute_name_invalid = `{$name}` cannot be a name of derive helper attribute diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index c883121fb406..0be7403f25b1 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -449,6 +449,13 @@ pub(crate) struct GlobDelegationOutsideImpls { pub span: Span, } +#[derive(Diagnostic)] +#[diag(expand_glob_delegation_traitless_qpath)] +pub(crate) struct GlobDelegationTraitlessQpath { + #[primary_span] + pub span: Span, +} + // This used to be the `proc_macro_back_compat` lint (#83125). It was later // turned into a hard error. #[derive(Diagnostic)] diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 716bfc8c26b1..26fc77c7f33d 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1,8 +1,9 @@ use crate::base::*; use crate::config::StripUnconfigured; use crate::errors::{ - EmptyDelegationMac, GlobDelegationOutsideImpls, IncompleteParse, RecursionLimitReached, - RemoveExprNotSupported, RemoveNodeNotSupported, UnsupportedKeyValue, WrongFragmentKind, + EmptyDelegationMac, GlobDelegationOutsideImpls, GlobDelegationTraitlessQpath, IncompleteParse, + RecursionLimitReached, RemoveExprNotSupported, RemoveNodeNotSupported, UnsupportedKeyValue, + WrongFragmentKind, }; use crate::mbe::diagnostics::annotate_err_with_kind; use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod}; @@ -1882,7 +1883,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { let mut span: Option = None; while let Some(attr) = attrs.next() { rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.sess, features); - validate_attr::check_attr(&self.cx.sess.psess, attr); + validate_attr::check_attr(features, &self.cx.sess.psess, attr); let current_span = if let Some(sp) = span { sp.to(attr.span) } else { attr.span }; span = Some(current_span); @@ -1989,6 +1990,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } None if let Some((deleg, item)) = node.delegation() => { let Some(suffixes) = &deleg.suffixes else { + let traitless_qself = + matches!(&deleg.qself, Some(qself) if qself.position == 0); let item = match node.to_annotatable() { Annotatable::ImplItem(item) => item, ann @ (Annotatable::Item(_) @@ -2000,6 +2003,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } _ => unreachable!(), }; + if traitless_qself { + let span = item.span; + self.cx.dcx().emit_err(GlobDelegationTraitlessQpath { span }); + return Default::default(); + } return self.collect_glob_delegation(item, Node::KIND).make_ast::(); }; diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 0050ff10539a..e43ba7c3a5a8 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -10,7 +10,9 @@ use crate::mbe::transcribe::transcribe; use ast::token::IdentIsRaw; use rustc_ast as ast; -use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind, TokenKind::*}; +use rustc_ast::token::{ + self, Delimiter, NonterminalKind, NtPatKind::*, Token, TokenKind, TokenKind::*, +}; use rustc_ast::tokenstream::{DelimSpan, TokenStream}; use rustc_ast::{NodeId, DUMMY_NODE_ID}; use rustc_ast_pretty::pprust; @@ -1145,14 +1147,17 @@ fn check_matcher_core<'tt>( // Macros defined in the current crate have a real node id, // whereas macros from an external crate have a dummy id. if def.id != DUMMY_NODE_ID - && matches!(kind, NonterminalKind::PatParam { inferred: true }) - && matches!(next_token, TokenTree::Token(token) if token.kind == BinOp(token::BinOpToken::Or)) + && matches!(kind, NonterminalKind::Pat(PatParam { inferred: true })) + && matches!( + next_token, + TokenTree::Token(token) if token.kind == BinOp(token::BinOpToken::Or) + ) { // It is suggestion to use pat_param, for example: $x:pat -> $x:pat_param. let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl( span, name, - Some(NonterminalKind::PatParam { inferred: false }), + Some(NonterminalKind::Pat(PatParam { inferred: false })), )); sess.psess.buffer_lint( RUST_2021_INCOMPATIBLE_OR_PATTERNS, @@ -1185,14 +1190,14 @@ fn check_matcher_core<'tt>( ); err.span_label(sp, format!("not allowed after `{kind}` fragments")); - if kind == NonterminalKind::PatWithOr + if kind == NonterminalKind::Pat(PatWithOr) && sess.psess.edition.at_least_rust_2021() && next_token.is_token(&BinOp(token::BinOpToken::Or)) { let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl( span, name, - Some(NonterminalKind::PatParam { inferred: false }), + Some(NonterminalKind::Pat(PatParam { inferred: false })), )); err.span_suggestion( span, @@ -1292,9 +1297,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { // maintain IsInFollow::Yes } - NonterminalKind::Stmt - | NonterminalKind::Expr - | NonterminalKind::Expr2021 { inferred: _ } => { + NonterminalKind::Stmt | NonterminalKind::Expr(_) => { const TOKENS: &[&str] = &["`=>`", "`,`", "`;`"]; match tok { TokenTree::Token(token) => match token.kind { @@ -1304,7 +1307,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { _ => IsInFollow::No(TOKENS), } } - NonterminalKind::PatParam { .. } => { + NonterminalKind::Pat(PatParam { .. }) => { const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"]; match tok { TokenTree::Token(token) => match token.kind { @@ -1317,7 +1320,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { _ => IsInFollow::No(TOKENS), } } - NonterminalKind::PatWithOr => { + NonterminalKind::Pat(PatWithOr) => { const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`if`", "`in`"]; match tok { TokenTree::Token(token) => match token.kind { diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index fdf187438d3d..9c480f17b421 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -2,7 +2,7 @@ use crate::errors; use crate::mbe::macro_parser::count_metavar_decls; use crate::mbe::{Delimited, KleeneOp, KleeneToken, MetaVarExpr, SequenceRepetition, TokenTree}; -use rustc_ast::token::{self, Delimiter, IdentIsRaw, Token}; +use rustc_ast::token::{self, Delimiter, IdentIsRaw, NonterminalKind, NtExprKind::*, Token}; use rustc_ast::{tokenstream, NodeId}; use rustc_ast_pretty::pprust; use rustc_feature::Features; @@ -85,36 +85,31 @@ pub(super) fn parse( span.edition() } }; - let kind = - token::NonterminalKind::from_symbol(fragment.name, edition) - .unwrap_or_else(|| { - let help = match fragment.name { - sym::expr_2021 => { - format!( - "fragment specifier `expr_2021` \ - requires Rust 2021 or later\n\ - {VALID_FRAGMENT_NAMES_MSG}" - ) - } - _ if edition().at_least_rust_2021() - && features - .expr_fragment_specifier_2024 => - { - VALID_FRAGMENT_NAMES_MSG_2021.into() - } - _ => VALID_FRAGMENT_NAMES_MSG.into(), - }; - sess.dcx().emit_err( - errors::InvalidFragmentSpecifier { - span, - fragment, - help, - }, - ); - token::NonterminalKind::Ident + let kind = NonterminalKind::from_symbol(fragment.name, edition) + .unwrap_or_else(|| { + let help = match fragment.name { + sym::expr_2021 => { + format!( + "fragment specifier `expr_2021` \ + requires Rust 2021 or later\n\ + {VALID_FRAGMENT_NAMES_MSG}" + ) + } + _ if edition().at_least_rust_2021() + && features.expr_fragment_specifier_2024 => + { + VALID_FRAGMENT_NAMES_MSG_2021.into() + } + _ => VALID_FRAGMENT_NAMES_MSG.into(), + }; + sess.dcx().emit_err(errors::InvalidFragmentSpecifier { + span, + fragment, + help, }); - if kind - == (token::NonterminalKind::Expr2021 { inferred: false }) + NonterminalKind::Ident + }); + if kind == NonterminalKind::Expr(Expr2021 { inferred: false }) && !features.expr_fragment_specifier_2024 { rustc_session::parse::feature_err( diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 9e2756f07ede..5e83e0d27e19 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1145,10 +1145,6 @@ pub fn is_valid_for_get_attr(name: Symbol) -> bool { }) } -pub fn is_unsafe_attr(name: Symbol) -> bool { - BUILTIN_ATTRIBUTE_MAP.get(&name).is_some_and(|attr| attr.safety == AttributeSafety::Unsafe) -} - pub static BUILTIN_ATTRIBUTE_MAP: LazyLock> = LazyLock::new(|| { let mut map = FxHashMap::default(); diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index fb3b7c0a1272..bf4293643183 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -125,7 +125,7 @@ pub use accepted::ACCEPTED_FEATURES; pub use builtin_attrs::AttributeDuplicates; pub use builtin_attrs::{ deprecated_attributes, encode_cross_crate, find_gated_cfg, is_builtin_attr_name, - is_unsafe_attr, is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType, + is_valid_for_get_attr, AttributeGate, AttributeSafety, AttributeTemplate, AttributeType, BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, }; pub use removed::REMOVED_FEATURES; diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index fbd67657e3b4..f66c9604cbe0 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -629,7 +629,7 @@ declare_features! ( /// Allows unsafe on extern declarations and safety qualifiers over internal items. (unstable, unsafe_extern_blocks, "1.80.0", Some(123743)), /// Allows unsized fn parameters. - (unstable, unsized_fn_params, "1.49.0", Some(48055)), + (internal, unsized_fn_params, "1.49.0", Some(48055)), /// Allows unsized rvalues at arguments and parameters. (incomplete, unsized_locals, "1.30.0", Some(48055)), /// Allows unsized tuple coercion. diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 9dd82868adc5..b3ebc0621cbd 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -26,10 +26,8 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::middle::stability::EvalResult; use rustc_middle::span_bug; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{ - self, suggest_constraining_type_params, Article, Binder, IsSuggestable, Ty, TypeVisitableExt, - Upcast, -}; +use rustc_middle::ty::{self, suggest_constraining_type_params, Article, Binder}; +use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeVisitableExt, Upcast}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; use rustc_span::symbol::{sym, Ident}; @@ -1111,12 +1109,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.hir().span_with_body(self.tcx.local_def_id_to_hir_id(fn_id)), ) { - err.multipart_suggestion( + // When the expr is in a match arm's body, we shouldn't add semicolon ';' at the end. + // For example: + // fn mismatch_types() -> i32 { + // match 1 { + // x => dbg!(x), + // } + // todo!() + // } + // -------------^^^^^^^- + // Don't add semicolon `;` at the end of `dbg!(x)` expr + fn is_in_arm<'tcx>(expr: &'tcx hir::Expr<'tcx>, tcx: TyCtxt<'tcx>) -> bool { + for (_, node) in tcx.hir().parent_iter(expr.hir_id) { + match node { + hir::Node::Block(block) => { + if let Some(ret) = block.expr + && ret.hir_id == expr.hir_id + { + continue; + } + } + hir::Node::Arm(arm) => { + if let hir::ExprKind::Block(block, _) = arm.body.kind + && let Some(ret) = block.expr + && ret.hir_id == expr.hir_id + { + return true; + } + } + hir::Node::Expr(e) if let hir::ExprKind::Block(block, _) = e.kind => { + if let Some(ret) = block.expr + && ret.hir_id == expr.hir_id + { + continue; + } + } + _ => { + return false; + } + } + } + + false + } + let mut suggs = vec![(span.shrink_to_lo(), "return ".to_string())]; + if !is_in_arm(expr, self.tcx) { + suggs.push((span.shrink_to_hi(), ";".to_string())); + } + err.multipart_suggestion_verbose( "you might have meant to return this value", - vec![ - (span.shrink_to_lo(), "return ".to_string()), - (span.shrink_to_hi(), ";".to_string()), - ], + suggs, Applicability::MaybeIncorrect, ); } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 2909f8adfb0e..6ffc518097ef 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -20,9 +20,9 @@ use rustc_span::source_map::{RealFileLoader, SourceMapInputs}; use rustc_span::symbol::sym; use rustc_span::{FileName, SourceFileHashAlgorithm}; use rustc_target::spec::{ - CodeModel, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel, WasmCAbi, + CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, + RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel, WasmCAbi, }; -use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel}; use std::collections::{BTreeMap, BTreeSet}; use std::num::NonZero; use std::path::{Path, PathBuf}; @@ -605,7 +605,7 @@ fn test_codegen_options_tracking_hash() { tracked!(debug_assertions, Some(true)); tracked!(debuginfo, DebugInfo::Limited); tracked!(embed_bitcode, false); - tracked!(force_frame_pointers, Some(false)); + tracked!(force_frame_pointers, FramePointer::Always); tracked!(force_unwind_tables, Some(true)); tracked!(inline_threshold, Some(0xf007ba11)); tracked!(instrument_coverage, InstrumentCoverage::Yes); diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index fdedf2c2e6d3..eac5083ffbf0 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -825,6 +825,10 @@ lint_unnameable_test_items = cannot test inner items lint_unnecessary_qualification = unnecessary qualification .suggestion = remove the unnecessary path segments +lint_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe + .label = usage of unsafe attribute +lint_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)` + lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´ lint_untranslatable_diag = diagnostics should be created using translatable messages diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index 290bb5173dbe..adb2a3275c0a 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -319,6 +319,16 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: & BuiltinLintDiag::UnusedQualifications { removal_span } => { lints::UnusedQualifications { removal_span }.decorate_lint(diag); } + BuiltinLintDiag::UnsafeAttrOutsideUnsafe { + attribute_name_span, + sugg_spans: (left, right), + } => { + lints::UnsafeAttrOutsideUnsafe { + span: attribute_name_span, + suggestion: lints::UnsafeAttrOutsideUnsafeSuggestion { left, right }, + } + .decorate_lint(diag); + } BuiltinLintDiag::AssociatedConstElidedLifetime { elided, span: lt_span, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index b26d04d06180..6df3a11deb00 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2890,3 +2890,24 @@ pub struct RedundantImportVisibility { pub import_vis: String, pub max_vis: String, } + +#[derive(LintDiagnostic)] +#[diag(lint_unsafe_attr_outside_unsafe)] +pub struct UnsafeAttrOutsideUnsafe { + #[label] + pub span: Span, + #[subdiagnostic] + pub suggestion: UnsafeAttrOutsideUnsafeSuggestion, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + lint_unsafe_attr_outside_unsafe_suggestion, + applicability = "machine-applicable" +)] +pub struct UnsafeAttrOutsideUnsafeSuggestion { + #[suggestion_part(code = "unsafe(")] + pub left: Span, + #[suggestion_part(code = ")")] + pub right: Span, +} diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 1913b9d6a1c3..265779c93747 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -115,6 +115,7 @@ declare_lint_pass! { UNNAMEABLE_TYPES, UNREACHABLE_CODE, UNREACHABLE_PATTERNS, + UNSAFE_ATTR_OUTSIDE_UNSAFE, UNSAFE_OP_IN_UNSAFE_FN, UNSTABLE_NAME_COLLISIONS, UNSTABLE_SYNTAX_PRE_EXPANSION, @@ -4902,3 +4903,45 @@ declare_lint! { reference: "issue #123743 ", }; } + +declare_lint! { + /// The `unsafe_attr_outside_unsafe` lint detects a missing unsafe keyword + /// on attributes considered unsafe. + /// + /// ### Example + /// + /// ```rust + /// #![feature(unsafe_attributes)] + /// #![warn(unsafe_attr_outside_unsafe)] + /// + /// #[no_mangle] + /// extern "C" fn foo() {} + /// + /// fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Some attributes (e.g. `no_mangle`, `export_name`, `link_section` -- see + /// [issue #82499] for a more complete list) are considered "unsafe" attributes. + /// An unsafe attribute must only be used inside unsafe(...). + /// + /// This lint can automatically wrap the attributes in `unsafe(...)` , but this + /// obviously cannot verify that the preconditions of the `unsafe` + /// attributes are fulfilled, so that is still up to the user. + /// + /// The lint is currently "allow" by default, but that might change in the + /// future. + /// + /// [editions]: https://doc.rust-lang.org/edition-guide/ + /// [issue #82499]: https://github.com/rust-lang/rust/issues/82499 + pub UNSAFE_ATTR_OUTSIDE_UNSAFE, + Allow, + "detects unsafe attributes outside of unsafe", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024), + reference: "issue #123757 ", + }; +} diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index b3838f915f6b..f33aadfbbc84 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -691,6 +691,10 @@ pub enum BuiltinLintDiag { /// The span of the unnecessarily-qualified path to remove. removal_span: Span, }, + UnsafeAttrOutsideUnsafe { + attribute_name_span: Span, + sugg_spans: (Span, Span), + }, AssociatedConstElidedLifetime { elided: bool, span: Span, diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 23680f143970..6a8498abaf93 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -520,6 +520,8 @@ pub enum UnsupportedOpInfo { Unsupported(String), /// Unsized local variables. UnsizedLocal, + /// Extern type field with an indeterminate offset. + ExternTypeField, // // The variants below are only reachable from CTFE/const prop, miri will never emit them. // diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 7c8b0ec671a4..c97af68c29e5 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -1047,6 +1047,12 @@ impl<'tcx> PatRangeBoundary<'tcx> { let b = other.eval_bits(ty, tcx, param_env); match ty.kind() { + ty::Float(ty::FloatTy::F16) => { + use rustc_apfloat::Float; + let a = rustc_apfloat::ieee::Half::from_bits(a); + let b = rustc_apfloat::ieee::Half::from_bits(b); + a.partial_cmp(&b) + } ty::Float(ty::FloatTy::F32) => { use rustc_apfloat::Float; let a = rustc_apfloat::ieee::Single::from_bits(a); @@ -1059,6 +1065,12 @@ impl<'tcx> PatRangeBoundary<'tcx> { let b = rustc_apfloat::ieee::Double::from_bits(b); a.partial_cmp(&b) } + ty::Float(ty::FloatTy::F128) => { + use rustc_apfloat::Float; + let a = rustc_apfloat::ieee::Quad::from_bits(a); + let b = rustc_apfloat::ieee::Quad::from_bits(b); + a.partial_cmp(&b) + } ty::Int(ity) => { let size = rustc_target::abi::Integer::from_int_ty(&tcx, *ity).size(); let a = size.sign_extend(a) as i128; diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 1b5efcee9035..9307e3806812 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1196,7 +1196,7 @@ impl<'tcx> Ty<'tcx> { /// Returns the minimum and maximum values for the given numeric type (including `char`s) or /// returns `None` if the type is not numeric. pub fn numeric_min_and_max_as_bits(self, tcx: TyCtxt<'tcx>) -> Option<(u128, u128)> { - use rustc_apfloat::ieee::{Double, Single}; + use rustc_apfloat::ieee::{Double, Half, Quad, Single}; Some(match self.kind() { ty::Int(_) | ty::Uint(_) => { let (size, signed) = self.int_size_and_signed(tcx); @@ -1206,12 +1206,14 @@ impl<'tcx> Ty<'tcx> { (min, max) } ty::Char => (0, std::char::MAX as u128), + ty::Float(ty::FloatTy::F16) => ((-Half::INFINITY).to_bits(), Half::INFINITY.to_bits()), ty::Float(ty::FloatTy::F32) => { ((-Single::INFINITY).to_bits(), Single::INFINITY.to_bits()) } ty::Float(ty::FloatTy::F64) => { ((-Double::INFINITY).to_bits(), Double::INFINITY.to_bits()) } + ty::Float(ty::FloatTy::F128) => ((-Quad::INFINITY).to_bits(), Quad::INFINITY.to_bits()), _ => return None, }) } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 192d706bce2c..dda6c88008bb 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -369,10 +369,10 @@ impl<'tcx> ConstToPat<'tcx> { ty::Float(flt) => { let v = cv.unwrap_leaf(); let is_nan = match flt { - ty::FloatTy::F16 => unimplemented!("f16_f128"), + ty::FloatTy::F16 => v.to_f16().is_nan(), ty::FloatTy::F32 => v.to_f32().is_nan(), ty::FloatTy::F64 => v.to_f64().is_nan(), - ty::FloatTy::F128 => unimplemented!("f16_f128"), + ty::FloatTy::F128 => v.to_f128().is_nan(), }; if is_nan { // NaNs are not ever equal to anything so they make no sense as patterns. diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index efb9526eabcf..f08efe60d96b 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -366,6 +366,10 @@ parse_inner_doc_comment_not_permitted = expected outer doc comment .label_does_not_annotate_this = the inner doc comment doesn't annotate this {$item} .sugg_change_inner_to_outer = to annotate the {$item}, change the doc comment from inner to outer style +parse_invalid_attr_unsafe = `{$name}` is not an unsafe attribute + .suggestion = remove the `unsafe(...)` + .note = extraneous unsafe is not allowed in attributes + parse_invalid_block_macro_segment = cannot use a `block` macro fragment here .label = the `block` fragment is within this context .suggestion = wrap this in another block @@ -866,6 +870,11 @@ parse_unmatched_angle_brackets = {$num_extra_brackets -> *[other] remove extra angle brackets } +parse_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe + .label = usage of unsafe attribute +parse_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)` + + parse_unskipped_whitespace = whitespace symbol '{$ch}' is not skipped .label = {parse_unskipped_whitespace} diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 46e157348530..8d49887f1644 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2997,3 +2997,34 @@ pub(crate) struct DotDotRangeAttribute { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(parse_invalid_attr_unsafe)] +#[note] +pub struct InvalidAttrUnsafe { + #[primary_span] + pub span: Span, + pub name: Path, +} + +#[derive(Diagnostic)] +#[diag(parse_unsafe_attr_outside_unsafe)] +pub struct UnsafeAttrOutsideUnsafe { + #[primary_span] + #[label] + pub span: Span, + #[subdiagnostic] + pub suggestion: UnsafeAttrOutsideUnsafeSuggestion, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + parse_unsafe_attr_outside_unsafe_suggestion, + applicability = "machine-applicable" +)] +pub struct UnsafeAttrOutsideUnsafeSuggestion { + #[suggestion_part(code = "unsafe(")] + pub left: Span, + #[suggestion_part(code = ")")] + pub right: Span, +} diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 59f6eff07b32..4a78b427832c 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -1,5 +1,7 @@ use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, Nonterminal::*, NonterminalKind, Token}; +use rustc_ast::token::{ + self, Delimiter, Nonterminal::*, NonterminalKind, NtExprKind::*, NtPatKind::*, Token, +}; use rustc_ast::HasTokens; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; @@ -36,14 +38,14 @@ impl<'a> Parser<'a> { } match kind { - NonterminalKind::Expr2021 { inferred: _ } => { + NonterminalKind::Expr(Expr2021 { .. }) => { token.can_begin_expr() // This exception is here for backwards compatibility. && !token.is_keyword(kw::Let) // This exception is here for backwards compatibility. && !token.is_keyword(kw::Const) } - NonterminalKind::Expr => { + NonterminalKind::Expr(Expr) => { token.can_begin_expr() // This exception is here for backwards compatibility. && !token.is_keyword(kw::Let) @@ -74,7 +76,7 @@ impl<'a> Parser<'a> { token::Interpolated(nt) => may_be_ident(nt), _ => false, }, - NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => match &token.kind { + NonterminalKind::Pat(pat_kind) => match &token.kind { // box, ref, mut, and other identifiers (can stricten) token::Ident(..) | token::NtIdent(..) | token::OpenDelim(Delimiter::Parenthesis) | // tuple pattern @@ -89,7 +91,7 @@ impl<'a> Parser<'a> { token::Lt | // path (UFCS constant) token::BinOp(token::Shl) => true, // path (double UFCS) // leading vert `|` or-pattern - token::BinOp(token::Or) => matches!(kind, NonterminalKind::PatWithOr), + token::BinOp(token::Or) => matches!(pat_kind, PatWithOr), token::Interpolated(nt) => may_be_ident(nt), _ => false, }, @@ -135,31 +137,25 @@ impl<'a> Parser<'a> { .create_err(UnexpectedNonterminal::Statement(self.token.span))); } }, - NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => { - NtPat(self.collect_tokens_no_attrs(|this| match kind { - NonterminalKind::PatParam { .. } => this.parse_pat_no_top_alt(None, None), - NonterminalKind::PatWithOr => this.parse_pat_allow_top_alt( + NonterminalKind::Pat(pat_kind) => { + NtPat(self.collect_tokens_no_attrs(|this| match pat_kind { + PatParam { .. } => this.parse_pat_no_top_alt(None, None), + PatWithOr => this.parse_pat_allow_top_alt( None, RecoverComma::No, RecoverColon::No, CommaRecoveryMode::EitherTupleOrPipe, ), - _ => unreachable!(), })?) } - - NonterminalKind::Expr | NonterminalKind::Expr2021 { inferred: _ } => { - NtExpr(self.parse_expr_force_collect()?) - } + NonterminalKind::Expr(_) => NtExpr(self.parse_expr_force_collect()?), NonterminalKind::Literal => { // The `:literal` matcher does not support attributes NtLiteral(self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?) } - NonterminalKind::Ty => { NtTy(self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?) } - // this could be handled like a token, since it is one NonterminalKind::Ident => { return if let Some((ident, is_raw)) = get_macro_ident(&self.token) { diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 4ca52146039c..bcb1131cc196 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -5,21 +5,73 @@ use crate::{errors, parse_in}; use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; use rustc_ast::MetaItemKind; -use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, Attribute, DelimArgs, MetaItem}; +use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, Attribute, DelimArgs, MetaItem, Safety}; use rustc_errors::{Applicability, FatalError, PResult}; -use rustc_feature::{AttributeTemplate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; +use rustc_feature::{ + AttributeSafety, AttributeTemplate, BuiltinAttribute, Features, BUILTIN_ATTRIBUTE_MAP, +}; use rustc_session::errors::report_lit_error; -use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; +use rustc_session::lint::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNSAFE_ATTR_OUTSIDE_UNSAFE}; use rustc_session::lint::BuiltinLintDiag; use rustc_session::parse::ParseSess; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{sym, BytePos, Span, Symbol}; -pub fn check_attr(psess: &ParseSess, attr: &Attribute) { +pub fn check_attr(features: &Features, psess: &ParseSess, attr: &Attribute) { if attr.is_doc_comment() { return; } let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); + let attr_item = attr.get_normal_item(); + + let is_unsafe_attr = attr_info.is_some_and(|attr| attr.safety == AttributeSafety::Unsafe); + + if features.unsafe_attributes { + if is_unsafe_attr { + if let ast::Safety::Default = attr_item.unsafety { + let path_span = attr_item.path.span; + + // If the `attr_item`'s span is not from a macro, then just suggest + // wrapping it in `unsafe(...)`. Otherwise, we suggest putting the + // `unsafe(`, `)` right after and right before the opening and closing + // square bracket respectively. + let diag_span = if attr_item.span().can_be_used_for_suggestions() { + attr_item.span() + } else { + attr.span + .with_lo(attr.span.lo() + BytePos(2)) + .with_hi(attr.span.hi() - BytePos(1)) + }; + + if attr.span.at_least_rust_2024() { + psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe { + span: path_span, + suggestion: errors::UnsafeAttrOutsideUnsafeSuggestion { + left: diag_span.shrink_to_lo(), + right: diag_span.shrink_to_hi(), + }, + }); + } else { + psess.buffer_lint( + UNSAFE_ATTR_OUTSIDE_UNSAFE, + path_span, + ast::CRATE_NODE_ID, + BuiltinLintDiag::UnsafeAttrOutsideUnsafe { + attribute_name_span: path_span, + sugg_spans: (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()), + }, + ); + } + } + } else { + if let Safety::Unsafe(unsafe_span) = attr_item.unsafety { + psess.dcx().emit_err(errors::InvalidAttrUnsafe { + span: unsafe_span, + name: attr_item.path.clone(), + }); + } + } + } // Check input tokens for built-in and key-value attributes. match attr_info { @@ -32,7 +84,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) { } } } - _ if let AttrArgs::Eq(..) = attr.get_normal_item().args => { + _ if let AttrArgs::Eq(..) = attr_item.args => { // All key-value attributes are restricted to meta-item syntax. match parse_meta(psess, attr) { Ok(_) => {} diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 84c71c4bed29..9a830b0f49ba 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -384,10 +384,6 @@ passes_invalid_attr_at_crate_level = passes_invalid_attr_at_crate_level_item = the inner attribute doesn't annotate this {$kind} -passes_invalid_attr_unsafe = `{$name}` is not an unsafe attribute - .suggestion = remove the `unsafe(...)` - .note = extraneous unsafe is not allowed in attributes - passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index a0b3470df6db..2ed5bba85c60 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -10,9 +10,7 @@ use rustc_ast::{MetaItemKind, MetaItemLit, NestedMetaItem}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, IntoDiagArg, MultiSpan}; use rustc_errors::{DiagCtxtHandle, StashKey}; -use rustc_feature::{ - is_unsafe_attr, AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP, -}; +use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use rustc_hir::def_id::LocalModDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir}; @@ -116,8 +114,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let mut seen = FxHashMap::default(); let attrs = self.tcx.hir().attrs(hir_id); for attr in attrs { - self.check_unsafe_attr(attr); - match attr.path().as_slice() { [sym::diagnostic, sym::do_not_recommend] => { self.check_do_not_recommend(attr.span, hir_id, target) @@ -312,21 +308,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { true } - /// Checks if `unsafe()` is applied to an invalid attribute. - fn check_unsafe_attr(&self, attr: &Attribute) { - if !attr.is_doc_comment() { - let attr_item = attr.get_normal_item(); - if let ast::Safety::Unsafe(unsafe_span) = attr_item.unsafety { - if !is_unsafe_attr(attr.name_or_empty()) { - self.dcx().emit_err(errors::InvalidAttrUnsafe { - span: unsafe_span, - name: attr_item.path.clone(), - }); - } - } - } - } - /// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition fn check_diagnostic_on_unimplemented( &self, diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index d27b94ebd22a..f05965680920 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -4,7 +4,7 @@ use std::{ }; use crate::fluent_generated as fluent; -use rustc_ast::{ast, Label}; +use rustc_ast::Label; use rustc_errors::{ codes::*, Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic, @@ -863,15 +863,6 @@ pub struct InvalidAttrAtCrateLevel { pub item: Option, } -#[derive(Diagnostic)] -#[diag(passes_invalid_attr_unsafe)] -#[note] -pub struct InvalidAttrUnsafe { - #[primary_span] - pub span: Span, - pub name: ast::Path, -} - #[derive(Clone, Copy)] pub struct ItemFollowingInnerAttr { pub span: Span, diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index 44f09b66bf6c..fb1037054759 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -182,7 +182,7 @@ use std::iter::once; use smallvec::SmallVec; -use rustc_apfloat::ieee::{DoubleS, IeeeFloat, SingleS}; +use rustc_apfloat::ieee::{DoubleS, HalfS, IeeeFloat, QuadS, SingleS}; use rustc_index::bit_set::{BitSet, GrowableBitSet}; use rustc_index::IndexVec; @@ -692,8 +692,10 @@ pub enum Constructor { /// Ranges of integer literal values (`2`, `2..=5` or `2..5`). IntRange(IntRange), /// Ranges of floating-point literal values (`2.0..=5.2`). + F16Range(IeeeFloat, IeeeFloat, RangeEnd), F32Range(IeeeFloat, IeeeFloat, RangeEnd), F64Range(IeeeFloat, IeeeFloat, RangeEnd), + F128Range(IeeeFloat, IeeeFloat, RangeEnd), /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately. Str(Cx::StrLit), /// Constants that must not be matched structurally. They are treated as black boxes for the @@ -735,8 +737,10 @@ impl Clone for Constructor { Constructor::UnionField => Constructor::UnionField, Constructor::Bool(b) => Constructor::Bool(*b), Constructor::IntRange(range) => Constructor::IntRange(*range), + Constructor::F16Range(lo, hi, end) => Constructor::F16Range(lo.clone(), *hi, *end), Constructor::F32Range(lo, hi, end) => Constructor::F32Range(lo.clone(), *hi, *end), Constructor::F64Range(lo, hi, end) => Constructor::F64Range(lo.clone(), *hi, *end), + Constructor::F128Range(lo, hi, end) => Constructor::F128Range(lo.clone(), *hi, *end), Constructor::Str(value) => Constructor::Str(value.clone()), Constructor::Opaque(inner) => Constructor::Opaque(inner.clone()), Constructor::Or => Constructor::Or, @@ -812,6 +816,14 @@ impl Constructor { (Bool(self_b), Bool(other_b)) => self_b == other_b, (IntRange(self_range), IntRange(other_range)) => self_range.is_subrange(other_range), + (F16Range(self_from, self_to, self_end), F16Range(other_from, other_to, other_end)) => { + self_from.ge(other_from) + && match self_to.partial_cmp(other_to) { + Some(Ordering::Less) => true, + Some(Ordering::Equal) => other_end == self_end, + _ => false, + } + } (F32Range(self_from, self_to, self_end), F32Range(other_from, other_to, other_end)) => { self_from.ge(other_from) && match self_to.partial_cmp(other_to) { @@ -828,6 +840,17 @@ impl Constructor { _ => false, } } + ( + F128Range(self_from, self_to, self_end), + F128Range(other_from, other_to, other_end), + ) => { + self_from.ge(other_from) + && match self_to.partial_cmp(other_to) { + Some(Ordering::Less) => true, + Some(Ordering::Equal) => other_end == self_end, + _ => false, + } + } (Str(self_val), Str(other_val)) => { // FIXME Once valtrees are available we can directly use the bytes // in the `Str` variant of the valtree for the comparison here. @@ -906,8 +929,10 @@ impl Constructor { Bool(b) => write!(f, "{b}")?, // Best-effort, will render signed ranges incorrectly IntRange(range) => write!(f, "{range:?}")?, + F16Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?, F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?, F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?, + F128Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?, Str(value) => write!(f, "{value:?}")?, Opaque(..) => write!(f, "")?, Or => { diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 8391c694c64b..d4dd4dd858c2 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -247,8 +247,9 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } _ => bug!("bad slice pattern {:?} {:?}", ctor, ty), }, - Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..) - | Never | NonExhaustive | Hidden | Missing | PrivateUninhabited | Wildcard => &[], + Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..) + | F128Range(..) | Str(..) | Opaque(..) | Never | NonExhaustive | Hidden | Missing + | PrivateUninhabited | Wildcard => &[], Or => { bug!("called `Fields::wildcards` on an `Or` ctor") } @@ -275,8 +276,9 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { }, Ref => 1, Slice(slice) => slice.arity(), - Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..) - | Never | NonExhaustive | Hidden | Missing | PrivateUninhabited | Wildcard => 0, + Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..) + | F128Range(..) | Str(..) | Opaque(..) | Never | NonExhaustive | Hidden | Missing + | PrivateUninhabited | Wildcard => 0, Or => bug!("The `Or` constructor doesn't have a fixed arity"), } } @@ -546,6 +548,18 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { fields = vec![]; arity = 0; } + ty::Float(ty::FloatTy::F16) => { + ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { + Some(bits) => { + use rustc_apfloat::Float; + let value = rustc_apfloat::ieee::Half::from_bits(bits); + F16Range(value, value, RangeEnd::Included) + } + None => Opaque(OpaqueId::new()), + }; + fields = vec![]; + arity = 0; + } ty::Float(ty::FloatTy::F32) => { ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { Some(bits) => { @@ -570,6 +584,18 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { fields = vec![]; arity = 0; } + ty::Float(ty::FloatTy::F128) => { + ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { + Some(bits) => { + use rustc_apfloat::Float; + let value = rustc_apfloat::ieee::Quad::from_bits(bits); + F128Range(value, value, RangeEnd::Included) + } + None => Opaque(OpaqueId::new()), + }; + fields = vec![]; + arity = 0; + } ty::Ref(_, t, _) if t.is_str() => { // We want a `&str` constant to behave like a `Deref` pattern, to be compatible // with other `Deref` patterns. This could have been done in `const_to_pat`, @@ -611,7 +637,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { let lo = lo.as_finite().map(|c| c.eval_bits(cx.tcx, cx.param_env)); let hi = hi.as_finite().map(|c| c.eval_bits(cx.tcx, cx.param_env)); match fty { - ty::FloatTy::F16 => unimplemented!("f16_f128"), + ty::FloatTy::F16 => { + use rustc_apfloat::ieee::Half; + let lo = lo.map(Half::from_bits).unwrap_or(-Half::INFINITY); + let hi = hi.map(Half::from_bits).unwrap_or(Half::INFINITY); + F16Range(lo, hi, end) + } ty::FloatTy::F32 => { use rustc_apfloat::ieee::Single; let lo = lo.map(Single::from_bits).unwrap_or(-Single::INFINITY); @@ -624,7 +655,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { let hi = hi.map(Double::from_bits).unwrap_or(Double::INFINITY); F64Range(lo, hi, end) } - ty::FloatTy::F128 => unimplemented!("f16_f128"), + ty::FloatTy::F128 => { + use rustc_apfloat::ieee::Quad; + let lo = lo.map(Quad::from_bits).unwrap_or(-Quad::INFINITY); + let hi = hi.map(Quad::from_bits).unwrap_or(Quad::INFINITY); + F128Range(lo, hi, end) + } } } _ => bug!("invalid type for range pattern: {}", ty.inner()), @@ -837,7 +873,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug, `Missing` should have been processed in `apply_constructors`" ), - F32Range(..) | F64Range(..) | Opaque(..) | Or => { + F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Opaque(..) | Or => { bug!("can't convert to pattern: {:?}", pat) } }; diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 24143808ef49..839cc51efcea 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -19,7 +19,7 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION}; use rustc_span::source_map::FilePathMapping; use rustc_span::{FileName, FileNameDisplayPreference, RealFileName, SourceFileHashAlgorithm}; -use rustc_target::spec::{LinkSelfContainedComponents, LinkerFeatures}; +use rustc_target::spec::{FramePointer, LinkSelfContainedComponents, LinkerFeatures}; use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple}; use std::collections::btree_map::{ Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter, @@ -2524,6 +2524,15 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M } } + if !nightly_options::is_unstable_enabled(matches) + && cg.force_frame_pointers == FramePointer::NonLeaf + { + early_dcx.early_fatal( + "`-Cforce-frame-pointers=non-leaf` or `always` also requires `-Zunstable-options` \ + and a nightly compiler", + ) + } + // For testing purposes, until we have more feedback about these options: ensure `-Z // unstable-options` is required when using the unstable `-C link-self-contained` and `-C // linker-flavor` options. @@ -2966,10 +2975,8 @@ pub(crate) mod dep_tracking { use rustc_span::edition::Edition; use rustc_span::RealFileName; use rustc_target::spec::{ - CodeModel, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel, WasmCAbi, - }; - use rustc_target::spec::{ - RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, + CodeModel, FramePointer, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel, + RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, WasmCAbi, }; use std::collections::BTreeMap; use std::hash::{DefaultHasher, Hash}; @@ -3023,6 +3030,7 @@ pub(crate) mod dep_tracking { lint::Level, WasiExecModel, u32, + FramePointer, RelocModel, CodeModel, TlsModel, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 145af50117cb..f068d0938897 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -12,10 +12,9 @@ use rustc_span::edition::Edition; use rustc_span::RealFileName; use rustc_span::SourceFileHashAlgorithm; use rustc_target::spec::{ - CodeModel, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, SanitizerSet, WasmCAbi, -}; -use rustc_target::spec::{ - RelocModel, RelroLevel, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, + CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, + RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, + WasmCAbi, }; use std::collections::BTreeMap; use std::hash::{DefaultHasher, Hasher}; @@ -374,6 +373,7 @@ mod desc { pub const parse_opt_comma_list: &str = parse_comma_list; pub const parse_number: &str = "a number"; pub const parse_opt_number: &str = parse_number; + pub const parse_frame_pointer: &str = "one of `true`/`yes`/`on`, `false`/`no`/`off`, or (with -Zunstable-options) `non-leaf` or `always`"; pub const parse_threads: &str = parse_number; pub const parse_time_passes_format: &str = "`text` (default) or `json`"; pub const parse_passes: &str = "a space-separated list of passes, or `all`"; @@ -672,6 +672,18 @@ mod parse { } } + pub(crate) fn parse_frame_pointer(slot: &mut FramePointer, v: Option<&str>) -> bool { + let mut yes = false; + match v { + _ if parse_bool(&mut yes, v) && yes => slot.ratchet(FramePointer::Always), + _ if parse_bool(&mut yes, v) => slot.ratchet(FramePointer::MayOmit), + Some("always") => slot.ratchet(FramePointer::Always), + Some("non-leaf") => slot.ratchet(FramePointer::NonLeaf), + _ => return false, + }; + true + } + pub(crate) fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool { match v { Some("all") => { @@ -1479,7 +1491,7 @@ options! { "emit bitcode in rlibs (default: yes)"), extra_filename: String = (String::new(), parse_string, [UNTRACKED], "extra data to put in each output filename"), - force_frame_pointers: Option = (None, parse_opt_bool, [TRACKED], + force_frame_pointers: FramePointer = (FramePointer::MayOmit, parse_frame_pointer, [TRACKED], "force use of the frame pointers"), #[rustc_lint_opt_deny_field_access("use `Session::must_emit_unwind_tables` instead of this field")] force_unwind_tables: Option = (None, parse_opt_bool, [TRACKED], diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index a8123fe994c3..8d8f4927e99c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -167,6 +167,7 @@ symbols! { Break, C, CStr, + C_dash_unwind: "C-unwind", CallOnceFuture, CallRefFuture, Capture, diff --git a/compiler/rustc_target/src/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs index 9d79faadd619..70fcaab18475 100644 --- a/compiler/rustc_target/src/asm/arm.rs +++ b/compiler/rustc_target/src/asm/arm.rs @@ -148,22 +148,22 @@ def_regs! { r11: reg = ["r11", "fp"] % frame_pointer_r11, r12: reg = ["r12", "ip"] % not_thumb1, r14: reg = ["r14", "lr"] % not_thumb1, - s0: sreg, sreg_low16 = ["s0"], - s1: sreg, sreg_low16 = ["s1"], - s2: sreg, sreg_low16 = ["s2"], - s3: sreg, sreg_low16 = ["s3"], - s4: sreg, sreg_low16 = ["s4"], - s5: sreg, sreg_low16 = ["s5"], - s6: sreg, sreg_low16 = ["s6"], - s7: sreg, sreg_low16 = ["s7"], - s8: sreg, sreg_low16 = ["s8"], - s9: sreg, sreg_low16 = ["s9"], - s10: sreg, sreg_low16 = ["s10"], - s11: sreg, sreg_low16 = ["s11"], - s12: sreg, sreg_low16 = ["s12"], - s13: sreg, sreg_low16 = ["s13"], - s14: sreg, sreg_low16 = ["s14"], - s15: sreg, sreg_low16 = ["s15"], + s0: sreg_low16, sreg = ["s0"], + s1: sreg_low16, sreg = ["s1"], + s2: sreg_low16, sreg = ["s2"], + s3: sreg_low16, sreg = ["s3"], + s4: sreg_low16, sreg = ["s4"], + s5: sreg_low16, sreg = ["s5"], + s6: sreg_low16, sreg = ["s6"], + s7: sreg_low16, sreg = ["s7"], + s8: sreg_low16, sreg = ["s8"], + s9: sreg_low16, sreg = ["s9"], + s10: sreg_low16, sreg = ["s10"], + s11: sreg_low16, sreg = ["s11"], + s12: sreg_low16, sreg = ["s12"], + s13: sreg_low16, sreg = ["s13"], + s14: sreg_low16, sreg = ["s14"], + s15: sreg_low16, sreg = ["s15"], s16: sreg = ["s16"], s17: sreg = ["s17"], s18: sreg = ["s18"], @@ -180,22 +180,22 @@ def_regs! { s29: sreg = ["s29"], s30: sreg = ["s30"], s31: sreg = ["s31"], - d0: dreg, dreg_low16, dreg_low8 = ["d0"], - d1: dreg, dreg_low16, dreg_low8 = ["d1"], - d2: dreg, dreg_low16, dreg_low8 = ["d2"], - d3: dreg, dreg_low16, dreg_low8 = ["d3"], - d4: dreg, dreg_low16, dreg_low8 = ["d4"], - d5: dreg, dreg_low16, dreg_low8 = ["d5"], - d6: dreg, dreg_low16, dreg_low8 = ["d6"], - d7: dreg, dreg_low16, dreg_low8 = ["d7"], - d8: dreg, dreg_low16 = ["d8"], - d9: dreg, dreg_low16 = ["d9"], - d10: dreg, dreg_low16 = ["d10"], - d11: dreg, dreg_low16 = ["d11"], - d12: dreg, dreg_low16 = ["d12"], - d13: dreg, dreg_low16 = ["d13"], - d14: dreg, dreg_low16 = ["d14"], - d15: dreg, dreg_low16 = ["d15"], + d0: dreg_low8, dreg_low16, dreg = ["d0"], + d1: dreg_low8, dreg_low16, dreg = ["d1"], + d2: dreg_low8, dreg_low16, dreg = ["d2"], + d3: dreg_low8, dreg_low16, dreg = ["d3"], + d4: dreg_low8, dreg_low16, dreg = ["d4"], + d5: dreg_low8, dreg_low16, dreg = ["d5"], + d6: dreg_low8, dreg_low16, dreg = ["d6"], + d7: dreg_low8, dreg_low16, dreg = ["d7"], + d8: dreg_low16, dreg = ["d8"], + d9: dreg_low16, dreg = ["d9"], + d10: dreg_low16, dreg = ["d10"], + d11: dreg_low16, dreg = ["d11"], + d12: dreg_low16, dreg = ["d12"], + d13: dreg_low16, dreg = ["d13"], + d14: dreg_low16, dreg = ["d14"], + d15: dreg_low16, dreg = ["d15"], d16: dreg = ["d16"], d17: dreg = ["d17"], d18: dreg = ["d18"], @@ -212,14 +212,14 @@ def_regs! { d29: dreg = ["d29"], d30: dreg = ["d30"], d31: dreg = ["d31"], - q0: qreg, qreg_low8, qreg_low4 = ["q0"], - q1: qreg, qreg_low8, qreg_low4 = ["q1"], - q2: qreg, qreg_low8, qreg_low4 = ["q2"], - q3: qreg, qreg_low8, qreg_low4 = ["q3"], - q4: qreg, qreg_low8 = ["q4"], - q5: qreg, qreg_low8 = ["q5"], - q6: qreg, qreg_low8 = ["q6"], - q7: qreg, qreg_low8 = ["q7"], + q0: qreg_low4, qreg_low8, qreg = ["q0"], + q1: qreg_low4, qreg_low8, qreg = ["q1"], + q2: qreg_low4, qreg_low8, qreg = ["q2"], + q3: qreg_low4, qreg_low8, qreg = ["q3"], + q4: qreg_low8, qreg = ["q4"], + q5: qreg_low8, qreg = ["q5"], + q6: qreg_low8, qreg = ["q6"], + q7: qreg_low8, qreg = ["q7"], q8: qreg = ["q8"], q9: qreg = ["q9"], q10: qreg = ["q10"], diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 62ccc57f421a..81ada30a5943 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1413,6 +1413,20 @@ pub enum FramePointer { MayOmit, } +impl FramePointer { + /// It is intended that the "force frame pointer" transition is "one way" + /// so this convenience assures such if used + #[inline] + pub fn ratchet(&mut self, rhs: FramePointer) -> FramePointer { + *self = match (*self, rhs) { + (FramePointer::Always, _) | (_, FramePointer::Always) => FramePointer::Always, + (FramePointer::NonLeaf, _) | (_, FramePointer::NonLeaf) => FramePointer::NonLeaf, + _ => FramePointer::MayOmit, + }; + *self + } +} + impl FromStr for FramePointer { type Err = (); fn from_str(s: &str) -> Result { diff --git a/library/std/src/net/mod.rs b/library/std/src/net/mod.rs index bcab15db35b5..858776f14466 100644 --- a/library/std/src/net/mod.rs +++ b/library/std/src/net/mod.rs @@ -27,7 +27,7 @@ use crate::io::{self, ErrorKind}; pub use self::ip_addr::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::socket_addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; -#[unstable(feature = "tcplistener_into_incoming", issue = "88339")] +#[unstable(feature = "tcplistener_into_incoming", issue = "88373")] pub use self::tcp::IntoIncoming; #[stable(feature = "rust1", since = "1.0.0")] pub use self::tcp::{Incoming, TcpListener, TcpStream}; diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 9667d5f920e4..6336354239b0 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -105,7 +105,7 @@ pub struct Incoming<'a> { /// /// [`accept`]: TcpListener::accept #[derive(Debug)] -#[unstable(feature = "tcplistener_into_incoming", issue = "88339")] +#[unstable(feature = "tcplistener_into_incoming", issue = "88373")] pub struct IntoIncoming { listener: TcpListener, } @@ -894,7 +894,7 @@ impl TcpListener { /// } /// ``` #[must_use = "`self` will be dropped if the result is not used"] - #[unstable(feature = "tcplistener_into_incoming", issue = "88339")] + #[unstable(feature = "tcplistener_into_incoming", issue = "88373")] pub fn into_incoming(self) -> IntoIncoming { IntoIncoming { listener: self } } @@ -1033,7 +1033,7 @@ impl<'a> Iterator for Incoming<'a> { #[stable(feature = "tcp_listener_incoming_fused_iterator", since = "1.64.0")] impl FusedIterator for Incoming<'_> {} -#[unstable(feature = "tcplistener_into_incoming", issue = "88339")] +#[unstable(feature = "tcplistener_into_incoming", issue = "88373")] impl Iterator for IntoIncoming { type Item = io::Result; fn next(&mut self) -> Option> { @@ -1041,7 +1041,7 @@ impl Iterator for IntoIncoming { } } -#[unstable(feature = "tcplistener_into_incoming", issue = "88339")] +#[unstable(feature = "tcplistener_into_incoming", issue = "88373")] impl FusedIterator for IntoIncoming {} impl AsInner for TcpListener { diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index 5c4ccd32850e..92c76ec4303f 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -20,14 +20,14 @@ use crate::sys::time::SystemTime; use crate::sys::{cvt, cvt_r}; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; -#[cfg(any(all(target_os = "linux", target_env = "gnu"), target_vendor = "apple"))] +#[cfg(all(target_os = "linux", target_env = "gnu"))] use crate::sys::weak::syscall; #[cfg(target_os = "android")] use crate::sys::weak::weak; use libc::{c_int, mode_t}; -#[cfg(any(all(target_os = "linux", target_env = "gnu"), target_vendor = "apple"))] +#[cfg(all(target_os = "linux", target_env = "gnu"))] use libc::c_char; #[cfg(any( all(target_os = "linux", not(target_env = "musl")), @@ -1891,8 +1891,6 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { #[cfg(target_vendor = "apple")] pub fn copy(from: &Path, to: &Path) -> io::Result { - use crate::sync::atomic::{AtomicBool, Ordering}; - const COPYFILE_ALL: libc::copyfile_flags_t = libc::COPYFILE_METADATA | libc::COPYFILE_DATA; struct FreeOnDrop(libc::copyfile_state_t); @@ -1907,39 +1905,21 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { } } - // MacOS prior to 10.12 don't support `fclonefileat` - // We store the availability in a global to avoid unnecessary syscalls - static HAS_FCLONEFILEAT: AtomicBool = AtomicBool::new(true); - syscall! { - // Mirrors `libc::fclonefileat` - fn fclonefileat( - srcfd: libc::c_int, - dst_dirfd: libc::c_int, - dst: *const c_char, - flags: libc::c_int - ) -> libc::c_int - } - let (reader, reader_metadata) = open_from(from)?; - // Opportunistically attempt to create a copy-on-write clone of `from` - // using `fclonefileat`. - if HAS_FCLONEFILEAT.load(Ordering::Relaxed) { - let clonefile_result = run_path_with_cstr(to, &|to| { - cvt(unsafe { fclonefileat(reader.as_raw_fd(), libc::AT_FDCWD, to.as_ptr(), 0) }) - }); - match clonefile_result { - Ok(_) => return Ok(reader_metadata.len()), - Err(err) => match err.raw_os_error() { - // `fclonefileat` will fail on non-APFS volumes, if the - // destination already exists, or if the source and destination - // are on different devices. In all these cases `fcopyfile` - // should succeed. - Some(libc::ENOTSUP) | Some(libc::EEXIST) | Some(libc::EXDEV) => (), - Some(libc::ENOSYS) => HAS_FCLONEFILEAT.store(false, Ordering::Relaxed), - _ => return Err(err), - }, - } + let clonefile_result = run_path_with_cstr(to, &|to| { + cvt(unsafe { libc::fclonefileat(reader.as_raw_fd(), libc::AT_FDCWD, to.as_ptr(), 0) }) + }); + match clonefile_result { + Ok(_) => return Ok(reader_metadata.len()), + Err(e) => match e.raw_os_error() { + // `fclonefileat` will fail on non-APFS volumes, if the + // destination already exists, or if the source and destination + // are on different devices. In all these cases `fcopyfile` + // should succeed. + Some(libc::ENOTSUP) | Some(libc::EEXIST) | Some(libc::EXDEV) => (), + _ => return Err(e), + }, } // Fall back to using `fcopyfile` if `fclonefileat` does not succeed. diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index 2e71ceceb58b..40e2d1403ef5 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -738,17 +738,17 @@ pub fn home_dir() -> Option { n => n as usize, }; let mut buf = Vec::with_capacity(amt); - let mut passwd: libc::passwd = mem::zeroed(); + let mut p = mem::MaybeUninit::::uninit(); let mut result = ptr::null_mut(); match libc::getpwuid_r( libc::getuid(), - &mut passwd, + p.as_mut_ptr(), buf.as_mut_ptr(), buf.capacity(), &mut result, ) { 0 if !result.is_null() => { - let ptr = passwd.pw_dir as *const _; + let ptr = (*result).pw_dir as *const _; let bytes = CStr::from_ptr(ptr).to_bytes().to_vec(); Some(OsStringExt::from_vec(bytes)) } diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp index e4dbd3a13fee..258a03474513 100644 --- a/src/bootstrap/download-ci-llvm-stamp +++ b/src/bootstrap/download-ci-llvm-stamp @@ -1,4 +1,4 @@ Change this file to make users of the `download-ci-llvm` configuration download a new version of LLVM from CI, even if the LLVM submodule hasn’t changed. -Last change is for: https://github.com/rust-lang/rust/pull/125141 +Last change is for: https://github.com/rust-lang/rust/pull/126298 diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index cc5b00732135..5b18cb3f7e1e 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1290,15 +1290,21 @@ fn needs_codegen_config(run: &RunConfig<'_>) -> bool { pub(crate) const CODEGEN_BACKEND_PREFIX: &str = "rustc_codegen_"; fn is_codegen_cfg_needed(path: &TaskPath, run: &RunConfig<'_>) -> bool { - if path.path.to_str().unwrap().contains(CODEGEN_BACKEND_PREFIX) { + let path = path.path.to_str().unwrap(); + + let is_explicitly_called = |p| -> bool { run.builder.paths.contains(p) }; + let should_enforce = run.builder.kind == Kind::Dist || run.builder.kind == Kind::Install; + + if path.contains(CODEGEN_BACKEND_PREFIX) { let mut needs_codegen_backend_config = true; for backend in run.builder.config.codegen_backends(run.target) { - if path.path.to_str().unwrap().ends_with(&(CODEGEN_BACKEND_PREFIX.to_owned() + backend)) - { + if path.ends_with(&(CODEGEN_BACKEND_PREFIX.to_owned() + backend)) { needs_codegen_backend_config = false; } } - if needs_codegen_backend_config { + if (is_explicitly_called(&PathBuf::from(path)) || should_enforce) + && needs_codegen_backend_config + { run.builder.info( "WARNING: no codegen-backends config matched the requested path to build a codegen backend. \ HELP: add backend to codegen-backends in config.toml.", diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 54136d2aebda..2dc7cd7de6a0 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -665,6 +665,10 @@ impl Step for Std { } } +/// Tarball containing the compiler that gets downloaded and used by +/// `rust.download-rustc`. +/// +/// (Don't confuse this with [`RustDev`], without the `c`!) #[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct RustcDev { pub compiler: Compiler, @@ -1014,7 +1018,7 @@ impl Step for PlainSourceTarball { // perhaps it should be removed in favor of making `dist` perform the `vendor` step? // Ensure we have all submodules from src and other directories checked out. - for submodule in builder.get_all_submodules() { + for submodule in build_helper::util::parse_gitmodules(&builder.src) { builder.update_submodule(Path::new(submodule)); } @@ -2225,6 +2229,11 @@ impl Step for LlvmBitcodeLinker { /// Tarball intended for internal consumption to ease rustc/std development. /// /// Should not be considered stable by end users. +/// +/// In practice, this is the tarball that gets downloaded and used by +/// `llvm.download-ci-llvm`. +/// +/// (Don't confuse this with [`RustcDev`], with a `c`!) #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct RustDev { pub target: TargetSelection, diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index f90403d2ec45..8b379d3be5c0 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -217,6 +217,7 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool { ("arm-unknown-linux-gnueabihf", false), ("armv7-unknown-linux-gnueabihf", false), ("loongarch64-unknown-linux-gnu", false), + ("loongarch64-unknown-linux-musl", false), ("mips-unknown-linux-gnu", false), ("mips64-unknown-linux-gnuabi64", false), ("mips64el-unknown-linux-gnuabi64", false), diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 8a2bc3b9d484..efc09c41bf42 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1048,8 +1048,6 @@ impl Step for Tidy { /// Once tidy passes, this step also runs `fmt --check` if tests are being run /// for the `dev` or `nightly` channels. fn run(self, builder: &Builder<'_>) { - builder.build.update_submodule(Path::new("src/tools/rustc-perf")); - let mut cmd = builder.tool_cmd(Tool::Tidy); cmd.arg(&builder.src); cmd.arg(&builder.initial_cargo); diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index a638d6f31db0..14ccbfe0267e 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -4,13 +4,11 @@ use std::collections::BTreeSet; use std::env; use std::ffi::{OsStr, OsString}; use std::fmt::{Debug, Write}; -use std::fs::{self, File}; +use std::fs; use std::hash::Hash; -use std::io::{BufRead, BufReader}; use std::ops::Deref; use std::path::{Path, PathBuf}; use std::process::Command; -use std::sync::OnceLock; use std::time::{Duration, Instant}; use crate::core::build_steps::tool::{self, SourceType}; @@ -274,7 +272,7 @@ impl PathSet { /// This is used for `StepDescription::krate`, which passes all matching crates at once to /// `Step::make_run`, rather than calling it many times with a single crate. /// See `tests.rs` for examples. - fn intersection_removing_matches(&self, needles: &mut Vec<&Path>, module: Kind) -> PathSet { + fn intersection_removing_matches(&self, needles: &mut Vec, module: Kind) -> PathSet { let mut check = |p| { for (i, n) in needles.iter().enumerate() { let matched = Self::check(p, n, module); @@ -346,7 +344,7 @@ const PATH_REMAP: &[(&str, &[&str])] = &[ ), ]; -fn remap_paths(paths: &mut Vec<&Path>) { +fn remap_paths(paths: &mut Vec) { let mut remove = vec![]; let mut add = vec![]; for (i, path) in paths.iter().enumerate().filter_map(|(i, path)| path.to_str().map(|s| (i, s))) @@ -355,7 +353,7 @@ fn remap_paths(paths: &mut Vec<&Path>) { // Remove leading and trailing slashes so `tests/` and `tests` are equivalent if path.trim_matches(std::path::is_separator) == search { remove.push(i); - add.extend(replace.iter().map(Path::new)); + add.extend(replace.iter().map(PathBuf::from)); break; } } @@ -438,8 +436,25 @@ impl StepDescription { } } - // strip CurDir prefix if present - let mut paths: Vec<_> = paths.iter().map(|p| p.strip_prefix(".").unwrap_or(p)).collect(); + // Attempt to resolve paths to be relative to the builder source directory. + let mut paths: Vec = paths + .iter() + .map(|p| { + // If the path does not exist, it may represent the name of a Step, such as `tidy` in `x test tidy` + if !p.exists() { + return p.clone(); + } + + // Make the path absolute, strip the prefix, and convert to a PathBuf. + match std::path::absolute(p) { + Ok(p) => p.strip_prefix(&builder.src).unwrap_or(&p).to_path_buf(), + Err(e) => { + eprintln!("ERROR: {:?}", e); + panic!("Due to the above error, failed to resolve path: {:?}", p); + } + } + }) + .collect(); remap_paths(&mut paths); @@ -577,7 +592,7 @@ impl<'a> ShouldRun<'a> { /// /// [`path`]: ShouldRun::path pub fn paths(mut self, paths: &[&str]) -> Self { - let submodules_paths = self.builder.get_all_submodules(); + let submodules_paths = build_helper::util::parse_gitmodules(&self.builder.src); self.paths.insert(PathSet::Set( paths @@ -629,7 +644,7 @@ impl<'a> ShouldRun<'a> { /// (for now, just `all_krates` and `paths`, but we may want to add an `aliases` function in the future?) fn pathset_for_paths_removing_matches( &self, - paths: &mut Vec<&Path>, + paths: &mut Vec, kind: Kind, ) -> Vec { let mut sets = vec![]; @@ -2226,28 +2241,6 @@ impl<'a> Builder<'a> { out } - /// Return paths of all submodules. - pub fn get_all_submodules(&self) -> &[String] { - static SUBMODULES_PATHS: OnceLock> = OnceLock::new(); - - let init_submodules_paths = |src: &PathBuf| { - let file = File::open(src.join(".gitmodules")).unwrap(); - - let mut submodules_paths = vec![]; - for line in BufReader::new(file).lines().map_while(Result::ok) { - let line = line.trim(); - if line.starts_with("path") { - let actual_path = line.split(' ').last().expect("Couldn't get value of path"); - submodules_paths.push(actual_path.to_owned()); - } - } - - submodules_paths - }; - - SUBMODULES_PATHS.get_or_init(|| init_submodules_paths(&self.src)) - } - /// Ensure that a given step is built *only if it's supposed to be built by default*, returning /// its output. This will cache the step, so it's safe (and good!) to call this as often as /// needed to ensure that all dependencies are build. diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 276fd0b11d64..aa119b8c6991 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -122,11 +122,14 @@ fn test_intersection() { PathSet::Set(paths.into_iter().map(|p| TaskPath { path: p.into(), kind: None }).collect()) }; let library_set = set(&["library/core", "library/alloc", "library/std"]); - let mut command_paths = - vec![Path::new("library/core"), Path::new("library/alloc"), Path::new("library/stdarch")]; + let mut command_paths = vec![ + PathBuf::from("library/core"), + PathBuf::from("library/alloc"), + PathBuf::from("library/stdarch"), + ]; let subset = library_set.intersection_removing_matches(&mut command_paths, Kind::Build); assert_eq!(subset, set(&["library/core", "library/alloc"]),); - assert_eq!(command_paths, vec![Path::new("library/stdarch")]); + assert_eq!(command_paths, vec![PathBuf::from("library/stdarch")]); } #[test] diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 4b6dc45b436d..59b29eedb797 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -135,7 +135,7 @@ pub fn symlink_dir(config: &Config, original: &Path, link: &Path) -> io::Result< if config.dry_run() { return Ok(()); } - let _ = fs::remove_dir(link); + let _ = fs::remove_dir_all(link); return symlink_dir_inner(original, link); #[cfg(not(windows))] diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md index 824c904e17f7..985e3b37422d 100644 --- a/src/ci/docker/README.md +++ b/src/ci/docker/README.md @@ -271,6 +271,22 @@ For targets: `loongarch64-unknown-linux-gnu` - C compiler > gcc version = 13.2.0 - C compiler > C++ = ENABLE -- to cross compile LLVM +### `loongarch64-linux-musl.defconfig` + +For targets: `loongarch64-unknown-linux-musl` + +- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET} +- Path and misc options > Use a mirror = ENABLE +- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc +- Target options > Target Architecture = loongarch +- Target options > Bitness = 64-bit +- Operating System > Target OS = linux +- Operating System > Linux kernel version = 5.19.16 +- Binary utilities > Version of binutils = 2.41 +- C-library > musl version = 1.2.5 +- C compiler > gcc version = 13.2.0 +- C compiler > C++ = ENABLE -- to cross compile LLVM + ### `mips-linux-gnu.defconfig` For targets: `mips-unknown-linux-gnu` diff --git a/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile new file mode 100644 index 000000000000..560adf971ba4 --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile @@ -0,0 +1,35 @@ +FROM ubuntu:22.04 + +COPY scripts/cross-apt-packages.sh /scripts/ +RUN sh /scripts/cross-apt-packages.sh + +COPY scripts/crosstool-ng-git.sh /scripts/ +RUN sh /scripts/crosstool-ng-git.sh + +COPY scripts/rustbuild-setup.sh /scripts/ +RUN sh /scripts/rustbuild-setup.sh +WORKDIR /tmp + +COPY scripts/crosstool-ng-build.sh /scripts/ +COPY host-x86_64/dist-loongarch64-musl/loongarch64-unknown-linux-musl.defconfig /tmp/crosstool.defconfig +RUN /scripts/crosstool-ng-build.sh + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +ENV PATH=$PATH:/x-tools/loongarch64-unknown-linux-musl/bin + +ENV CC_loongarch64_unknown_linux_musl=loongarch64-unknown-linux-musl-gcc \ + AR_loongarch64_unknown_linux_musl=loongarch64-unknown-linux-musl-ar \ + CXX_loongarch64_unknown_linux_musl=loongarch64-unknown-linux-musl-g++ + +ENV HOSTS=loongarch64-unknown-linux-musl + +ENV RUST_CONFIGURE_ARGS \ + --enable-extended \ + --enable-lld \ + --disable-docs \ + --set target.loongarch64-unknown-linux-musl.crt-static=false \ + --musl-root-loongarch64=/x-tools/loongarch64-unknown-linux-musl/loongarch64-unknown-linux-musl/sysroot/usr + +ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/dist-loongarch64-musl/loongarch64-unknown-linux-musl.defconfig b/src/ci/docker/host-x86_64/dist-loongarch64-musl/loongarch64-unknown-linux-musl.defconfig new file mode 100644 index 000000000000..3ab676ed9717 --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-loongarch64-musl/loongarch64-unknown-linux-musl.defconfig @@ -0,0 +1,15 @@ +CT_CONFIG_VERSION="4" +CT_EXPERIMENTAL=y +CT_PREFIX_DIR="/x-tools/${CT_TARGET}" +CT_USE_MIRROR=y +CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc" +CT_ARCH_LOONGARCH=y +# CT_DEMULTILIB is not set +CT_ARCH_USE_MMU=y +CT_ARCH_ARCH="loongarch64" +CT_KERNEL_LINUX=y +CT_LINUX_V_5_19=y +CT_LIBC_MUSL=y +CT_CC_GCC_ENABLE_DEFAULT_PIE=y +CT_CC_LANG_CXX=y +CT_GETTEXT_NEEDED=y diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index 50c2e5e29f0b..47d04a528837 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.17.2 \ No newline at end of file +0.18.0 \ No newline at end of file diff --git a/src/ci/docker/scripts/crosstool-ng-git.sh b/src/ci/docker/scripts/crosstool-ng-git.sh new file mode 100644 index 000000000000..2a10e262df8c --- /dev/null +++ b/src/ci/docker/scripts/crosstool-ng-git.sh @@ -0,0 +1,17 @@ +#!/bin/sh +set -ex + +URL=https://github.com/crosstool-ng/crosstool-ng +REV=c64500d94be92ed1bcdfdef911048a14e216a5e1 + +mkdir crosstool-ng +cd crosstool-ng +git init +git fetch --depth=1 ${URL} ${REV} +git reset --hard FETCH_HEAD +./bootstrap +./configure --prefix=/usr/local +make -j$(nproc) +make install +cd .. +rm -rf crosstool-ng diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 4366a92fbcdf..e3903c3dd5a1 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -144,6 +144,9 @@ auto: - image: dist-loongarch64-linux <<: *job-linux-4c + - image: dist-loongarch64-musl + <<: *job-linux-4c + - image: dist-ohos <<: *job-linux-4c diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 537c88cd22b2..39659473f220 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -93,6 +93,7 @@ target | notes `arm-unknown-linux-gnueabihf` | Armv6 Linux, hardfloat (kernel 3.2, glibc 2.17) `armv7-unknown-linux-gnueabihf` | Armv7-A Linux, hardfloat (kernel 3.2, glibc 2.17) [`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36) +[`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, musl 1.2.5) `powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2, glibc 2.17) `powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2, glibc 2.17) `powerpc64le-unknown-linux-gnu` | PPC64LE Linux (kernel 3.10, glibc 2.17) @@ -305,7 +306,6 @@ target | std | host | notes `i686-uwp-windows-msvc` | ✓ | | [^x86_32-floats-return-ABI] [`i686-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ | | 32-bit Windows 7 support [^x86_32-floats-return-ABI] `i686-wrs-vxworks` | ? | | [^x86_32-floats-return-ABI] -[`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | ? | | LoongArch64 Linux (LP64D ABI) with musl 1.2.3 [`m68k-unknown-linux-gnu`](platform-support/m68k-unknown-linux-gnu.md) | ? | | Motorola 680x0 Linux `mips-unknown-linux-gnu` | ✓ | ✓ | MIPS Linux (kernel 4.4, glibc 2.23) `mips-unknown-linux-musl` | ✓ | | MIPS Linux with musl 1.2.3 diff --git a/src/tools/build-manifest/README.md b/src/tools/build-manifest/README.md index 9d30c554186b..2ea1bffb35f4 100644 --- a/src/tools/build-manifest/README.md +++ b/src/tools/build-manifest/README.md @@ -4,7 +4,7 @@ This tool generates the manifests uploaded to static.rust-lang.org and used by r You can see a full list of all manifests at . This listing is updated by every 7 days. -This gets called by `promote-release` via `x.py dist hash-and-sign`. +This gets called by `promote-release` . `promote-release` downloads a pre-built binary of `build-manifest` which is generated in the dist-x86_64-linux builder and uploaded to s3. ## Adding a new component diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index a709aab7ce22..a2e7907b532e 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -25,6 +25,7 @@ static HOSTS: &[&str] = &[ "i686-pc-windows-msvc", "i686-unknown-linux-gnu", "loongarch64-unknown-linux-gnu", + "loongarch64-unknown-linux-musl", "mips-unknown-linux-gnu", "mips64-unknown-linux-gnuabi64", "mips64el-unknown-linux-gnuabi64", @@ -106,6 +107,7 @@ static TARGETS: &[&str] = &[ "i686-unknown-redox", "i686-unknown-uefi", "loongarch64-unknown-linux-gnu", + "loongarch64-unknown-linux-musl", "loongarch64-unknown-none", "loongarch64-unknown-none-softfloat", "m68k-unknown-linux-gnu", diff --git a/src/tools/build_helper/src/util.rs b/src/tools/build_helper/src/util.rs index 5801a8648f22..72c05c4c48ab 100644 --- a/src/tools/build_helper/src/util.rs +++ b/src/tools/build_helper/src/util.rs @@ -1,4 +1,8 @@ +use std::fs::File; +use std::io::{BufRead, BufReader}; +use std::path::Path; use std::process::Command; +use std::sync::OnceLock; /// Invokes `build_helper::util::detail_exit` with `cfg!(test)` /// @@ -45,3 +49,27 @@ pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> Result<(), ()> { Ok(()) } } + +/// Returns the submodule paths from the `.gitmodules` file in the given directory. +pub fn parse_gitmodules(target_dir: &Path) -> &[String] { + static SUBMODULES_PATHS: OnceLock> = OnceLock::new(); + let gitmodules = target_dir.join(".gitmodules"); + assert!(gitmodules.exists(), "'{}' file is missing.", gitmodules.display()); + + let init_submodules_paths = || { + let file = File::open(gitmodules).unwrap(); + + let mut submodules_paths = vec![]; + for line in BufReader::new(file).lines().map_while(Result::ok) { + let line = line.trim(); + if line.starts_with("path") { + let actual_path = line.split(' ').last().expect("Couldn't get value of path"); + submodules_paths.push(actual_path.to_owned()); + } + } + + submodules_paths + }; + + SUBMODULES_PATHS.get_or_init(|| init_submodules_paths()) +} diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 5469b9f1a0a2..31ae0deb7ec3 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -779,6 +779,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-haiku", "ignore-horizon", "ignore-i686-pc-windows-msvc", + "ignore-illumos", "ignore-ios", "ignore-linux", "ignore-lldb", @@ -843,6 +844,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-x32", "ignore-x86", "ignore-x86_64", + "ignore-x86_64-apple-darwin", "ignore-x86_64-unknown-linux-gnu", "incremental", "known-bug", @@ -875,6 +877,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "needs-sanitizer-shadow-call-stack", "needs-sanitizer-support", "needs-sanitizer-thread", + "needs-symlink", "needs-threads", "needs-unwind", "needs-wasmtime", diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs index b96832db67be..5b2665f7d0ba 100644 --- a/src/tools/compiletest/src/header/needs.rs +++ b/src/tools/compiletest/src/header/needs.rs @@ -144,6 +144,11 @@ pub(super) fn handle_needs( condition: config.runner.as_ref().is_some_and(|r| r.contains("wasmtime")), ignore_reason: "ignored when wasmtime runner is not available", }, + Need { + name: "needs-symlink", + condition: cache.symlinks, + ignore_reason: "ignored if symlinks are unavailable", + }, ]; let (name, comment) = match ln.split_once([':', ' ']) { @@ -209,6 +214,7 @@ pub(super) struct CachedNeedsConditions { xray: bool, rust_lld: bool, dlltool: bool, + symlinks: bool, } impl CachedNeedsConditions { @@ -253,6 +259,7 @@ impl CachedNeedsConditions { .exists(), dlltool: find_dlltool(&config), + symlinks: has_symlinks(), } } } @@ -279,3 +286,22 @@ fn find_dlltool(config: &Config) -> bool { }; dlltool_found } + +#[cfg(windows)] +fn has_symlinks() -> bool { + if std::env::var_os("CI").is_some() { + return true; + } + let link = std::env::temp_dir().join("RUST_COMPILETEST_SYMLINK_CHECK"); + if std::os::windows::fs::symlink_file("DOES NOT EXIST", &link).is_ok() { + std::fs::remove_file(&link).unwrap(); + true + } else { + false + } +} + +#[cfg(not(windows))] +fn has_symlinks() -> bool { + true +} diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 97d37b0ebe59..11a1c43bae9a 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -acb62737aca7045f331e7a05adc38bed213e278d +d49994b060684af423339b55769439b2f444a7b9 diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 139c81a9d40c..647d7d44bb1b 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -311,7 +311,9 @@ pub fn report_error<'tcx>( ResourceExhaustion(_) => "resource exhaustion", Unsupported( // We list only the ones that can actually happen. - UnsupportedOpInfo::Unsupported(_) | UnsupportedOpInfo::UnsizedLocal, + UnsupportedOpInfo::Unsupported(_) + | UnsupportedOpInfo::UnsizedLocal + | UnsupportedOpInfo::ExternTypeField, ) => "unsupported operation", InvalidProgram( // We list only the ones that can actually happen. diff --git a/src/tools/miri/tests/fail/extern-type-field-offset.stderr b/src/tools/miri/tests/fail/extern-type-field-offset.stderr index e0d6e9ebf1de..3ed5732b4eb0 100644 --- a/src/tools/miri/tests/fail/extern-type-field-offset.stderr +++ b/src/tools/miri/tests/fail/extern-type-field-offset.stderr @@ -1,8 +1,8 @@ -error: unsupported operation: `extern type` does not have a known offset +error: unsupported operation: `extern type` field does not have a known offset --> $DIR/extern-type-field-offset.rs:LL:CC | LL | let _field = &x.a; - | ^^^^ `extern type` does not have a known offset + | ^^^^ `extern type` field does not have a known offset | = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: BACKTRACE: diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index f39bcfd60dfb..0a1bd9b0b34f 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -36,8 +36,10 @@ impl Command { Self { cmd: StdCommand::new(program), stdin: None, drop_bomb: DropBomb::arm(program) } } - pub fn set_stdin(&mut self, stdin: Box<[u8]>) { - self.stdin = Some(stdin); + /// Specify a stdin input + pub fn stdin>(&mut self, input: I) -> &mut Self { + self.stdin = Some(input.as_ref().to_vec().into_boxed_slice()); + self } /// Specify an environment variable. diff --git a/src/tools/run-make-support/src/llvm.rs b/src/tools/run-make-support/src/llvm.rs index 99bce08fc238..7f42223bf7f5 100644 --- a/src/tools/run-make-support/src/llvm.rs +++ b/src/tools/run-make-support/src/llvm.rs @@ -102,6 +102,24 @@ impl LlvmReadobj { self } + /// Pass `--program-headers` to display program headers. + pub fn program_headers(&mut self) -> &mut Self { + self.cmd.arg("--program-headers"); + self + } + + /// Pass `--symbols` to display the symbol. + pub fn symbols(&mut self) -> &mut Self { + self.cmd.arg("--symbols"); + self + } + + /// Pass `--dynamic-table` to display the dynamic symbol table. + pub fn dynamic_table(&mut self) -> &mut Self { + self.cmd.arg("--dynamic-table"); + self + } + /// Specify the section to display. pub fn section(&mut self, section: &str) -> &mut Self { self.cmd.arg("--string-dump"); @@ -153,7 +171,7 @@ impl LlvmFilecheck { /// Pipe a read file into standard input containing patterns that will be matched against the .patterns(path) call. pub fn stdin>(&mut self, input: I) -> &mut Self { - self.cmd.set_stdin(input.as_ref().to_vec().into_boxed_slice()); + self.cmd.stdin(input); self } diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index a377dad99d6a..28ece1dff128 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -244,7 +244,7 @@ impl Rustc { /// Specify a stdin input pub fn stdin>(&mut self, input: I) -> &mut Self { - self.cmd.set_stdin(input.as_ref().to_vec().into_boxed_slice()); + self.cmd.stdin(input); self } diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs index 930785612545..fb00427b1c19 100644 --- a/src/tools/run-make-support/src/rustdoc.rs +++ b/src/tools/run-make-support/src/rustdoc.rs @@ -92,7 +92,7 @@ impl Rustdoc { /// Specify a stdin input pub fn stdin>(&mut self, input: I) -> &mut Self { - self.cmd.set_stdin(input.as_ref().to_vec().into_boxed_slice()); + self.cmd.stdin(input); self } diff --git a/src/tools/rust-analyzer/.cargo/config.toml b/src/tools/rust-analyzer/.cargo/config.toml index 070560dfbc31..0193a9566e2b 100644 --- a/src/tools/rust-analyzer/.cargo/config.toml +++ b/src/tools/rust-analyzer/.cargo/config.toml @@ -4,6 +4,7 @@ tq = "test -- -q" qt = "tq" lint = "clippy --all-targets -- --cap-lints warn" codegen = "run --package xtask --bin xtask -- codegen" +dist = "run --package xtask --bin xtask -- dist" [target.x86_64-pc-windows-msvc] linker = "rust-lld" diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 3558c39bb32c..57d43dad3fd8 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -328,6 +328,15 @@ dependencies = [ "dirs-sys", ] +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + [[package]] name = "dirs-sys" version = "0.4.1" @@ -503,6 +512,7 @@ dependencies = [ "hir-def", "hir-expand", "hir-ty", + "intern", "itertools", "once_cell", "rustc-hash", @@ -891,9 +901,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.154" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libloading" @@ -1665,6 +1675,7 @@ dependencies = [ "anyhow", "cfg", "crossbeam-channel", + "dirs", "dissimilar", "expect-test", "flycheck", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index ccc27e21333b..583c7bbe3389 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -162,7 +162,11 @@ xshell = "0.2.5" dashmap = { version = "=5.5.3", features = ["raw-api"] } [workspace.lints.rust] -rust_2018_idioms = "warn" +bare_trait_objects = "warn" +elided_lifetimes_in_paths = "warn" +ellipsis_inclusive_range_patterns = "warn" +explicit_outlives_requirements = "warn" +unused_extern_crates = "warn" unused_lifetimes = "warn" unreachable_pub = "warn" semicolon_in_expressions_from_macros = "warn" diff --git a/src/tools/rust-analyzer/crates/base-db/src/change.rs b/src/tools/rust-analyzer/crates/base-db/src/change.rs index 927b2108a6ce..0fd54e1211cd 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/change.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/change.rs @@ -51,7 +51,7 @@ impl FileChange { } pub fn apply(self, db: &mut dyn SourceDatabaseExt) { - let _p = tracing::span!(tracing::Level::INFO, "FileChange::apply").entered(); + let _p = tracing::info_span!("FileChange::apply").entered(); if let Some(roots) = self.roots { for (idx, root) in roots.into_iter().enumerate() { let root_id = SourceRootId(idx as u32); diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs index b2c3f38ab4f8..1d172ab9e40e 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs @@ -412,7 +412,7 @@ impl CrateGraph { from: CrateId, dep: Dependency, ) -> Result<(), CyclicDependenciesError> { - let _p = tracing::span!(tracing::Level::INFO, "add_dep").entered(); + let _p = tracing::info_span!("add_dep").entered(); self.check_cycle_after_dependency(from, dep.crate_id)?; diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index 2c13eed56c3e..f5165ea8a7bb 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -85,7 +85,7 @@ fn toolchain_channel(db: &dyn SourceDatabase, krate: CrateId) -> Option Parse { - let _p = tracing::span!(tracing::Level::INFO, "parse", ?file_id).entered(); + let _p = tracing::info_span!("parse", ?file_id).entered(); let text = db.file_text(file_id); // FIXME: Edition based parsing SourceFile::parse(&text, span::Edition::CURRENT) @@ -187,7 +187,7 @@ impl FileLoader for FileLoaderDelegate<&'_ T> { } fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]> { - let _p = tracing::span!(tracing::Level::INFO, "relevant_crates").entered(); + let _p = tracing::info_span!("relevant_crates").entered(); let source_root = self.0.file_source_root(file_id); self.0.source_root_crates(source_root) } diff --git a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs index afdc3e389b36..4584400e66f0 100644 --- a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs +++ b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs @@ -304,7 +304,7 @@ impl FlycheckActor { Some(c) => c, None => continue, }; - let formatted_command = format!("{:?}", command); + let formatted_command = format!("{command:?}"); tracing::debug!(?command, "will restart flycheck"); let (sender, receiver) = unbounded(); @@ -318,8 +318,7 @@ impl FlycheckActor { } Err(error) => { self.report_progress(Progress::DidFailToRestart(format!( - "Failed to run the following command: {} error={}", - formatted_command, error + "Failed to run the following command: {formatted_command} error={error}" ))); self.status = FlycheckStatus::Finished; } @@ -331,7 +330,7 @@ impl FlycheckActor { // Watcher finished let command_handle = self.command_handle.take().unwrap(); self.command_receiver.take(); - let formatted_handle = format!("{:?}", command_handle); + let formatted_handle = format!("{command_handle:?}"); let res = command_handle.join(); if let Err(error) = &res { @@ -387,6 +386,7 @@ impl FlycheckActor { "did cancel flycheck" ); command_handle.cancel(); + self.command_receiver.take(); self.report_progress(Progress::DidCancel); self.status = FlycheckStatus::Finished; } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs index d9eeffd7983b..184dab8367c1 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs @@ -1,10 +1,5 @@ //! A higher level attributes based on TokenTree, with also some shortcuts. -pub mod builtin; - -#[cfg(test)] -mod tests; - use std::{borrow::Cow, hash::Hash, ops, slice::Iter as SliceIter}; use base_db::CrateId; @@ -75,7 +70,7 @@ impl Attrs { db: &dyn DefDatabase, v: VariantId, ) -> Arc> { - let _p = tracing::span!(tracing::Level::INFO, "fields_attrs_query").entered(); + let _p = tracing::info_span!("fields_attrs_query").entered(); // FIXME: There should be some proper form of mapping between item tree field ids and hir field ids let mut res = ArenaMap::default(); @@ -326,7 +321,7 @@ impl AttrsWithOwner { } pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { - let _p = tracing::span!(tracing::Level::INFO, "attrs_query").entered(); + let _p = tracing::info_span!("attrs_query").entered(); // FIXME: this should use `Trace` to avoid duplication in `source_map` below let raw_attrs = match def { AttrDefId::ModuleId(module) => { @@ -646,3 +641,55 @@ pub(crate) fn fields_attrs_source_map( Arc::new(res) } + +#[cfg(test)] +mod tests { + //! This module contains tests for doc-expression parsing. + //! Currently, it tests `#[doc(hidden)]` and `#[doc(alias)]`. + + use triomphe::Arc; + + use base_db::FileId; + use hir_expand::span_map::{RealSpanMap, SpanMap}; + use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode}; + use syntax::{ast, AstNode, TextRange}; + + use crate::attr::{DocAtom, DocExpr}; + + fn assert_parse_result(input: &str, expected: DocExpr) { + let source_file = ast::SourceFile::parse(input, span::Edition::CURRENT).ok().unwrap(); + let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); + let map = SpanMap::RealSpanMap(Arc::new(RealSpanMap::absolute(FileId::from_raw(0)))); + let tt = syntax_node_to_token_tree( + tt.syntax(), + map.as_ref(), + map.span_for_range(TextRange::empty(0.into())), + DocCommentDesugarMode::ProcMacro, + ); + let cfg = DocExpr::parse(&tt); + assert_eq!(cfg, expected); + } + + #[test] + fn test_doc_expr_parser() { + assert_parse_result("#![doc(hidden)]", DocAtom::Flag("hidden".into()).into()); + + assert_parse_result( + r#"#![doc(alias = "foo")]"#, + DocAtom::KeyValue { key: "alias".into(), value: "foo".into() }.into(), + ); + + assert_parse_result(r#"#![doc(alias("foo"))]"#, DocExpr::Alias(["foo".into()].into())); + assert_parse_result( + r#"#![doc(alias("foo", "bar", "baz"))]"#, + DocExpr::Alias(["foo".into(), "bar".into(), "baz".into()].into()), + ); + + assert_parse_result( + r#" + #[doc(alias("Bar", "Qux"))] + struct Foo;"#, + DocExpr::Alias(["Bar".into(), "Qux".into()].into()), + ); + } +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr/tests.rs deleted file mode 100644 index 727f4429802c..000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr/tests.rs +++ /dev/null @@ -1,48 +0,0 @@ -//! This module contains tests for doc-expression parsing. -//! Currently, it tests `#[doc(hidden)]` and `#[doc(alias)]`. - -use triomphe::Arc; - -use base_db::FileId; -use hir_expand::span_map::{RealSpanMap, SpanMap}; -use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode}; -use syntax::{ast, AstNode, TextRange}; - -use crate::attr::{DocAtom, DocExpr}; - -fn assert_parse_result(input: &str, expected: DocExpr) { - let source_file = ast::SourceFile::parse(input, span::Edition::CURRENT).ok().unwrap(); - let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); - let map = SpanMap::RealSpanMap(Arc::new(RealSpanMap::absolute(FileId::from_raw(0)))); - let tt = syntax_node_to_token_tree( - tt.syntax(), - map.as_ref(), - map.span_for_range(TextRange::empty(0.into())), - DocCommentDesugarMode::ProcMacro, - ); - let cfg = DocExpr::parse(&tt); - assert_eq!(cfg, expected); -} - -#[test] -fn test_doc_expr_parser() { - assert_parse_result("#![doc(hidden)]", DocAtom::Flag("hidden".into()).into()); - - assert_parse_result( - r#"#![doc(alias = "foo")]"#, - DocAtom::KeyValue { key: "alias".into(), value: "foo".into() }.into(), - ); - - assert_parse_result(r#"#![doc(alias("foo"))]"#, DocExpr::Alias(["foo".into()].into())); - assert_parse_result( - r#"#![doc(alias("foo", "bar", "baz"))]"#, - DocExpr::Alias(["foo".into(), "bar".into(), "baz".into()].into()), - ); - - assert_parse_result( - r#" - #[doc(alias("Bar", "Qux"))] - struct Foo;"#, - DocExpr::Alias(["Bar".into(), "Qux".into()].into()), - ); -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs index d2f4d7b7e56e..ca4a3f5217cf 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs @@ -124,7 +124,7 @@ impl Body { db: &dyn DefDatabase, def: DefWithBodyId, ) -> (Arc, Arc) { - let _p = tracing::span!(tracing::Level::INFO, "body_with_source_map_query").entered(); + let _p = tracing::info_span!("body_with_source_map_query").entered(); let mut params = None; let mut is_async_fn = false; @@ -395,6 +395,12 @@ impl BodySourceMap { self.expr_map.get(&src).copied() } + pub fn expansions( + &self, + ) -> impl Iterator>, &MacroFileId)> { + self.expansions.iter() + } + pub fn implicit_format_args( &self, node: InFile<&ast::FormatArgsExpr>, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs index c6d9ba6cfe45..faba9050fc4d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs @@ -12,6 +12,7 @@ use intern::Interned; use rustc_hash::FxHashMap; use smallvec::SmallVec; use span::AstIdMap; +use stdx::never; use syntax::{ ast::{ self, ArrayExprKind, AstChildren, BlockExpr, HasArgList, HasAttrs, HasLoopBody, HasName, @@ -480,7 +481,8 @@ impl ExprCollector<'_> { } else if e.const_token().is_some() { Mutability::Shared } else { - unreachable!("parser only remaps to raw_token() if matching mutability token follows") + never!("parser only remaps to raw_token() if matching mutability token follows"); + Mutability::Shared } } else { Mutability::from_mutable(e.mut_token().is_some()) @@ -963,7 +965,7 @@ impl ExprCollector<'_> { .resolve_path( self.db, module, - &path, + path, crate::item_scope::BuiltinShadowMode::Other, Some(MacroSubNs::Bang), ) @@ -1006,9 +1008,9 @@ impl ExprCollector<'_> { Some((mark, expansion)) => { // Keep collecting even with expansion errors so we can provide completions and // other services in incomplete macro expressions. - self.source_map - .expansions - .insert(macro_call_ptr, self.expander.current_file_id().macro_file().unwrap()); + if let Some(macro_file) = self.expander.current_file_id().macro_file() { + self.source_map.expansions.insert(macro_call_ptr, macro_file); + } let prev_ast_id_map = mem::replace( &mut self.ast_id_map, self.db.ast_id_map(self.expander.current_file_id()), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs index cbb5ca887f49..c48d16d05304 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs @@ -48,21 +48,30 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo let mut p = Printer { db, body, buf: header, indent_level: 0, needs_indent: false }; if let DefWithBodyId::FunctionId(it) = owner { p.buf.push('('); - let params = &db.function_data(it).params; - let mut params = params.iter(); + let function_data = &db.function_data(it); + let (mut params, ret_type) = (function_data.params.iter(), &function_data.ret_type); if let Some(self_param) = body.self_param { p.print_binding(self_param); - p.buf.push(':'); + p.buf.push_str(": "); if let Some(ty) = params.next() { p.print_type_ref(ty); + p.buf.push_str(", "); } } body.params.iter().zip(params).for_each(|(¶m, ty)| { p.print_pat(param); - p.buf.push(':'); + p.buf.push_str(": "); p.print_type_ref(ty); + p.buf.push_str(", "); }); + // remove the last ", " in param list + if body.params.len() > 0 { + p.buf.truncate(p.buf.len() - 2); + } p.buf.push(')'); + // return type + p.buf.push_str(" -> "); + p.print_type_ref(ret_type); p.buf.push(' '); } p.print_expr(body.body_expr); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs index e8b26d537345..0011d3a20c2a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs @@ -156,7 +156,7 @@ fn main() { ); expect![[r#" - fn main() { + fn main() -> () { let are = "are"; let count = 10; builtin#lang(Arguments::new_v1_formatted)( @@ -258,7 +258,7 @@ impl SsrError { assert_eq!(db.body_with_source_map(def).1.diagnostics(), &[]); expect![[r#" - fn main() { + fn main() -> () { _ = $crate::error::SsrError::new( builtin#lang(Arguments::new_v1_formatted)( &[ @@ -303,7 +303,7 @@ macro_rules! m { }; } -fn f() { +fn f(a: i32, b: u32) -> String { m!(); } "#, @@ -317,7 +317,7 @@ fn f() { } expect![[r#" - fn f() { + fn f(a: i32, b: u32) -> String { { $crate::panicking::panic_fmt( builtin#lang(Arguments::new_v1_formatted)( diff --git a/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs b/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs index 0b41984bdd89..106109eb1844 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs @@ -6,7 +6,7 @@ use either::Either; use hir_expand::{attrs::collect_attrs, HirFileId}; -use syntax::ast; +use syntax::{ast, AstPtr}; use crate::{ db::DefDatabase, @@ -38,7 +38,7 @@ impl ChildBySource for TraitId { data.attribute_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each( |(ast_id, call_id)| { - res[keys::ATTR_MACRO_CALL].insert(ast_id.to_node(db.upcast()), call_id); + res[keys::ATTR_MACRO_CALL].insert(ast_id.to_ptr(db.upcast()), call_id); }, ); data.items.iter().for_each(|&(_, item)| { @@ -50,9 +50,10 @@ impl ChildBySource for TraitId { impl ChildBySource for ImplId { fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { let data = db.impl_data(*self); + // FIXME: Macro calls data.attribute_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each( |(ast_id, call_id)| { - res[keys::ATTR_MACRO_CALL].insert(ast_id.to_node(db.upcast()), call_id); + res[keys::ATTR_MACRO_CALL].insert(ast_id.to_ptr(db.upcast()), call_id); }, ); data.items.iter().for_each(|&item| { @@ -80,7 +81,7 @@ impl ChildBySource for ItemScope { .for_each(|konst| insert_item_loc(db, res, file_id, konst, keys::CONST)); self.attr_macro_invocs().filter(|(id, _)| id.file_id == file_id).for_each( |(ast_id, call_id)| { - res[keys::ATTR_MACRO_CALL].insert(ast_id.to_node(db.upcast()), call_id); + res[keys::ATTR_MACRO_CALL].insert(ast_id.to_ptr(db.upcast()), call_id); }, ); self.legacy_macros().for_each(|(_, ids)| { @@ -88,7 +89,7 @@ impl ChildBySource for ItemScope { if let MacroId::MacroRulesId(id) = id { let loc = id.lookup(db); if loc.id.file_id() == file_id { - res[keys::MACRO_RULES].insert(loc.source(db).value, id); + res[keys::MACRO_RULES].insert(loc.ast_ptr(db).value, id); } } }) @@ -100,12 +101,18 @@ impl ChildBySource for ItemScope { if let Some((_, Either::Left(attr))) = collect_attrs(&adt).nth(attr_id.ast_index()) { - res[keys::DERIVE_MACRO_CALL].insert(attr, (attr_id, call_id, calls.into())); + res[keys::DERIVE_MACRO_CALL] + .insert(AstPtr::new(&attr), (attr_id, call_id, calls.into())); } }); }, ); - + self.iter_macro_invoc().filter(|(id, _)| id.file_id == file_id).for_each( + |(ast_id, &call)| { + let ast = ast_id.to_ptr(db.upcast()); + res[keys::MACRO_CALL].insert(ast, call); + }, + ); fn add_module_def( db: &dyn DefDatabase, map: &mut DynMap, @@ -155,8 +162,8 @@ impl ChildBySource for VariantId { for (local_id, source) in arena_map.value.iter() { let id = FieldId { parent, local_id }; match source.clone() { - Either::Left(source) => res[keys::TUPLE_FIELD].insert(source, id), - Either::Right(source) => res[keys::RECORD_FIELD].insert(source, id), + Either::Left(source) => res[keys::TUPLE_FIELD].insert(AstPtr::new(&source), id), + Either::Right(source) => res[keys::RECORD_FIELD].insert(AstPtr::new(&source), id), } } } @@ -171,29 +178,30 @@ impl ChildBySource for EnumId { let tree = loc.id.item_tree(db); let ast_id_map = db.ast_id_map(loc.id.file_id()); - let root = db.parse_or_expand(loc.id.file_id()); db.enum_data(*self).variants.iter().for_each(|&(variant, _)| { - res[keys::ENUM_VARIANT].insert( - ast_id_map.get(tree[variant.lookup(db).id.value].ast_id).to_node(&root), - variant, - ); + res[keys::ENUM_VARIANT] + .insert(ast_id_map.get(tree[variant.lookup(db).id.value].ast_id), variant); }); } } impl ChildBySource for DefWithBodyId { fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { - let body = db.body(*self); + let (body, sm) = db.body_with_source_map(*self); if let &DefWithBodyId::VariantId(v) = self { VariantId::EnumVariantId(v).child_by_source_to(db, res, file_id) } + sm.expansions().filter(|(ast, _)| ast.file_id == file_id).for_each(|(ast, &exp_id)| { + res[keys::MACRO_CALL].insert(ast.value, exp_id.macro_call_id); + }); + for (block, def_map) in body.blocks(db) { // All block expressions are merged into the same map, because they logically all add // inner items to the containing `DefWithBodyId`. def_map[DefMap::ROOT].scope.child_by_source_to(db, res, file_id); - res[keys::BLOCK].insert(block.lookup(db).ast_id.to_node(db.upcast()), block); + res[keys::BLOCK].insert(block.lookup(db).ast_id.to_ptr(db.upcast()), block); } } } @@ -220,13 +228,17 @@ impl ChildBySource for GenericDefId { { let id = TypeOrConstParamId { parent: *self, local_id }; match ast_param { - ast::TypeOrConstParam::Type(a) => res[keys::TYPE_PARAM].insert(a, id), - ast::TypeOrConstParam::Const(a) => res[keys::CONST_PARAM].insert(a, id), + ast::TypeOrConstParam::Type(a) => { + res[keys::TYPE_PARAM].insert(AstPtr::new(&a), id) + } + ast::TypeOrConstParam::Const(a) => { + res[keys::CONST_PARAM].insert(AstPtr::new(&a), id) + } } } for (local_id, ast_param) in lts_idx_iter.zip(generic_params_list.lifetime_params()) { let id = LifetimeParamId { parent: *self, local_id }; - res[keys::LIFETIME_PARAM].insert(ast_param, id); + res[keys::LIFETIME_PARAM].insert(AstPtr::new(&ast_param), id); } } } @@ -246,7 +258,7 @@ fn insert_item_loc( { let loc = id.lookup(db); if loc.item_tree_id().file_id() == file_id { - res[key].insert(loc.source(db).value, id) + res[key].insert(loc.ast_ptr(db).value, id) } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs index 51a4dd6f42a8..43381636721b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs @@ -340,7 +340,7 @@ impl ImplData { db: &dyn DefDatabase, id: ImplId, ) -> (Arc, DefDiagnostics) { - let _p = tracing::span!(tracing::Level::INFO, "impl_data_with_diagnostics_query").entered(); + let _p = tracing::info_span!("impl_data_with_diagnostics_query").entered(); let ItemLoc { container: module_id, id: tree_id } = id.lookup(db); let item_tree = tree_id.item_tree(db); @@ -628,7 +628,7 @@ impl<'a> AssocItemCollector<'a> { 'attrs: for attr in &*attrs { let ast_id = AstId::new(self.expander.current_file_id(), item.ast_id(item_tree).upcast()); - let ast_id_with_path = AstIdWithPath { path: (*attr.path).clone(), ast_id }; + let ast_id_with_path = AstIdWithPath { path: attr.path.clone(), ast_id }; match self.def_map.resolve_attr_macro( self.db, @@ -642,7 +642,7 @@ impl<'a> AssocItemCollector<'a> { continue 'attrs; } let loc = self.db.lookup_intern_macro_call(call_id); - if let MacroDefKind::ProcMacro(exp, ..) = loc.def.kind { + if let MacroDefKind::ProcMacro(_, exp, _) = loc.def.kind { // If there's no expander for the proc macro (e.g. the // proc macro is ignored, or building the proc macro // crate failed), skip expansion like we would if it was @@ -719,12 +719,12 @@ impl<'a> AssocItemCollector<'a> { let MacroCall { ast_id, expand_to, ctxt, ref path } = item_tree[call]; let module = self.expander.module.local_id; - let resolver = |path| { + let resolver = |path: &_| { self.def_map .resolve_path( self.db, module, - &path, + path, crate::item_scope::BuiltinShadowMode::Other, Some(MacroSubNs::Bang), ) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index 55ecabdc38e2..61fed71218ee 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -294,10 +294,10 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { let in_file = InFile::new(file_id, m); match expander { MacroExpander::Declarative => MacroDefKind::Declarative(in_file), - MacroExpander::BuiltIn(it) => MacroDefKind::BuiltIn(it, in_file), - MacroExpander::BuiltInAttr(it) => MacroDefKind::BuiltInAttr(it, in_file), - MacroExpander::BuiltInDerive(it) => MacroDefKind::BuiltInDerive(it, in_file), - MacroExpander::BuiltInEager(it) => MacroDefKind::BuiltInEager(it, in_file), + MacroExpander::BuiltIn(it) => MacroDefKind::BuiltIn(in_file, it), + MacroExpander::BuiltInAttr(it) => MacroDefKind::BuiltInAttr(in_file, it), + MacroExpander::BuiltInDerive(it) => MacroDefKind::BuiltInDerive(in_file, it), + MacroExpander::BuiltInEager(it) => MacroDefKind::BuiltInEager(in_file, it), } }; @@ -338,9 +338,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { MacroDefId { krate: loc.container.krate, kind: MacroDefKind::ProcMacro( + InFile::new(loc.id.file_id(), makro.ast_id), loc.expander, loc.kind, - InFile::new(loc.id.file_id(), makro.ast_id), ), local_inner: false, allow_internal_unsafe: false, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs index f83ab1e1a056..9d330a7bf1c0 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs @@ -13,7 +13,7 @@ use crate::{ TraitId, TypeAliasId, TypeOrConstParamId, UnionId, UseId, }; -pub type Key = crate::dyn_map::Key>; +pub type Key = crate::dyn_map::Key, V, AstPtrPolicy>; pub const BLOCK: Key = Key::new(); pub const FUNCTION: Key = Key::new(); @@ -39,6 +39,7 @@ pub const LIFETIME_PARAM: Key = Key::new(); pub const MACRO_RULES: Key = Key::new(); pub const MACRO2: Key = Key::new(); pub const PROC_MACRO: Key = Key::new(); +pub const MACRO_CALL: Key = Key::new(); pub const ATTR_MACRO_CALL: Key = Key::new(); pub const DERIVE_MACRO_CALL: Key]>)> = Key::new(); @@ -54,18 +55,16 @@ pub struct AstPtrPolicy { } impl Policy for AstPtrPolicy { - type K = AST; + type K = AstPtr; type V = ID; - fn insert(map: &mut DynMap, key: AST, value: ID) { - let key = AstPtr::new(&key); + fn insert(map: &mut DynMap, key: AstPtr, value: ID) { map.map .entry::, ID>>() .or_insert_with(Default::default) .insert(key, value); } - fn get<'a>(map: &'a DynMap, key: &AST) -> Option<&'a ID> { - let key = AstPtr::new(key); - map.map.get::, ID>>()?.get(&key) + fn get<'a>(map: &'a DynMap, key: &AstPtr) -> Option<&'a ID> { + map.map.get::, ID>>()?.get(key) } fn is_empty(map: &DynMap) -> bool { map.map.get::, ID>>().map_or(true, |it| it.is_empty()) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs index 73ce942c5807..dbf8e6b225c2 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs @@ -56,7 +56,7 @@ impl Expander { &mut self, db: &dyn DefDatabase, macro_call: ast::MacroCall, - resolver: impl Fn(ModPath) -> Option, + resolver: impl Fn(&ModPath) -> Option, ) -> Result)>>, UnresolvedMacro> { // FIXME: within_limit should support this, instead of us having to extract the error let mut unresolved_macro_err = None; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs index d9495d36c0d9..58a1872ef251 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs @@ -1,6 +1,6 @@ //! An algorithm to find a path to refer to a certain item. -use std::{cmp::Ordering, iter}; +use std::{cell::Cell, cmp::Ordering, iter}; use hir_expand::{ name::{known, AsName, Name}, @@ -23,15 +23,40 @@ pub fn find_path( db: &dyn DefDatabase, item: ItemInNs, from: ModuleId, - prefix_kind: PrefixKind, + mut prefix_kind: PrefixKind, ignore_local_imports: bool, - cfg: ImportPathConfig, + mut cfg: ImportPathConfig, ) -> Option { - let _p = tracing::span!(tracing::Level::INFO, "find_path").entered(); - find_path_inner(FindPathCtx { db, prefix: prefix_kind, cfg, ignore_local_imports }, item, from) + let _p = tracing::info_span!("find_path").entered(); + + // - if the item is a builtin, it's in scope + if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item { + return Some(ModPath::from_segments(PathKind::Plain, iter::once(builtin.as_name()))); + } + + // within block modules, forcing a `self` or `crate` prefix will not allow using inner items, so + // default to plain paths. + if item.module(db).is_some_and(ModuleId::is_within_block) { + prefix_kind = PrefixKind::Plain; + } + cfg.prefer_no_std = cfg.prefer_no_std || db.crate_supports_no_std(from.krate()); + + find_path_inner( + &FindPathCtx { + db, + prefix: prefix_kind, + cfg, + ignore_local_imports, + from, + from_def_map: &from.def_map(db), + fuel: Cell::new(FIND_PATH_FUEL), + }, + item, + MAX_PATH_LEN, + ) } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] enum Stability { Unstable, Stable, @@ -46,6 +71,7 @@ fn zip_stability(a: Stability, b: Stability) -> Stability { } const MAX_PATH_LEN: usize = 15; +const FIND_PATH_FUEL: usize = 10000; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum PrefixKind { @@ -63,79 +89,54 @@ impl PrefixKind { #[inline] fn path_kind(self) -> PathKind { match self { - PrefixKind::BySelf => PathKind::Super(0), + PrefixKind::BySelf => PathKind::SELF, PrefixKind::Plain => PathKind::Plain, PrefixKind::ByCrate => PathKind::Crate, } } } -#[derive(Copy, Clone)] struct FindPathCtx<'db> { db: &'db dyn DefDatabase, prefix: PrefixKind, cfg: ImportPathConfig, ignore_local_imports: bool, + from: ModuleId, + from_def_map: &'db DefMap, + fuel: Cell, } /// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId -fn find_path_inner(ctx: FindPathCtx<'_>, item: ItemInNs, from: ModuleId) -> Option { - // - if the item is a builtin, it's in scope - if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item { - return Some(ModPath::from_segments(PathKind::Plain, iter::once(builtin.as_name()))); - } - - let def_map = from.def_map(ctx.db); - let crate_root = from.derive_crate_root(); +fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Option { // - if the item is a module, jump straight to module search if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item { let mut visited_modules = FxHashSet::default(); - return find_path_for_module( - FindPathCtx { - cfg: ImportPathConfig { - prefer_no_std: ctx.cfg.prefer_no_std - || ctx.db.crate_supports_no_std(crate_root.krate), - ..ctx.cfg - }, - ..ctx - }, - &def_map, - &mut visited_modules, - from, - module_id, - MAX_PATH_LEN, - ) - .map(|(item, _)| item); + return find_path_for_module(ctx, &mut visited_modules, module_id, max_len) + .map(|(item, _)| item); } - let prefix = if item.module(ctx.db).is_some_and(|it| it.is_within_block()) { - PrefixKind::Plain - } else { - ctx.prefix - }; - let may_be_in_scope = match prefix { + let may_be_in_scope = match ctx.prefix { PrefixKind::Plain | PrefixKind::BySelf => true, - PrefixKind::ByCrate => from.is_crate_root(), + PrefixKind::ByCrate => ctx.from.is_crate_root(), }; if may_be_in_scope { // - if the item is already in scope, return the name under which it is - let scope_name = find_in_scope(ctx.db, &def_map, from, item, ctx.ignore_local_imports); + let scope_name = + find_in_scope(ctx.db, ctx.from_def_map, ctx.from, item, ctx.ignore_local_imports); if let Some(scope_name) = scope_name { - return Some(ModPath::from_segments(prefix.path_kind(), iter::once(scope_name))); + return Some(ModPath::from_segments(ctx.prefix.path_kind(), iter::once(scope_name))); } } // - if the item is in the prelude, return the name from there - if let value @ Some(_) = - find_in_prelude(ctx.db, &crate_root.def_map(ctx.db), &def_map, item, from) - { - return value; + if let Some(value) = find_in_prelude(ctx.db, ctx.from_def_map, item, ctx.from) { + return Some(value); } if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() { // - if the item is an enum variant, refer to it via the enum if let Some(mut path) = - find_path_inner(ctx, ItemInNs::Types(variant.lookup(ctx.db).parent.into()), from) + find_path_inner(ctx, ItemInNs::Types(variant.lookup(ctx.db).parent.into()), max_len) { path.push_segment(ctx.db.enum_variant_data(variant).name.clone()); return Some(path); @@ -147,53 +148,32 @@ fn find_path_inner(ctx: FindPathCtx<'_>, item: ItemInNs, from: ModuleId) -> Opti let mut visited_modules = FxHashSet::default(); - calculate_best_path( - FindPathCtx { - cfg: ImportPathConfig { - prefer_no_std: ctx.cfg.prefer_no_std - || ctx.db.crate_supports_no_std(crate_root.krate), - ..ctx.cfg - }, - ..ctx - }, - &def_map, - &mut visited_modules, - MAX_PATH_LEN, - item, - from, - ) - .map(|(item, _)| item) + calculate_best_path(ctx, &mut visited_modules, item, max_len).map(|(item, _)| item) } #[tracing::instrument(skip_all)] fn find_path_for_module( - ctx: FindPathCtx<'_>, - def_map: &DefMap, + ctx: &FindPathCtx<'_>, visited_modules: &mut FxHashSet, - from: ModuleId, module_id: ModuleId, max_len: usize, ) -> Option<(ModPath, Stability)> { - if max_len == 0 { - return None; - } + if let Some(crate_root) = module_id.as_crate_root() { + if crate_root == ctx.from.derive_crate_root() { + // - if the item is the crate root, return `crate` + return Some((ModPath::from_segments(PathKind::Crate, None), Stable)); + } + // - otherwise if the item is the crate root of a dependency crate, return the name from the extern prelude - let is_crate_root = module_id.as_crate_root(); - // - if the item is the crate root, return `crate` - if is_crate_root.is_some_and(|it| it == from.derive_crate_root()) { - return Some((ModPath::from_segments(PathKind::Crate, None), Stable)); - } - - let root_def_map = from.derive_crate_root().def_map(ctx.db); - // - if the item is the crate root of a dependency crate, return the name from the extern prelude - if let Some(crate_root) = is_crate_root { + let root_def_map = ctx.from.derive_crate_root().def_map(ctx.db); // rev here so we prefer looking at renamed extern decls first for (name, (def_id, _extern_crate)) in root_def_map.extern_prelude().rev() { if crate_root != def_id { continue; } - let name_already_occupied_in_type_ns = def_map - .with_ancestor_maps(ctx.db, from.local_id, &mut |def_map, local_id| { + let name_already_occupied_in_type_ns = ctx + .from_def_map + .with_ancestor_maps(ctx.db, ctx.from.local_id, &mut |def_map, local_id| { def_map[local_id] .scope .type_(name) @@ -209,30 +189,30 @@ fn find_path_for_module( return Some((ModPath::from_segments(kind, iter::once(name.clone())), Stable)); } } - let prefix = if module_id.is_within_block() { PrefixKind::Plain } else { ctx.prefix }; - let may_be_in_scope = match prefix { + + let may_be_in_scope = match ctx.prefix { PrefixKind::Plain | PrefixKind::BySelf => true, - PrefixKind::ByCrate => from.is_crate_root(), + PrefixKind::ByCrate => ctx.from.is_crate_root(), }; if may_be_in_scope { let scope_name = find_in_scope( ctx.db, - def_map, - from, + ctx.from_def_map, + ctx.from, ItemInNs::Types(module_id.into()), ctx.ignore_local_imports, ); if let Some(scope_name) = scope_name { // - if the item is already in scope, return the name under which it is return Some(( - ModPath::from_segments(prefix.path_kind(), iter::once(scope_name)), + ModPath::from_segments(ctx.prefix.path_kind(), iter::once(scope_name)), Stable, )); } } // - if the module can be referenced as self, super or crate, do that - if let Some(mod_path) = is_kw_kind_relative_to_from(def_map, module_id, from) { + if let Some(mod_path) = is_kw_kind_relative_to_from(ctx.from_def_map, module_id, ctx.from) { if ctx.prefix != PrefixKind::ByCrate || mod_path.kind == PathKind::Crate { return Some((mod_path, Stable)); } @@ -240,21 +220,13 @@ fn find_path_for_module( // - if the module is in the prelude, return it by that path if let Some(mod_path) = - find_in_prelude(ctx.db, &root_def_map, def_map, ItemInNs::Types(module_id.into()), from) + find_in_prelude(ctx.db, ctx.from_def_map, ItemInNs::Types(module_id.into()), ctx.from) { return Some((mod_path, Stable)); } - calculate_best_path( - ctx, - def_map, - visited_modules, - max_len, - ItemInNs::Types(module_id.into()), - from, - ) + calculate_best_path(ctx, visited_modules, ItemInNs::Types(module_id.into()), max_len) } -// FIXME: Do we still need this now that we record import origins, and hence aliases? fn find_in_scope( db: &dyn DefDatabase, def_map: &DefMap, @@ -274,13 +246,11 @@ fn find_in_scope( /// name doesn't clash in current scope. fn find_in_prelude( db: &dyn DefDatabase, - root_def_map: &DefMap, local_def_map: &DefMap, item: ItemInNs, from: ModuleId, ) -> Option { - let (prelude_module, _) = root_def_map.prelude()?; - // Preludes in block DefMaps are ignored, only the crate DefMap is searched + let (prelude_module, _) = local_def_map.prelude()?; let prelude_def_map = prelude_module.def_map(db); let prelude_scope = &prelude_def_map[prelude_module.local_id].scope; let (name, vis, _declared) = prelude_scope.name_of(item)?; @@ -319,7 +289,7 @@ fn is_kw_kind_relative_to_from( let from = from.local_id; if item == from { // - if the item is the module we're in, use `self` - Some(ModPath::from_segments(PathKind::Super(0), None)) + Some(ModPath::from_segments(PathKind::SELF, None)) } else if let Some(parent_id) = def_map[from].parent { if item == parent_id { // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly) @@ -337,60 +307,71 @@ fn is_kw_kind_relative_to_from( #[tracing::instrument(skip_all)] fn calculate_best_path( - ctx: FindPathCtx<'_>, - def_map: &DefMap, + ctx: &FindPathCtx<'_>, visited_modules: &mut FxHashSet, - max_len: usize, item: ItemInNs, - from: ModuleId, + max_len: usize, ) -> Option<(ModPath, Stability)> { if max_len <= 1 { + // recursive base case, we can't find a path prefix of length 0, one segment is occupied by + // the item's name itself. return None; } + let fuel = ctx.fuel.get(); + if fuel == 0 { + // we ran out of fuel, so we stop searching here + tracing::warn!( + "ran out of fuel while searching for a path for item {item:?} of krate {:?} from krate {:?}", + item.krate(ctx.db), + ctx.from.krate() + ); + return None; + } + ctx.fuel.set(fuel - 1); + let mut best_path = None; - let update_best_path = - |best_path: &mut Option<_>, new_path: (ModPath, Stability)| match best_path { + let mut best_path_len = max_len; + let mut process = |mut path: (ModPath, Stability), name, best_path_len: &mut _| { + path.0.push_segment(name); + let new_path = match best_path.take() { + Some(best_path) => select_best_path(best_path, path, ctx.cfg), + None => path, + }; + if new_path.1 == Stable { + *best_path_len = new_path.0.len(); + } + match &mut best_path { Some((old_path, old_stability)) => { *old_path = new_path.0; *old_stability = zip_stability(*old_stability, new_path.1); } - None => *best_path = Some(new_path), - }; - // Recursive case: - // - otherwise, look for modules containing (reexporting) it and import it from one of those - if item.krate(ctx.db) == Some(from.krate) { - let mut best_path_len = max_len; + None => best_path = Some(new_path), + } + }; + let db = ctx.db; + if item.krate(db) == Some(ctx.from.krate) { // Item was defined in the same crate that wants to import it. It cannot be found in any // dependency in this case. - for (module_id, name) in find_local_import_locations(ctx.db, item, from) { + // FIXME: cache the `find_local_import_locations` output? + find_local_import_locations(db, item, ctx.from, ctx.from_def_map, |name, module_id| { if !visited_modules.insert(module_id) { - continue; + return; } - if let Some(mut path) = find_path_for_module( - ctx, - def_map, - visited_modules, - from, - module_id, - best_path_len - 1, - ) { - path.0.push_segment(name); - - let new_path = match best_path.take() { - Some(best_path) => select_best_path(best_path, path, ctx.cfg), - None => path, - }; - best_path_len = new_path.0.len(); - update_best_path(&mut best_path, new_path); + // we are looking for paths of length up to best_path_len, any longer will make it be + // less optimal. The -1 is due to us pushing name onto it afterwards. + if let Some(path) = + find_path_for_module(ctx, visited_modules, module_id, best_path_len - 1) + { + process(path, name.clone(), &mut best_path_len); } - } + }) } else { // Item was defined in some upstream crate. This means that it must be exported from one, // too (unless we can't name it at all). It could *also* be (re)exported by the same crate // that wants to import it here, but we always prefer to use the external path here. - for dep in &ctx.db.crate_graph()[from.krate].dependencies { - let import_map = ctx.db.import_map(dep.crate_id); + for dep in &db.crate_graph()[ctx.from.krate].dependencies { + let import_map = db.import_map(dep.crate_id); let Some(import_info_for) = import_map.import_info_for(item) else { continue }; for info in import_info_for { if info.is_doc_hidden { @@ -400,29 +381,18 @@ fn calculate_best_path( // Determine best path for containing module and append last segment from `info`. // FIXME: we should guide this to look up the path locally, or from the same crate again? - let Some((mut path, path_stability)) = find_path_for_module( - ctx, - def_map, - visited_modules, - from, - info.container, - max_len - 1, - ) else { + let path = + find_path_for_module(ctx, visited_modules, info.container, best_path_len - 1); + let Some((path, path_stability)) = path else { continue; }; cov_mark::hit!(partially_imported); - path.push_segment(info.name.clone()); - - let path_with_stab = ( + let path = ( path, zip_stability(path_stability, if info.is_unstable { Unstable } else { Stable }), ); - let new_path_with_stab = match best_path.take() { - Some(best_path) => select_best_path(best_path, path_with_stab, ctx.cfg), - None => path_with_stab, - }; - update_best_path(&mut best_path, new_path_with_stab); + process(path, info.name.clone(), &mut best_path_len); } } } @@ -430,7 +400,7 @@ fn calculate_best_path( } /// Select the best (most relevant) path between two paths. -/// This accounts for stability, path length whether std should be chosen over alloc/core paths as +/// This accounts for stability, path length whether, std should be chosen over alloc/core paths as /// well as ignoring prelude like paths or not. fn select_best_path( old_path @ (_, old_stability): (ModPath, Stability), @@ -496,36 +466,33 @@ fn select_best_path( } } -// FIXME: Remove allocations /// Finds locations in `from.krate` from which `item` can be imported by `from`. fn find_local_import_locations( db: &dyn DefDatabase, item: ItemInNs, from: ModuleId, -) -> Vec<(ModuleId, Name)> { - let _p = tracing::span!(tracing::Level::INFO, "find_local_import_locations").entered(); + def_map: &DefMap, + mut cb: impl FnMut(&Name, ModuleId), +) { + let _p = tracing::info_span!("find_local_import_locations").entered(); // `from` can import anything below `from` with visibility of at least `from`, and anything // above `from` with any visibility. That means we do not need to descend into private siblings // of `from` (and similar). - let def_map = from.def_map(db); - // Compute the initial worklist. We start with all direct child modules of `from` as well as all // of its (recursive) parent modules. - let data = &def_map[from.local_id]; - let mut worklist = - data.children.values().map(|child| def_map.module_id(*child)).collect::>(); - // FIXME: do we need to traverse out of block expressions here? - for ancestor in iter::successors(from.containing_module(db), |m| m.containing_module(db)) { - worklist.push(ancestor); - } + let mut worklist = def_map[from.local_id] + .children + .values() + .map(|child| def_map.module_id(*child)) + // FIXME: do we need to traverse out of block expressions here? + .chain(iter::successors(from.containing_module(db), |m| m.containing_module(db))) + .collect::>(); + let mut seen: FxHashSet<_> = FxHashSet::default(); let def_map = def_map.crate_root().def_map(db); - let mut seen: FxHashSet<_> = FxHashSet::default(); - - let mut locations = Vec::new(); while let Some(module) = worklist.pop() { if !seen.insert(module) { continue; // already processed this module @@ -566,7 +533,7 @@ fn find_local_import_locations( // the item and we're a submodule of it, so can we. // Also this keeps the cached data smaller. if declared || is_pub_or_explicit { - locations.push((module, name.clone())); + cb(name, module); } } } @@ -578,8 +545,6 @@ fn find_local_import_locations( } } } - - locations } #[cfg(test)] @@ -633,15 +598,13 @@ mod tests { .into_iter() .cartesian_product([false, true]) { - let found_path = find_path_inner( - FindPathCtx { - db: &db, - prefix, - cfg: ImportPathConfig { prefer_no_std: false, prefer_prelude }, - ignore_local_imports, - }, + let found_path = find_path( + &db, resolved, module, + prefix, + ignore_local_imports, + ImportPathConfig { prefer_no_std: false, prefer_prelude }, ); format_to!( res, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs index 10a1d65bb933..b9f8082391f1 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs @@ -11,7 +11,7 @@ use hir_expand::{ ExpandResult, }; use intern::Interned; -use la_arena::Arena; +use la_arena::{Arena, RawIdx}; use once_cell::unsync::Lazy; use stdx::impl_from; use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds}; @@ -28,6 +28,9 @@ use crate::{ LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId, }; +const SELF_PARAM_ID_IN_SELF: la_arena::Idx = + LocalTypeOrConstParamId::from_raw(RawIdx::from_u32(0)); + /// Data about a generic type parameter (to a function, struct, impl, ...). #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TypeParamData { @@ -403,12 +406,12 @@ impl GenericParamsCollector { let (def_map, expander) = &mut **exp; let module = expander.module.local_id; - let resolver = |path| { + let resolver = |path: &_| { def_map .resolve_path( db, module, - &path, + path, crate::item_scope::BuiltinShadowMode::Other, Some(MacroSubNs::Bang), ) @@ -441,15 +444,18 @@ impl GenericParamsCollector { impl GenericParams { /// Number of Generic parameters (type_or_consts + lifetimes) + #[inline] pub fn len(&self) -> usize { self.type_or_consts.len() + self.lifetimes.len() } + #[inline] pub fn is_empty(&self) -> bool { self.len() == 0 } /// Iterator of type_or_consts field + #[inline] pub fn iter_type_or_consts( &self, ) -> impl DoubleEndedIterator { @@ -457,6 +463,7 @@ impl GenericParams { } /// Iterator of lifetimes field + #[inline] pub fn iter_lt( &self, ) -> impl DoubleEndedIterator { @@ -467,7 +474,7 @@ impl GenericParams { db: &dyn DefDatabase, def: GenericDefId, ) -> Interned { - let _p = tracing::span!(tracing::Level::INFO, "generic_params_query").entered(); + let _p = tracing::info_span!("generic_params_query").entered(); let krate = def.module(db).krate; let cfg_options = db.crate_graph(); @@ -605,17 +612,18 @@ impl GenericParams { }) } - pub fn find_trait_self_param(&self) -> Option { - self.type_or_consts.iter().find_map(|(id, p)| { - matches!( - p, - TypeOrConstParamData::TypeParamData(TypeParamData { - provenance: TypeParamProvenance::TraitSelf, - .. - }) - ) - .then(|| id) - }) + pub fn trait_self_param(&self) -> Option { + if self.type_or_consts.is_empty() { + return None; + } + matches!( + self.type_or_consts[SELF_PARAM_ID_IN_SELF], + TypeOrConstParamData::TypeParamData(TypeParamData { + provenance: TypeParamProvenance::TraitSelf, + .. + }) + ) + .then(|| SELF_PARAM_ID_IN_SELF) } pub fn find_lifetime_by_name( diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs index 2f7ebbfec13a..fd6f4a3d089d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs @@ -503,11 +503,11 @@ impl BindingAnnotation { #[derive(Debug, Clone, Eq, PartialEq)] pub enum BindingProblems { - /// https://doc.rust-lang.org/stable/error_codes/E0416.html + /// BoundMoreThanOnce, - /// https://doc.rust-lang.org/stable/error_codes/E0409.html + /// BoundInconsistently, - /// https://doc.rust-lang.org/stable/error_codes/E0408.html + /// NotBoundAcrossAll, } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs index 6e40293dbf8e..2b2db21a9f41 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs @@ -73,7 +73,7 @@ impl ImportMap { } pub(crate) fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc { - let _p = tracing::span!(tracing::Level::INFO, "import_map_query").entered(); + let _p = tracing::info_span!("import_map_query").entered(); let map = Self::collect_import_map(db, krate); @@ -124,7 +124,7 @@ impl ImportMap { } fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMapIndex { - let _p = tracing::span!(tracing::Level::INFO, "collect_import_map").entered(); + let _p = tracing::info_span!("collect_import_map").entered(); let def_map = db.crate_def_map(krate); let mut map = FxIndexMap::default(); @@ -214,7 +214,7 @@ impl ImportMap { is_type_in_ns: bool, trait_import_info: &ImportInfo, ) { - let _p = tracing::span!(tracing::Level::INFO, "collect_trait_assoc_items").entered(); + let _p = tracing::info_span!("collect_trait_assoc_items").entered(); for &(ref assoc_item_name, item) in &db.trait_data(tr).items { let module_def_id = match item { AssocItemId::FunctionId(f) => ModuleDefId::from(f), @@ -396,7 +396,7 @@ pub fn search_dependencies( krate: CrateId, query: &Query, ) -> FxHashSet { - let _p = tracing::span!(tracing::Level::INFO, "search_dependencies", ?query).entered(); + let _p = tracing::info_span!("search_dependencies", ?query).entered(); let graph = db.crate_graph(); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index acda64c41fb2..c3b7a78301d2 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -99,7 +99,7 @@ pub struct ItemTree { impl ItemTree { pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc { - let _p = tracing::span!(tracing::Level::INFO, "file_item_tree_query", ?file_id).entered(); + let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered(); let syntax = db.parse_or_expand(file_id); @@ -242,11 +242,11 @@ impl ItemVisibilities { match &vis { RawVisibility::Public => RawVisibilityId::PUB, RawVisibility::Module(path, explicitiy) if path.segments().is_empty() => { - match (&path.kind, explicitiy) { - (PathKind::Super(0), VisibilityExplicitness::Explicit) => { + match (path.kind, explicitiy) { + (PathKind::SELF, VisibilityExplicitness::Explicit) => { RawVisibilityId::PRIV_EXPLICIT } - (PathKind::Super(0), VisibilityExplicitness::Implicit) => { + (PathKind::SELF, VisibilityExplicitness::Implicit) => { RawVisibilityId::PRIV_IMPLICIT } (PathKind::Crate, _) => RawVisibilityId::PUB_CRATE, @@ -586,11 +586,11 @@ impl Index for ItemTree { fn index(&self, index: RawVisibilityId) -> &Self::Output { static VIS_PUB: RawVisibility = RawVisibility::Public; static VIS_PRIV_IMPLICIT: RawVisibility = RawVisibility::Module( - ModPath::from_kind(PathKind::Super(0)), + ModPath::from_kind(PathKind::SELF), VisibilityExplicitness::Implicit, ); static VIS_PRIV_EXPLICIT: RawVisibility = RawVisibility::Module( - ModPath::from_kind(PathKind::Super(0)), + ModPath::from_kind(PathKind::SELF), VisibilityExplicitness::Explicit, ); static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module( @@ -928,7 +928,7 @@ impl UseTree { _ => None, } } - (Some(prefix), PathKind::Super(0)) if path.segments().is_empty() => { + (Some(prefix), PathKind::SELF) if path.segments().is_empty() => { // `some::path::self` == `some::path` Some((prefix, ImportKind::TypeOnly)) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index 3a07c678428e..6d7836d5ae89 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -91,7 +91,7 @@ impl LangItems { db: &dyn DefDatabase, krate: CrateId, ) -> Option> { - let _p = tracing::span!(tracing::Level::INFO, "crate_lang_items_query").entered(); + let _p = tracing::info_span!("crate_lang_items_query").entered(); let mut lang_items = LangItems::default(); @@ -163,7 +163,7 @@ impl LangItems { start_crate: CrateId, item: LangItem, ) -> Option { - let _p = tracing::span!(tracing::Level::INFO, "lang_item_query").entered(); + let _p = tracing::info_span!("lang_item_query").entered(); if let Some(target) = db.crate_lang_items(start_crate).and_then(|it| it.items.get(&item).copied()) { @@ -183,7 +183,7 @@ impl LangItems { ) where T: Into + Copy, { - let _p = tracing::span!(tracing::Level::INFO, "collect_lang_item").entered(); + let _p = tracing::info_span!("collect_lang_item").entered(); if let Some(lang_item) = lang_attr(db, item.into()) { self.items.entry(lang_item).or_insert_with(|| constructor(item)); } @@ -199,7 +199,7 @@ pub(crate) fn notable_traits_in_deps( db: &dyn DefDatabase, krate: CrateId, ) -> Arc<[Arc<[TraitId]>]> { - let _p = tracing::span!(tracing::Level::INFO, "notable_traits_in_deps", ?krate).entered(); + let _p = tracing::info_span!("notable_traits_in_deps", ?krate).entered(); let crate_graph = db.crate_graph(); Arc::from_iter( @@ -208,7 +208,7 @@ pub(crate) fn notable_traits_in_deps( } pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: CrateId) -> Option> { - let _p = tracing::span!(tracing::Level::INFO, "crate_notable_traits", ?krate).entered(); + let _p = tracing::info_span!("crate_notable_traits", ?krate).entered(); let mut traits = Vec::new(); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index 682d169adb11..f6fe0c618a29 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -56,6 +56,7 @@ pub mod find_path; pub mod import_map; pub mod visibility; +use intern::Interned; pub use rustc_abi as layout; use triomphe::Arc; @@ -72,7 +73,7 @@ use std::{ use base_db::{ impl_intern_key, - salsa::{self, impl_intern_value_trivial}, + salsa::{self, InternValueTrivial}, CrateId, }; use hir_expand::{ @@ -90,7 +91,7 @@ use hir_expand::{ use item_tree::ExternBlock; use la_arena::Idx; use nameres::DefMap; -use span::{AstIdNode, Edition, FileAstId, FileId, SyntaxContextId}; +use span::{AstIdNode, Edition, FileAstId, SyntaxContextId}; use stdx::impl_from; use syntax::{ast, AstNode}; @@ -186,7 +187,7 @@ pub trait ItemTreeLoc { macro_rules! impl_intern { ($id:ident, $loc:ident, $intern:ident, $lookup:ident) => { impl_intern_key!($id); - impl_intern_value_trivial!($loc); + impl InternValueTrivial for $loc {} impl_intern_lookup!(DefDatabase, $id, $loc, $intern, $lookup); }; } @@ -396,6 +397,23 @@ impl PartialEq for CrateRootModuleId { other.block.is_none() && other.local_id == DefMap::ROOT && self.krate == other.krate } } +impl PartialEq for ModuleId { + fn eq(&self, other: &CrateRootModuleId) -> bool { + other == self + } +} + +impl From for ModuleId { + fn from(CrateRootModuleId { krate }: CrateRootModuleId) -> Self { + ModuleId { krate, block: None, local_id: DefMap::ROOT } + } +} + +impl From for ModuleDefId { + fn from(value: CrateRootModuleId) -> Self { + ModuleDefId::ModuleId(value.into()) + } +} impl From for CrateRootModuleId { fn from(krate: CrateId) -> Self { @@ -472,6 +490,7 @@ impl ModuleId { self.block.is_some() } + /// Returns the [`CrateRootModuleId`] for this module if it is the crate root module. pub fn as_crate_root(&self) -> Option { if self.local_id == DefMap::ROOT && self.block.is_none() { Some(CrateRootModuleId { krate: self.krate }) @@ -480,33 +499,17 @@ impl ModuleId { } } + /// Returns the [`CrateRootModuleId`] for this module. pub fn derive_crate_root(&self) -> CrateRootModuleId { CrateRootModuleId { krate: self.krate } } + /// Whether this module represents the crate root module fn is_crate_root(&self) -> bool { self.local_id == DefMap::ROOT && self.block.is_none() } } -impl PartialEq for ModuleId { - fn eq(&self, other: &CrateRootModuleId) -> bool { - other == self - } -} - -impl From for ModuleId { - fn from(CrateRootModuleId { krate }: CrateRootModuleId) -> Self { - ModuleId { krate, block: None, local_id: DefMap::ROOT } - } -} - -impl From for ModuleDefId { - fn from(value: CrateRootModuleId) -> Self { - ModuleDefId::ModuleId(value.into()) - } -} - /// An ID of a module, **local** to a `DefMap`. pub type LocalModuleId = Idx; @@ -532,7 +535,7 @@ pub struct TypeOrConstParamId { pub parent: GenericDefId, pub local_id: LocalTypeOrConstParamId, } -impl_intern_value_trivial!(TypeOrConstParamId); +impl InternValueTrivial for TypeOrConstParamId {} /// A TypeOrConstParamId with an invariant that it actually belongs to a type #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -594,7 +597,7 @@ pub struct LifetimeParamId { pub local_id: LocalLifetimeParamId, } pub type LocalLifetimeParamId = Idx; -impl_intern_value_trivial!(LifetimeParamId); +impl InternValueTrivial for LifetimeParamId {} #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ItemContainerId { @@ -920,6 +923,7 @@ pub enum GenericDefId { ImplId(ImplId), // enum variants cannot have generics themselves, but their parent enums // can, and this makes some code easier to write + // FIXME: Try to remove this as that will reduce the amount of query slots generated per enum? EnumVariantId(EnumVariantId), // consts can have type parameters from their parents (i.e. associated consts of traits) ConstId(ConstId), @@ -956,15 +960,14 @@ impl GenericDefId { match self { GenericDefId::FunctionId(it) => file_id_and_params_of_item_loc(db, it), GenericDefId::TypeAliasId(it) => file_id_and_params_of_item_loc(db, it), - GenericDefId::ConstId(_) => (FileId::BOGUS.into(), None), GenericDefId::AdtId(AdtId::StructId(it)) => file_id_and_params_of_item_loc(db, it), GenericDefId::AdtId(AdtId::UnionId(it)) => file_id_and_params_of_item_loc(db, it), GenericDefId::AdtId(AdtId::EnumId(it)) => file_id_and_params_of_item_loc(db, it), GenericDefId::TraitId(it) => file_id_and_params_of_item_loc(db, it), GenericDefId::TraitAliasId(it) => file_id_and_params_of_item_loc(db, it), GenericDefId::ImplId(it) => file_id_and_params_of_item_loc(db, it), - // We won't be using this ID anyway - GenericDefId::EnumVariantId(_) => (FileId::BOGUS.into(), None), + GenericDefId::ConstId(it) => (it.lookup(db).id.file_id(), None), + GenericDefId::EnumVariantId(it) => (it.lookup(db).id.file_id(), None), } } @@ -1368,7 +1371,7 @@ pub trait AsMacroCall { &self, db: &dyn ExpandDatabase, krate: CrateId, - resolver: impl Fn(path::ModPath) -> Option + Copy, + resolver: impl Fn(&path::ModPath) -> Option + Copy, ) -> Option { self.as_call_id_with_errors(db, krate, resolver).ok()?.value } @@ -1377,7 +1380,7 @@ pub trait AsMacroCall { &self, db: &dyn ExpandDatabase, krate: CrateId, - resolver: impl Fn(path::ModPath) -> Option + Copy, + resolver: impl Fn(&path::ModPath) -> Option + Copy, ) -> Result>, UnresolvedMacro>; } @@ -1386,7 +1389,7 @@ impl AsMacroCall for InFile<&ast::MacroCall> { &self, db: &dyn ExpandDatabase, krate: CrateId, - resolver: impl Fn(path::ModPath) -> Option + Copy, + resolver: impl Fn(&path::ModPath) -> Option + Copy, ) -> Result>, UnresolvedMacro> { let expands_to = hir_expand::ExpandTo::from_call_site(self.value); let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); @@ -1406,7 +1409,8 @@ impl AsMacroCall for InFile<&ast::MacroCall> { macro_call_as_call_id_with_eager( db, - &AstIdWithPath::new(ast_id.file_id, ast_id.value, path), + ast_id, + &path, call_site.ctx, expands_to, krate, @@ -1420,11 +1424,15 @@ impl AsMacroCall for InFile<&ast::MacroCall> { #[derive(Clone, Debug, Eq, PartialEq)] struct AstIdWithPath { ast_id: AstId, - path: path::ModPath, + path: Interned, } impl AstIdWithPath { - fn new(file_id: HirFileId, ast_id: FileAstId, path: path::ModPath) -> AstIdWithPath { + fn new( + file_id: HirFileId, + ast_id: FileAstId, + path: Interned, + ) -> AstIdWithPath { AstIdWithPath { ast_id: AstId::new(file_id, ast_id), path } } } @@ -1435,30 +1443,39 @@ fn macro_call_as_call_id( call_site: SyntaxContextId, expand_to: ExpandTo, krate: CrateId, - resolver: impl Fn(path::ModPath) -> Option + Copy, + resolver: impl Fn(&path::ModPath) -> Option + Copy, ) -> Result, UnresolvedMacro> { - macro_call_as_call_id_with_eager(db, call, call_site, expand_to, krate, resolver, resolver) - .map(|res| res.value) + macro_call_as_call_id_with_eager( + db, + call.ast_id, + &call.path, + call_site, + expand_to, + krate, + resolver, + resolver, + ) + .map(|res| res.value) } fn macro_call_as_call_id_with_eager( db: &dyn ExpandDatabase, - call: &AstIdWithPath, + ast_id: AstId, + path: &path::ModPath, call_site: SyntaxContextId, expand_to: ExpandTo, krate: CrateId, - resolver: impl FnOnce(path::ModPath) -> Option, - eager_resolver: impl Fn(path::ModPath) -> Option, + resolver: impl FnOnce(&path::ModPath) -> Option, + eager_resolver: impl Fn(&path::ModPath) -> Option, ) -> Result>, UnresolvedMacro> { - let def = - resolver(call.path.clone()).ok_or_else(|| UnresolvedMacro { path: call.path.clone() })?; + let def = resolver(path).ok_or_else(|| UnresolvedMacro { path: path.clone() })?; let res = match def.kind { MacroDefKind::BuiltInEager(..) => expand_eager_macro_input( db, krate, - &call.ast_id.to_node(db), - call.ast_id, + &ast_id.to_node(db), + ast_id, def, call_site, &|path| eager_resolver(path).filter(MacroDefId::is_fn_like), @@ -1467,12 +1484,12 @@ fn macro_call_as_call_id_with_eager( value: Some(def.make_call( db, krate, - MacroCallKind::FnLike { ast_id: call.ast_id, expand_to, eager: None }, + MacroCallKind::FnLike { ast_id, expand_to, eager: None }, call_site, )), err: None, }, - _ => return Err(UnresolvedMacro { path: call.path.clone() }), + _ => return Err(UnresolvedMacro { path: path.clone() }), }; Ok(res) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs index c5c26e26bc0e..4058159cefef 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -1883,3 +1883,41 @@ fn test() { "#]], ); } + +#[test] +fn test_pat_fragment_eof_17441() { + check( + r#" +macro_rules! matches { + ($expression:expr, $pattern:pat $(if $guard:expr)? ) => { + match $expression { + $pattern $(if $guard)? => true, + _ => false + } + }; +} +fn f() { + matches!(0, 10..); + matches!(0, 10.. if true); +} + "#, + expect![[r#" +macro_rules! matches { + ($expression:expr, $pattern:pat $(if $guard:expr)? ) => { + match $expression { + $pattern $(if $guard)? => true, + _ => false + } + }; +} +fn f() { + match 0 { + 10.. =>true , _=>false + }; + match 0 { + 10..if true =>true , _=>false + }; +} + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs index 8904aca9f284..dc964b3c9a8d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -96,7 +96,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream let res = macro_call .as_call_id_with_errors(&db, krate, |path| { resolver - .resolve_path_as_macro(&db, &path, Some(MacroSubNs::Bang)) + .resolve_path_as_macro(&db, path, Some(MacroSubNs::Bang)) .map(|(it, _)| db.macro_def(it)) }) .unwrap(); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs index a3eab22fc49c..162b6429c341 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs @@ -16,8 +16,8 @@ //! //! This happens in the `raw` module, which parses a single source file into a //! set of top-level items. Nested imports are desugared to flat imports in this -//! phase. Macro calls are represented as a triple of (Path, Option, -//! TokenTree). +//! phase. Macro calls are represented as a triple of `(Path, Option, +//! TokenTree)`. //! //! ## Collecting Modules //! @@ -333,7 +333,7 @@ impl DefMap { let crate_graph = db.crate_graph(); let krate = &crate_graph[crate_id]; let name = krate.display_name.as_deref().unwrap_or_default(); - let _p = tracing::span!(tracing::Level::INFO, "crate_def_map_query", ?name).entered(); + let _p = tracing::info_span!("crate_def_map_query", ?name).entered(); let module_data = ModuleData::new( ModuleOrigin::CrateRoot { definition: krate.root_file_id }, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs index 3cb0666edf9c..f842027d642a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs @@ -3,6 +3,7 @@ use base_db::CrateId; use hir_expand::{ attrs::{Attr, AttrId, AttrInput}, + inert_attr_macro::find_builtin_attr_idx, MacroCallId, MacroCallKind, MacroDefId, }; use span::SyntaxContextId; @@ -10,7 +11,6 @@ use syntax::{ast, SmolStr}; use triomphe::Arc; use crate::{ - attr::builtin::find_builtin_attr_idx, db::DefDatabase, item_scope::BuiltinShadowMode, nameres::path_resolution::ResolveMode, @@ -59,7 +59,7 @@ impl DefMap { return Ok(ResolvedAttr::Other); } } - None => return Err(UnresolvedMacro { path: ast_id.path }), + None => return Err(UnresolvedMacro { path: ast_id.path.as_ref().clone() }), }; Ok(ResolvedAttr::Macro(attr_macro_as_call_id( @@ -89,9 +89,12 @@ impl DefMap { } if segments.len() == 1 { - let mut registered = self.data.registered_attrs.iter().map(SmolStr::as_str); - let is_inert = find_builtin_attr_idx(&name).is_some() || registered.any(pred); - return is_inert; + if find_builtin_attr_idx(&name).is_some() { + return true; + } + if self.data.registered_attrs.iter().map(SmolStr::as_str).any(pred) { + return true; + } } } false @@ -134,12 +137,12 @@ pub(super) fn derive_macro_as_call_id( derive_pos: u32, call_site: SyntaxContextId, krate: CrateId, - resolver: impl Fn(path::ModPath) -> Option<(MacroId, MacroDefId)>, + resolver: impl Fn(&path::ModPath) -> Option<(MacroId, MacroDefId)>, derive_macro_id: MacroCallId, ) -> Result<(MacroId, MacroDefId, MacroCallId), UnresolvedMacro> { - let (macro_id, def_id) = resolver(item_attr.path.clone()) + let (macro_id, def_id) = resolver(&item_attr.path) .filter(|(_, def_id)| def_id.is_derive()) - .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?; + .ok_or_else(|| UnresolvedMacro { path: item_attr.path.as_ref().clone() })?; let call_id = def_id.make_call( db.upcast(), krate, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 587997c47361..6d2eb71549e7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -10,18 +10,19 @@ use cfg::{CfgExpr, CfgOptions}; use either::Either; use hir_expand::{ attrs::{Attr, AttrId}, - builtin_attr_macro::{find_builtin_attr, BuiltinAttrExpander}, + builtin_attr_macro::find_builtin_attr, builtin_derive_macro::find_builtin_derive, builtin_fn_macro::find_builtin_macro, name::{name, AsName, Name}, proc_macro::CustomProcMacroExpander, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, }; +use intern::Interned; use itertools::{izip, Itertools}; use la_arena::Idx; use limit::Limit; use rustc_hash::{FxHashMap, FxHashSet}; -use span::{Edition, ErasedFileAstId, FileAstId, Span, SyntaxContextId}; +use span::{Edition, ErasedFileAstId, FileAstId, SyntaxContextId}; use syntax::ast; use triomphe::Arc; @@ -75,36 +76,23 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI let proc_macros = if krate.is_proc_macro { match db.proc_macros().get(&def_map.krate) { - Some(Ok(proc_macros)) => { - Ok(proc_macros - .iter() - .enumerate() - .map(|(idx, it)| { - // FIXME: a hacky way to create a Name from string. - let name = tt::Ident { - text: it.name.clone(), - span: Span { - range: syntax::TextRange::empty(syntax::TextSize::new(0)), - anchor: span::SpanAnchor { - file_id: FileId::BOGUS, - ast_id: span::ROOT_ERASED_FILE_AST_ID, - }, - ctx: SyntaxContextId::ROOT, - }, - }; - ( - name.as_name(), - if it.disabled { - CustomProcMacroExpander::disabled() - } else { - CustomProcMacroExpander::new( - hir_expand::proc_macro::ProcMacroId::new(idx as u32), - ) - }, - ) - }) - .collect()) - } + Some(Ok(proc_macros)) => Ok(proc_macros + .iter() + .enumerate() + .map(|(idx, it)| { + let name = Name::new_text_dont_use(it.name.clone()); + ( + name, + if it.disabled { + CustomProcMacroExpander::disabled() + } else { + CustomProcMacroExpander::new(hir_expand::proc_macro::ProcMacroId::new( + idx as u32, + )) + }, + ) + }) + .collect()), Some(Err(e)) => Err(e.clone().into_boxed_str()), None => Err("No proc-macros present for crate".to_owned().into_boxed_str()), } @@ -270,12 +258,13 @@ struct DefCollector<'a> { /// /// This also stores the attributes to skip when we resolve derive helpers and non-macro /// non-builtin attributes in general. + // FIXME: There has to be a better way to do this skip_attrs: FxHashMap, AttrId>, } impl DefCollector<'_> { fn seed_with_top_level(&mut self) { - let _p = tracing::span!(tracing::Level::INFO, "seed_with_top_level").entered(); + let _p = tracing::info_span!("seed_with_top_level").entered(); let crate_graph = self.db.crate_graph(); let file_id = crate_graph[self.def_map.krate].root_file_id; @@ -410,17 +399,17 @@ impl DefCollector<'_> { } fn resolution_loop(&mut self) { - let _p = tracing::span!(tracing::Level::INFO, "DefCollector::resolution_loop").entered(); + let _p = tracing::info_span!("DefCollector::resolution_loop").entered(); // main name resolution fixed-point loop. let mut i = 0; 'resolve_attr: loop { - let _p = tracing::span!(tracing::Level::INFO, "resolve_macros loop").entered(); + let _p = tracing::info_span!("resolve_macros loop").entered(); 'resolve_macros: loop { self.db.unwind_if_cancelled(); { - let _p = tracing::span!(tracing::Level::INFO, "resolve_imports loop").entered(); + let _p = tracing::info_span!("resolve_imports loop").entered(); 'resolve_imports: loop { if self.resolve_imports() == ReachedFixedPoint::Yes { @@ -446,7 +435,7 @@ impl DefCollector<'_> { } fn collect(&mut self) { - let _p = tracing::span!(tracing::Level::INFO, "DefCollector::collect").entered(); + let _p = tracing::info_span!("DefCollector::collect").entered(); self.resolution_loop(); @@ -794,7 +783,7 @@ impl DefCollector<'_> { } fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport { - let _p = tracing::span!(tracing::Level::INFO, "resolve_import", import_path = %import.path.display(self.db.upcast())) + let _p = tracing::info_span!("resolve_import", import_path = %import.path.display(self.db.upcast())) .entered(); tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.data.edition); match import.source { @@ -856,7 +845,7 @@ impl DefCollector<'_> { } fn record_resolved_import(&mut self, directive: &ImportDirective) { - let _p = tracing::span!(tracing::Level::INFO, "record_resolved_import").entered(); + let _p = tracing::info_span!("record_resolved_import").entered(); let module_id = directive.module_id; let import = &directive.import; @@ -1136,18 +1125,18 @@ impl DefCollector<'_> { MacroSubNs::Attr } }; - let resolver = |path| { + let resolver = |path: &_| { let resolved_res = self.def_map.resolve_path_fp_with_macro( self.db, ResolveMode::Other, directive.module_id, - &path, + path, BuiltinShadowMode::Module, Some(subns), ); resolved_res.resolved_def.take_macros().map(|it| (it, self.db.macro_def(it))) }; - let resolver_def_id = |path| resolver(path).map(|(_, it)| it); + let resolver_def_id = |path: &_| resolver(path).map(|(_, it)| it); match &directive.kind { MacroDirectiveKind::FnLike { ast_id, expand_to, ctxt: call_site } => { @@ -1250,22 +1239,28 @@ impl DefCollector<'_> { } } - let def = match resolver_def_id(path.clone()) { + let def = match resolver_def_id(path) { Some(def) if def.is_attribute() => def, _ => return Resolved::No, }; - let call_id = - attr_macro_as_call_id(self.db, file_ast_id, attr, self.def_map.krate, def); - if let MacroDefId { - kind: - MacroDefKind::BuiltInAttr( - BuiltinAttrExpander::Derive | BuiltinAttrExpander::DeriveConst, - _, - ), - .. - } = def - { + // Skip #[test]/#[bench] expansion, which would merely result in more memory usage + // due to duplicating functions into macro expansions + if matches!( + def.kind, + MacroDefKind::BuiltInAttr(_, expander) + if expander.is_test() || expander.is_bench() + ) { + return recollect_without(self); + } + + let call_id = || { + attr_macro_as_call_id(self.db, file_ast_id, attr, self.def_map.krate, def) + }; + if matches!(def, + MacroDefId { kind: MacroDefKind::BuiltInAttr(_, exp), .. } + if exp.is_derive() + ) { // Resolved to `#[derive]`, we don't actually expand this attribute like // normal (as that would just be an identity expansion with extra output) // Instead we treat derive attributes special and apply them separately. @@ -1290,9 +1285,14 @@ impl DefCollector<'_> { match attr.parse_path_comma_token_tree(self.db.upcast()) { Some(derive_macros) => { + let call_id = call_id(); let mut len = 0; for (idx, (path, call_site)) in derive_macros.enumerate() { - let ast_id = AstIdWithPath::new(file_id, ast_id.value, path); + let ast_id = AstIdWithPath::new( + file_id, + ast_id.value, + Interned::new(path), + ); self.unresolved_macros.push(MacroDirective { module_id: directive.module_id, depth: directive.depth + 1, @@ -1312,13 +1312,6 @@ impl DefCollector<'_> { // This is just a trick to be able to resolve the input to derives // as proper paths in `Semantics`. // Check the comment in [`builtin_attr_macro`]. - let call_id = attr_macro_as_call_id( - self.db, - file_ast_id, - attr, - self.def_map.krate, - def, - ); self.def_map.modules[directive.module_id] .scope .init_derive_attribute(ast_id, attr.id, call_id, len + 1); @@ -1336,17 +1329,8 @@ impl DefCollector<'_> { return recollect_without(self); } - // Skip #[test]/#[bench] expansion, which would merely result in more memory usage - // due to duplicating functions into macro expansions - if matches!( - def.kind, - MacroDefKind::BuiltInAttr(expander, _) - if expander.is_test() || expander.is_bench() - ) { - return recollect_without(self); - } - - if let MacroDefKind::ProcMacro(exp, ..) = def.kind { + let call_id = call_id(); + if let MacroDefKind::ProcMacro(_, exp, _) = def.kind { // If proc attribute macro expansion is disabled, skip expanding it here if !self.db.expand_proc_attr_macros() { self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro( @@ -1430,7 +1414,7 @@ impl DefCollector<'_> { fn finish(mut self) -> DefMap { // Emit diagnostics for all remaining unexpanded macros. - let _p = tracing::span!(tracing::Level::INFO, "DefCollector::finish").entered(); + let _p = tracing::info_span!("DefCollector::finish").entered(); for directive in &self.unresolved_macros { match &directive.kind { @@ -1447,7 +1431,7 @@ impl DefCollector<'_> { self.db, ResolveMode::Other, directive.module_id, - &path, + path, BuiltinShadowMode::Module, Some(MacroSubNs::Bang), ); @@ -1481,7 +1465,7 @@ impl DefCollector<'_> { derive_index: *derive_pos as u32, derive_macro_id: *derive_macro_id, }, - ast_id.path.clone(), + ast_id.path.as_ref().clone(), )); } // These are diagnosed by `reseed_with_unresolved_attribute`, as that function consumes them @@ -2116,7 +2100,7 @@ impl ModCollector<'_, '_> { let ast_id = AstIdWithPath::new( self.file_id(), mod_item.ast_id(self.item_tree), - attr.path.as_ref().clone(), + attr.path.clone(), ); self.def_collector.unresolved_macros.push(MacroDirective { module_id: self.module_id, @@ -2162,19 +2146,7 @@ impl ModCollector<'_, '_> { let name; let name = match attrs.by_key("rustc_builtin_macro").string_value() { Some(it) => { - // FIXME: a hacky way to create a Name from string. - name = tt::Ident { - text: it.into(), - span: Span { - range: syntax::TextRange::empty(syntax::TextSize::new(0)), - anchor: span::SpanAnchor { - file_id: FileId::BOGUS, - ast_id: span::ROOT_ERASED_FILE_AST_ID, - }, - ctx: SyntaxContextId::ROOT, - }, - } - .as_name(); + name = Name::new_text_dont_use(it.into()); &name } None => { @@ -2310,7 +2282,7 @@ impl ModCollector<'_, '_> { &MacroCall { ref path, ast_id, expand_to, ctxt }: &MacroCall, container: ItemContainerId, ) { - let ast_id = AstIdWithPath::new(self.file_id(), ast_id, ModPath::clone(path)); + let ast_id = AstIdWithPath::new(self.file_id(), ast_id, path.clone()); let db = self.def_collector.db; // FIXME: Immediately expanding in "Case 1" is insufficient since "Case 2" may also define @@ -2320,7 +2292,8 @@ impl ModCollector<'_, '_> { // Case 1: try to resolve macro calls with single-segment name and expand macro_rules if let Ok(res) = macro_call_as_call_id_with_eager( db.upcast(), - &ast_id, + ast_id.ast_id, + &ast_id.path, ctxt, expand_to, self.def_collector.def_map.krate, @@ -2347,7 +2320,7 @@ impl ModCollector<'_, '_> { db, ResolveMode::Other, self.module_id, - &path, + path, BuiltinShadowMode::Module, Some(MacroSubNs::Bang), ); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs index d621f3a360a9..e797d19223ed 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs @@ -283,7 +283,7 @@ impl DefMap { // If we have a different `DefMap` from `self` (the original `DefMap` we started // with), resolve the remaining path segments in that `DefMap`. let path = - ModPath::from_segments(PathKind::Super(0), path.segments().iter().cloned()); + ModPath::from_segments(PathKind::SELF, path.segments().iter().cloned()); return def_map.resolve_path_fp_with_macro( db, mode, @@ -333,7 +333,7 @@ impl DefMap { ModuleDefId::ModuleId(module) => { if module.krate != self.krate { let path = ModPath::from_segments( - PathKind::Super(0), + PathKind::SELF, path.segments()[i..].iter().cloned(), ); tracing::debug!("resolving {:?} in other crate", path); @@ -493,7 +493,12 @@ impl DefMap { ) }) }; - let prelude = || self.resolve_in_prelude(db, name); + let prelude = || { + if self.block.is_some() && module == DefMap::ROOT { + return PerNs::none(); + } + self.resolve_in_prelude(db, name) + }; from_legacy_macro .or(from_scope_or_builtin) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs index 6af526141116..2b555b3998a7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs @@ -122,7 +122,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option, mut path: ast::Path) -> Option bool) -> PerNs { - let _p = tracing::span!(tracing::Level::INFO, "PerNs::filter_visibility").entered(); + let _p = tracing::info_span!("PerNs::filter_visibility").entered(); PerNs { types: self.types.filter(|&(_, v, _)| f(v)), values: self.values.filter(|&(_, v, _)| f(v)), @@ -119,7 +119,7 @@ impl PerNs { } pub fn iter_items(self) -> impl Iterator)> { - let _p = tracing::span!(tracing::Level::INFO, "PerNs::iter_items").entered(); + let _p = tracing::info_span!("PerNs::iter_items").entered(); self.types .map(|it| (ItemInNs::Types(it.0), it.2)) .into_iter() diff --git a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs index d3135bba9656..d08e063976a3 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs @@ -57,7 +57,7 @@ pub(crate) fn print_path(db: &dyn DefDatabase, path: &Path, buf: &mut dyn Write) } None => match path.kind() { PathKind::Plain => {} - PathKind::Super(0) => write!(buf, "self")?, + &PathKind::SELF => write!(buf, "self")?, PathKind::Super(n) => { for i in 0..*n { if i == 0 { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs index 1ef8fa772a11..e08718fc8366 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs @@ -27,10 +27,7 @@ pub enum RawVisibility { impl RawVisibility { pub(crate) const fn private() -> RawVisibility { - RawVisibility::Module( - ModPath::from_kind(PathKind::Super(0)), - VisibilityExplicitness::Implicit, - ) + RawVisibility::Module(ModPath::from_kind(PathKind::SELF), VisibilityExplicitness::Implicit) } pub(crate) fn from_ast( @@ -60,7 +57,7 @@ impl RawVisibility { } ast::VisibilityKind::PubCrate => ModPath::from_kind(PathKind::Crate), ast::VisibilityKind::PubSuper => ModPath::from_kind(PathKind::Super(1)), - ast::VisibilityKind::PubSelf => ModPath::from_kind(PathKind::Super(0)), + ast::VisibilityKind::PubSelf => ModPath::from_kind(PathKind::SELF), ast::VisibilityKind::Pub => return RawVisibility::Public, }; RawVisibility::Module(path, VisibilityExplicitness::Explicit) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs index 85ec02ae0731..db0feb055e19 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs @@ -54,7 +54,7 @@ impl RawAttrs { let span = span_map.span_for_range(comment.syntax().text_range()); Attr { id, - input: Some(Interned::new(AttrInput::Literal(tt::Literal { + input: Some(Box::new(AttrInput::Literal(tt::Literal { text: SmolStr::new(format_smolstr!("\"{}\"", Self::escape_chars(doc))), span, }))), @@ -199,7 +199,7 @@ impl AttrId { pub struct Attr { pub id: AttrId, pub path: Interned, - pub input: Option>, + pub input: Option>, pub ctxt: SyntaxContextId, } @@ -234,7 +234,7 @@ impl Attr { })?); let span = span_map.span_for_range(range); let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { - Some(Interned::new(AttrInput::Literal(tt::Literal { + Some(Box::new(AttrInput::Literal(tt::Literal { text: lit.token().text().into(), span, }))) @@ -245,7 +245,7 @@ impl Attr { span, DocCommentDesugarMode::ProcMacro, ); - Some(Interned::new(AttrInput::TokenTree(Box::new(tree)))) + Some(Box::new(AttrInput::TokenTree(Box::new(tree)))) } else { None }; @@ -281,12 +281,12 @@ impl Attr { let input = match input.first() { Some(tt::TokenTree::Subtree(tree)) => { - Some(Interned::new(AttrInput::TokenTree(Box::new(tree.clone())))) + Some(Box::new(AttrInput::TokenTree(Box::new(tree.clone())))) } Some(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '=', .. }))) => { let input = match input.get(1) { Some(tt::TokenTree::Leaf(tt::Leaf::Literal(lit))) => { - Some(Interned::new(AttrInput::Literal(lit.clone()))) + Some(Box::new(AttrInput::Literal(lit.clone()))) } _ => None, }; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs index 9ff29b484d32..2e115f479327 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs @@ -52,8 +52,6 @@ impl BuiltinAttrExpander { register_builtin! { (bench, Bench) => dummy_attr_expand, - (cfg, Cfg) => dummy_attr_expand, - (cfg_attr, CfgAttr) => dummy_attr_expand, (cfg_accessible, CfgAccessible) => dummy_attr_expand, (cfg_eval, CfgEval) => dummy_attr_expand, (derive, Derive) => derive_expand, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs index ba96ab6cc2f0..02fd431e4e7e 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs @@ -67,6 +67,10 @@ impl BuiltinFnLikeExpander { let span = span_with_def_site_ctxt(db, span, id); self.expander()(db, id, tt, span) } + + pub fn is_asm(&self) -> bool { + matches!(self, Self::Asm | Self::GlobalAsm) + } } impl EagerExpander { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs b/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs index 9dd44262ba95..55ae19068f9c 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs @@ -189,8 +189,8 @@ pub(crate) fn process_cfg_attrs( // FIXME: #[cfg_eval] is not implemented. But it is not stable yet let is_derive = match loc.def.kind { MacroDefKind::BuiltInDerive(..) - | MacroDefKind::ProcMacro(_, ProcMacroKind::CustomDerive, _) => true, - MacroDefKind::BuiltInAttr(expander, _) => expander.is_derive(), + | MacroDefKind::ProcMacro(_, _, ProcMacroKind::CustomDerive) => true, + MacroDefKind::BuiltInAttr(_, expander) => expander.is_derive(), _ => false, }; if !is_derive { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs index 12421bbe7026..ad25a1168c4d 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs @@ -146,13 +146,11 @@ pub fn expand_speculative( token_to_map: SyntaxToken, ) -> Option<(SyntaxNode, SyntaxToken)> { let loc = db.lookup_intern_macro_call(actual_macro_call); - - // FIXME: This BOGUS here is dangerous once the proc-macro server can call back into the database! - let span_map = RealSpanMap::absolute(FileId::BOGUS); - let span_map = SpanMapRef::RealSpanMap(&span_map); - let (_, _, span) = db.macro_arg_considering_derives(actual_macro_call, &loc.kind); + let span_map = RealSpanMap::absolute(span.anchor.file_id); + let span_map = SpanMapRef::RealSpanMap(&span_map); + // Build the subtree and token mapping for the speculative args let (mut tt, undo_info) = match loc.kind { MacroCallKind::FnLike { .. } => ( @@ -252,7 +250,7 @@ pub fn expand_speculative( // Otherwise the expand query will fetch the non speculative attribute args and pass those instead. let mut speculative_expansion = match loc.def.kind { - MacroDefKind::ProcMacro(expander, _, ast) => { + MacroDefKind::ProcMacro(ast, expander, _) => { let span = db.proc_macro_span(ast); tt.delimiter = tt::Delimiter::invisible_spanned(span); expander.expand( @@ -266,22 +264,22 @@ pub fn expand_speculative( span_with_mixed_site_ctxt(db, span, actual_macro_call), ) } - MacroDefKind::BuiltInAttr(BuiltinAttrExpander::Derive, _) => { + MacroDefKind::BuiltInAttr(_, it) if it.is_derive() => { pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?, span) } MacroDefKind::Declarative(it) => db .decl_macro_expander(loc.krate, it) .expand_unhygienic(db, tt, loc.def.krate, span, loc.def.edition), - MacroDefKind::BuiltIn(it, _) => { + MacroDefKind::BuiltIn(_, it) => { it.expand(db, actual_macro_call, &tt, span).map_err(Into::into) } - MacroDefKind::BuiltInDerive(it, ..) => { + MacroDefKind::BuiltInDerive(_, it) => { it.expand(db, actual_macro_call, &tt, span).map_err(Into::into) } - MacroDefKind::BuiltInEager(it, _) => { + MacroDefKind::BuiltInEager(_, it) => { it.expand(db, actual_macro_call, &tt, span).map_err(Into::into) } - MacroDefKind::BuiltInAttr(it, _) => it.expand(db, actual_macro_call, &tt, span), + MacroDefKind::BuiltInAttr(_, it) => it.expand(db, actual_macro_call, &tt, span), }; let expand_to = loc.expand_to(); @@ -334,7 +332,7 @@ fn parse_macro_expansion( db: &dyn ExpandDatabase, macro_file: MacroFileId, ) -> ExpandResult<(Parse, Arc)> { - let _p = tracing::span!(tracing::Level::INFO, "parse_macro_expansion").entered(); + let _p = tracing::info_span!("parse_macro_expansion").entered(); let loc = db.lookup_intern_macro_call(macro_file.macro_call_id); let edition = loc.def.edition; let expand_to = loc.expand_to(); @@ -493,7 +491,7 @@ fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult { .map_or_else(|| node.syntax().text_range(), |it| it.syntax().text_range()), ); // If derive attribute we need to censor the derive input - if matches!(loc.def.kind, MacroDefKind::BuiltInAttr(expander, ..) if expander.is_derive()) + if matches!(loc.def.kind, MacroDefKind::BuiltInAttr(_, expander) if expander.is_derive()) && ast::Adt::can_cast(node.syntax().kind()) { let adt = ast::Adt::cast(node.syntax().clone()).unwrap(); @@ -569,11 +567,11 @@ impl TokenExpander { MacroDefKind::Declarative(ast_id) => { TokenExpander::DeclarativeMacro(db.decl_macro_expander(id.krate, ast_id)) } - MacroDefKind::BuiltIn(expander, _) => TokenExpander::BuiltIn(expander), - MacroDefKind::BuiltInAttr(expander, _) => TokenExpander::BuiltInAttr(expander), - MacroDefKind::BuiltInDerive(expander, _) => TokenExpander::BuiltInDerive(expander), - MacroDefKind::BuiltInEager(expander, ..) => TokenExpander::BuiltInEager(expander), - MacroDefKind::ProcMacro(expander, ..) => TokenExpander::ProcMacro(expander), + MacroDefKind::BuiltIn(_, expander) => TokenExpander::BuiltIn(expander), + MacroDefKind::BuiltInAttr(_, expander) => TokenExpander::BuiltInAttr(expander), + MacroDefKind::BuiltInDerive(_, expander) => TokenExpander::BuiltInDerive(expander), + MacroDefKind::BuiltInEager(_, expander) => TokenExpander::BuiltInEager(expander), + MacroDefKind::ProcMacro(_, expander, _) => TokenExpander::ProcMacro(expander), } } } @@ -588,7 +586,7 @@ fn macro_expand( macro_call_id: MacroCallId, loc: MacroCallLoc, ) -> ExpandResult<(CowArc, MatchedArmIndex)> { - let _p = tracing::span!(tracing::Level::INFO, "macro_expand").entered(); + let _p = tracing::info_span!("macro_expand").entered(); let (ExpandResult { value: (tt, matched_arm), err }, span) = match loc.def.kind { MacroDefKind::ProcMacro(..) => { @@ -604,13 +602,13 @@ fn macro_expand( MacroDefKind::Declarative(id) => db .decl_macro_expander(loc.def.krate, id) .expand(db, arg.clone(), macro_call_id, span), - MacroDefKind::BuiltIn(it, _) => { + MacroDefKind::BuiltIn(_, it) => { it.expand(db, macro_call_id, arg, span).map_err(Into::into).zip_val(None) } - MacroDefKind::BuiltInDerive(it, _) => { + MacroDefKind::BuiltInDerive(_, it) => { it.expand(db, macro_call_id, arg, span).map_err(Into::into).zip_val(None) } - MacroDefKind::BuiltInEager(it, _) => { + MacroDefKind::BuiltInEager(_, it) => { // This might look a bit odd, but we do not expand the inputs to eager macros here. // Eager macros inputs are expanded, well, eagerly when we collect the macro calls. // That kind of expansion uses the ast id map of an eager macros input though which goes through @@ -634,12 +632,12 @@ fn macro_expand( } res.zip_val(None) } - MacroDefKind::BuiltInAttr(it, _) => { + MacroDefKind::BuiltInAttr(_, it) => { let mut res = it.expand(db, macro_call_id, arg, span); fixup::reverse_fixups(&mut res.value, &undo_info); res.zip_val(None) } - _ => unreachable!(), + MacroDefKind::ProcMacro(_, _, _) => unreachable!(), }; (ExpandResult { value: res.value, err: res.err }, span) } @@ -678,8 +676,8 @@ fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult (expander, ast), + let (ast, expander) = match loc.def.kind { + MacroDefKind::ProcMacro(ast, expander, _) => (ast, expander), _ => unreachable!(), }; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs index 64e04bc08f52..3e0d2dfa6c17 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs @@ -39,7 +39,7 @@ pub fn expand_eager_macro_input( ast_id: AstId, def: MacroDefId, call_site: SyntaxContextId, - resolver: &dyn Fn(ModPath) -> Option, + resolver: &dyn Fn(&ModPath) -> Option, ) -> ExpandResult> { let expand_to = ExpandTo::from_call_site(macro_call); @@ -138,7 +138,7 @@ fn eager_macro_recur( curr: InFile, krate: CrateId, call_site: SyntaxContextId, - macro_resolver: &dyn Fn(ModPath) -> Option, + macro_resolver: &dyn Fn(&ModPath) -> Option, ) -> ExpandResult> { let original = curr.value.clone_for_update(); @@ -172,7 +172,7 @@ fn eager_macro_recur( let def = match call.path().and_then(|path| { ModPath::from_src(db, path, &mut |range| span_map.span_at(range.start()).ctx) }) { - Some(path) => match macro_resolver(path.clone()) { + Some(path) => match macro_resolver(&path) { Some(def) => def, None => { error = diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs index 1ba85c5c7eac..743fac50f4e1 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs @@ -1,6 +1,4 @@ //! Things to wrap other things in file ids. -use std::iter; - use either::Either; use span::{ AstIdNode, ErasedFileAstId, FileAstId, FileId, FileRange, HirFileId, HirFileIdRepr, @@ -150,27 +148,16 @@ impl InFileWrapper { } } +impl InFileWrapper { + // unfortunately `syntax` collides with the impl above, because `&_` is fundamental + pub fn syntax_ref(&self) -> InFileWrapper { + self.with_value(self.value.syntax()) + } +} + // region:specific impls impl InFile<&SyntaxNode> { - /// Traverse up macro calls and skips the macro invocation node - pub fn ancestors_with_macros( - self, - db: &dyn db::ExpandDatabase, - ) -> impl Iterator> + '_ { - let succ = move |node: &InFile| match node.value.parent() { - Some(parent) => Some(node.with_value(parent)), - None => db - .lookup_intern_macro_call(node.file_id.macro_file()?.macro_call_id) - .to_node_item(db) - .syntax() - .cloned() - .map(|node| node.parent()) - .transpose(), - }; - iter::successors(succ(&self.cloned()), succ) - } - /// Falls back to the macro call range if the node cannot be mapped up fully. /// /// For attributes and derives, this will point back to the attribute only. diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs index 9ec2a83162a6..9fdf4aa4f7cc 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs @@ -4,7 +4,10 @@ use mbe::DocCommentDesugarMode; use rustc_hash::{FxHashMap, FxHashSet}; use smallvec::SmallVec; -use span::{ErasedFileAstId, Span, SpanAnchor, FIXUP_ERASED_FILE_AST_ID_MARKER}; +use span::{ + ErasedFileAstId, Span, SpanAnchor, SyntaxContextId, FIXUP_ERASED_FILE_AST_ID_MARKER, + ROOT_ERASED_FILE_AST_ID, +}; use stdx::never; use syntax::{ ast::{self, AstNode, HasLoopBody}, @@ -88,7 +91,6 @@ pub(crate) fn fixup_syntax( preorder.skip_subtree(); continue; } - // In some other situations, we can fix things by just appending some tokens. match_ast! { match node { @@ -273,6 +275,62 @@ pub(crate) fn fixup_syntax( ]); } }, + ast::RecordExprField(it) => { + if let Some(colon) = it.colon_token() { + if it.name_ref().is_some() && it.expr().is_none() { + append.insert(colon.into(), vec![ + Leaf::Ident(Ident { + text: "__ra_fixup".into(), + span: fake_span(node_range) + }) + ]); + } + } + }, + ast::Path(it) => { + if let Some(colon) = it.coloncolon_token() { + if it.segment().is_none() { + append.insert(colon.into(), vec![ + Leaf::Ident(Ident { + text: "__ra_fixup".into(), + span: fake_span(node_range) + }) + ]); + } + } + }, + ast::ArgList(it) => { + if it.r_paren_token().is_none() { + append.insert(node.into(), vec![ + Leaf::Punct(Punct { + span: fake_span(node_range), + char: ')', + spacing: Spacing::Alone + }) + ]); + } + }, + ast::ArgList(it) => { + if it.r_paren_token().is_none() { + append.insert(node.into(), vec![ + Leaf::Punct(Punct { + span: fake_span(node_range), + char: ')', + spacing: Spacing::Alone + }) + ]); + } + }, + ast::ClosureExpr(it) => { + if it.body().is_none() { + append.insert(node.into(), vec![ + Leaf::Ident(Ident { + text: "__ra_fixup".into(), + span: fake_span(node_range) + }) + ]); + } + }, _ => (), } } @@ -307,8 +365,13 @@ pub(crate) fn reverse_fixups(tt: &mut Subtree, undo_info: &SyntaxFixupUndoInfo) tt.delimiter.close.anchor.ast_id == FIXUP_DUMMY_AST_ID || tt.delimiter.open.anchor.ast_id == FIXUP_DUMMY_AST_ID ) { - tt.delimiter.close = Span::DUMMY; - tt.delimiter.open = Span::DUMMY; + let span = |file_id| Span { + range: TextRange::empty(TextSize::new(0)), + anchor: SpanAnchor { file_id, ast_id: ROOT_ERASED_FILE_AST_ID }, + ctx: SyntaxContextId::ROOT, + }; + tt.delimiter.open = span(tt.delimiter.open.anchor.file_id); + tt.delimiter.close = span(tt.delimiter.close.anchor.file_id); } reverse_fixups_(tt, undo_info); } @@ -751,4 +814,84 @@ fn foo () {loop { }} "#]], ) } + + #[test] + fn fixup_path() { + check( + r#" +fn foo() { + path:: +} +"#, + expect![[r#" +fn foo () {path :: __ra_fixup} +"#]], + ) + } + + #[test] + fn fixup_record_ctor_field() { + check( + r#" +fn foo() { + R { f: } +} +"#, + expect![[r#" +fn foo () {R {f : __ra_fixup}} +"#]], + ) + } + + #[test] + fn no_fixup_record_ctor_field() { + check( + r#" +fn foo() { + R { f: a } +} +"#, + expect![[r#" +fn foo () {R {f : a}} +"#]], + ) + } + + #[test] + fn fixup_arg_list() { + check( + r#" +fn foo() { + foo(a +} +"#, + expect![[r#" +fn foo () { foo ( a ) } +"#]], + ); + check( + r#" +fn foo() { + bar.foo(a +} +"#, + expect![[r#" +fn foo () { bar . foo ( a ) } +"#]], + ); + } + + #[test] + fn fixup_closure() { + check( + r#" +fn foo() { + || +} +"#, + expect![[r#" +fn foo () {|| __ra_fixup} +"#]], + ); + } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs index 097e760c70ab..cc02332207d6 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs @@ -4,7 +4,7 @@ //! Expansion, and Definition Contexts,” *Journal of Functional Programming* 22, no. 2 //! (March 1, 2012): 181–216, . //! -//! Also see https://rustc-dev-guide.rust-lang.org/macro-expansion.html#hygiene-and-hierarchies +//! Also see //! //! # The Expansion Order Hierarchy //! diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs similarity index 99% rename from src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs rename to src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs index f4564c94bb59..35fd85bf4518 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs @@ -36,11 +36,6 @@ pub fn find_builtin_attr_idx(name: &str) -> Option { .copied() } -// impl AttributeTemplate { -// const DEFAULT: AttributeTemplate = -// AttributeTemplate { word: false, list: None, name_value_str: None }; -// } - /// A convenience macro for constructing attribute templates. /// E.g., `template!(Word, List: "description")` means that the attribute /// supports forms `#[attr]` and `#[attr(description)]`. @@ -628,6 +623,10 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_safe_intrinsic, Normal, template!(Word), WarnFollowing, "the `#[rustc_safe_intrinsic]` attribute is used internally to mark intrinsics as safe" ), + rustc_attr!( + rustc_deprecated_safe_2024, Normal, template!(Word), WarnFollowing, + "the `#[rustc_safe_intrinsic]` marks functions as unsafe in Rust 2024", + ), // ========================================================================== // Internal attributes, Testing: diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index 83e92565f4d8..a7150cf30874 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -16,6 +16,7 @@ pub mod declarative; pub mod eager; pub mod files; pub mod hygiene; +pub mod inert_attr_macro; pub mod mod_path; pub mod name; pub mod proc_macro; @@ -30,7 +31,7 @@ use triomphe::Arc; use std::{fmt, hash::Hash}; -use base_db::{salsa::impl_intern_value_trivial, CrateId, FileId}; +use base_db::{salsa::InternValueTrivial, CrateId, FileId}; use either::Either; use span::{ Edition, ErasedFileAstId, FileAstId, FileRange, HirFileIdRepr, Span, SpanAnchor, @@ -46,7 +47,7 @@ use crate::{ builtin_attr_macro::BuiltinAttrExpander, builtin_derive_macro::BuiltinDeriveExpander, builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander}, - db::{ExpandDatabase, TokenExpander}, + db::ExpandDatabase, mod_path::ModPath, proc_macro::{CustomProcMacroExpander, ProcMacroKind}, span_map::{ExpansionSpanMap, SpanMap}, @@ -172,7 +173,7 @@ pub struct MacroCallLoc { pub kind: MacroCallKind, pub ctxt: SyntaxContextId, } -impl_intern_value_trivial!(MacroCallLoc); +impl InternValueTrivial for MacroCallLoc {} #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct MacroDefId { @@ -186,11 +187,11 @@ pub struct MacroDefId { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum MacroDefKind { Declarative(AstId), - BuiltIn(BuiltinFnLikeExpander, AstId), - BuiltInAttr(BuiltinAttrExpander, AstId), - BuiltInDerive(BuiltinDeriveExpander, AstId), - BuiltInEager(EagerExpander, AstId), - ProcMacro(CustomProcMacroExpander, ProcMacroKind, AstId), + BuiltIn(AstId, BuiltinFnLikeExpander), + BuiltInAttr(AstId, BuiltinAttrExpander), + BuiltInDerive(AstId, BuiltinDeriveExpander), + BuiltInEager(AstId, EagerExpander), + ProcMacro(AstId, CustomProcMacroExpander, ProcMacroKind), } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -252,9 +253,6 @@ pub trait HirFileIdExt { /// If this is a macro call, returns the syntax node of the very first macro call this file resides in. fn original_call_node(self, db: &dyn ExpandDatabase) -> Option>; - /// Return expansion information if it is a macro-expansion file - fn expansion_info(self, db: &dyn ExpandDatabase) -> Option; - fn as_builtin_derive_attr_node(&self, db: &dyn ExpandDatabase) -> Option>; } @@ -308,11 +306,6 @@ impl HirFileIdExt for HirFileId { } } - /// Return expansion information if it is a macro-expansion file - fn expansion_info(self, db: &dyn ExpandDatabase) -> Option { - Some(ExpansionInfo::new(db, self.macro_file()?)) - } - fn as_builtin_derive_attr_node(&self, db: &dyn ExpandDatabase) -> Option> { let macro_file = self.macro_file()?; let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); @@ -379,7 +372,7 @@ impl MacroFileIdExt for MacroFileId { fn is_custom_derive(&self, db: &dyn ExpandDatabase) -> bool { matches!( db.lookup_intern_macro_call(self.macro_call_id).def.kind, - MacroDefKind::ProcMacro(_, ProcMacroKind::CustomDerive, _) + MacroDefKind::ProcMacro(_, _, ProcMacroKind::CustomDerive) ) } @@ -416,8 +409,10 @@ impl MacroFileIdExt for MacroFileId { } fn is_attr_macro(&self, db: &dyn ExpandDatabase) -> bool { - let loc = db.lookup_intern_macro_call(self.macro_call_id); - matches!(loc.kind, MacroCallKind::Attr { .. }) + matches!( + db.lookup_intern_macro_call(self.macro_call_id).def.kind, + MacroDefKind::BuiltInAttr(..) | MacroDefKind::ProcMacro(_, _, ProcMacroKind::Attr) + ) } fn is_derive_attr_pseudo_expansion(&self, db: &dyn ExpandDatabase) -> bool { @@ -440,13 +435,13 @@ impl MacroDefId { pub fn definition_range(&self, db: &dyn ExpandDatabase) -> InFile { match self.kind { MacroDefKind::Declarative(id) - | MacroDefKind::BuiltIn(_, id) - | MacroDefKind::BuiltInAttr(_, id) - | MacroDefKind::BuiltInDerive(_, id) - | MacroDefKind::BuiltInEager(_, id) => { + | MacroDefKind::BuiltIn(id, _) + | MacroDefKind::BuiltInAttr(id, _) + | MacroDefKind::BuiltInDerive(id, _) + | MacroDefKind::BuiltInEager(id, _) => { id.with_value(db.ast_id_map(id.file_id).get(id.value).text_range()) } - MacroDefKind::ProcMacro(_, _, id) => { + MacroDefKind::ProcMacro(id, _, _) => { id.with_value(db.ast_id_map(id.file_id).get(id.value).text_range()) } } @@ -454,12 +449,12 @@ impl MacroDefId { pub fn ast_id(&self) -> Either, AstId> { match self.kind { - MacroDefKind::ProcMacro(.., id) => Either::Right(id), + MacroDefKind::ProcMacro(id, ..) => Either::Right(id), MacroDefKind::Declarative(id) - | MacroDefKind::BuiltIn(_, id) - | MacroDefKind::BuiltInAttr(_, id) - | MacroDefKind::BuiltInDerive(_, id) - | MacroDefKind::BuiltInEager(_, id) => Either::Left(id), + | MacroDefKind::BuiltIn(id, _) + | MacroDefKind::BuiltInAttr(id, _) + | MacroDefKind::BuiltInDerive(id, _) + | MacroDefKind::BuiltInEager(id, _) => Either::Left(id), } } @@ -470,7 +465,7 @@ impl MacroDefId { pub fn is_attribute(&self) -> bool { matches!( self.kind, - MacroDefKind::BuiltInAttr(..) | MacroDefKind::ProcMacro(_, ProcMacroKind::Attr, _) + MacroDefKind::BuiltInAttr(..) | MacroDefKind::ProcMacro(_, _, ProcMacroKind::Attr) ) } @@ -478,7 +473,7 @@ impl MacroDefId { matches!( self.kind, MacroDefKind::BuiltInDerive(..) - | MacroDefKind::ProcMacro(_, ProcMacroKind::CustomDerive, _) + | MacroDefKind::ProcMacro(_, _, ProcMacroKind::CustomDerive) ) } @@ -486,26 +481,26 @@ impl MacroDefId { matches!( self.kind, MacroDefKind::BuiltIn(..) - | MacroDefKind::ProcMacro(_, ProcMacroKind::Bang, _) + | MacroDefKind::ProcMacro(_, _, ProcMacroKind::Bang) | MacroDefKind::BuiltInEager(..) | MacroDefKind::Declarative(..) ) } pub fn is_attribute_derive(&self) -> bool { - matches!(self.kind, MacroDefKind::BuiltInAttr(expander, ..) if expander.is_derive()) + matches!(self.kind, MacroDefKind::BuiltInAttr(_, expander) if expander.is_derive()) } pub fn is_include(&self) -> bool { - matches!(self.kind, MacroDefKind::BuiltInEager(expander, ..) if expander.is_include()) + matches!(self.kind, MacroDefKind::BuiltInEager(_, expander) if expander.is_include()) } pub fn is_include_like(&self) -> bool { - matches!(self.kind, MacroDefKind::BuiltInEager(expander, ..) if expander.is_include_like()) + matches!(self.kind, MacroDefKind::BuiltInEager(_, expander) if expander.is_include_like()) } pub fn is_env_or_option_env(&self) -> bool { - matches!(self.kind, MacroDefKind::BuiltInEager(expander, ..) if expander.is_env_or_option_env()) + matches!(self.kind, MacroDefKind::BuiltInEager(_, expander) if expander.is_env_or_option_env()) } } @@ -702,16 +697,12 @@ impl MacroCallKind { // simpler function calls if the map is only used once #[derive(Clone, Debug, PartialEq, Eq)] pub struct ExpansionInfo { - pub expanded: InMacroFile, + expanded: InMacroFile, /// The argument TokenTree or item for attributes arg: InFile>, - /// The `macro_rules!` or attribute input. - attr_input_or_mac_def: Option>, - - macro_def: TokenExpander, - macro_arg: Arc, - pub exp_map: Arc, + exp_map: Arc, arg_map: SpanMap, + loc: MacroCallLoc, } impl ExpansionInfo { @@ -719,14 +710,21 @@ impl ExpansionInfo { self.expanded.clone() } - pub fn call_node(&self) -> Option> { - Some(self.arg.with_value(self.arg.value.as_ref()?.parent()?)) + pub fn arg(&self) -> InFile> { + self.arg.as_ref().map(|it| it.as_ref()) } pub fn call_file(&self) -> HirFileId { self.arg.file_id } + pub fn is_attr(&self) -> bool { + matches!( + self.loc.def.kind, + MacroDefKind::BuiltInAttr(..) | MacroDefKind::ProcMacro(_, _, ProcMacroKind::Attr) + ) + } + /// Maps the passed in file range down into a macro expansion if it is the input to a macro call. /// /// Note this does a linear search through the entire backing vector of the spanmap. @@ -811,49 +809,16 @@ impl ExpansionInfo { } pub fn new(db: &dyn ExpandDatabase, macro_file: MacroFileId) -> ExpansionInfo { - let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); + let _p = tracing::info_span!("ExpansionInfo::new").entered(); + let loc = db.lookup_intern_macro_call(macro_file.macro_call_id); let arg_tt = loc.kind.arg(db); let arg_map = db.span_map(arg_tt.file_id); - let macro_def = db.macro_expander(loc.def); let (parse, exp_map) = db.parse_macro_expansion(macro_file).value; let expanded = InMacroFile { file_id: macro_file, value: parse.syntax_node() }; - let (macro_arg, _, _) = - db.macro_arg_considering_derives(macro_file.macro_call_id, &loc.kind); - - let def = loc.def.ast_id().left().and_then(|id| { - let def_tt = match id.to_node(db) { - ast::Macro::MacroRules(mac) => mac.token_tree()?, - ast::Macro::MacroDef(_) if matches!(macro_def, TokenExpander::BuiltInAttr(_)) => { - return None - } - ast::Macro::MacroDef(mac) => mac.body()?, - }; - Some(InFile::new(id.file_id, def_tt)) - }); - let attr_input_or_mac_def = def.or_else(|| match loc.kind { - MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => { - // FIXME: handle `cfg_attr` - let tt = collect_attrs(&ast_id.to_node(db)) - .nth(invoc_attr_index.ast_index()) - .and_then(|x| Either::left(x.1))? - .token_tree()?; - Some(InFile::new(ast_id.file_id, tt)) - } - _ => None, - }); - - ExpansionInfo { - expanded, - arg: arg_tt, - attr_input_or_mac_def, - macro_arg, - macro_def, - exp_map, - arg_map, - } + ExpansionInfo { expanded, loc, arg: arg_tt, exp_map, arg_map } } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs index 46f8c2b9d8c4..12fdf88a2a87 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs @@ -44,6 +44,10 @@ pub enum PathKind { DollarCrate(CrateId), } +impl PathKind { + pub const SELF: PathKind = PathKind::Super(0); +} + impl ModPath { pub fn from_src( db: &dyn ExpandDatabase, @@ -96,7 +100,7 @@ impl ModPath { pub fn textual_len(&self) -> usize { let base = match self.kind { PathKind::Plain => 0, - PathKind::Super(0) => "self".len(), + PathKind::SELF => "self".len(), PathKind::Super(i) => "super".len() * i as usize, PathKind::Crate => "crate".len(), PathKind::Abs => 0, @@ -113,7 +117,7 @@ impl ModPath { } pub fn is_self(&self) -> bool { - self.kind == PathKind::Super(0) && self.segments.is_empty() + self.kind == PathKind::SELF && self.segments.is_empty() } #[allow(non_snake_case)] @@ -193,7 +197,7 @@ fn display_fmt_path( }; match path.kind { PathKind::Plain => {} - PathKind::Super(0) => add_segment("self")?, + PathKind::SELF => add_segment("self")?, PathKind::Super(n) => { for _ in 0..n { add_segment("super")?; @@ -316,7 +320,7 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree]) -> Option { resolve_crate_root(db, span.ctx).map(PathKind::DollarCrate).unwrap_or(PathKind::Crate) } - tt::Leaf::Ident(tt::Ident { text, .. }) if text == "self" => PathKind::Super(0), + tt::Leaf::Ident(tt::Ident { text, .. }) if text == "self" => PathKind::SELF, tt::Leaf::Ident(tt::Ident { text, .. }) if text == "super" => { let mut deg = 1; while let Some(tt::Leaf::Ident(tt::Ident { text, .. })) = leaves.next() { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs b/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs index a31a111c9117..8f1e32321e14 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs @@ -231,7 +231,7 @@ mod tests { const DUMMY: tt::Span = tt::Span { range: TextRange::empty(TextSize::new(0)), - anchor: SpanAnchor { file_id: FileId::BOGUS, ast_id: ROOT_ERASED_FILE_AST_ID }, + anchor: SpanAnchor { file_id: FileId::from_raw(0xe4e4e), ast_id: ROOT_ERASED_FILE_AST_ID }, ctx: SyntaxContextId::ROOT, }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs index e2446c34254a..b706cef0b3a2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs @@ -143,7 +143,7 @@ pub(crate) fn deref_by_trait( table @ &mut InferenceTable { db, .. }: &mut InferenceTable<'_>, ty: Ty, ) -> Option { - let _p = tracing::span!(tracing::Level::INFO, "deref_by_trait").entered(); + let _p = tracing::info_span!("deref_by_trait").entered(); if table.resolve_ty_shallow(&ty).inference_var(Interner).is_some() { // don't try to deref unknown variables return None; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs index 41acd3555eb9..52411f94ad03 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs @@ -14,10 +14,10 @@ use hir_def::{ use smallvec::SmallVec; use crate::{ - consteval::unknown_const_as_generic, db::HirDatabase, error_lifetime, - infer::unify::InferenceTable, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, - Binders, BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy, - Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind, + consteval::unknown_const_as_generic, db::HirDatabase, error_lifetime, generics::generics, + infer::unify::InferenceTable, primitive, to_assoc_type_id, to_chalk_trait_id, Binders, + BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution, + TraitRef, Ty, TyDefId, TyExt, TyKind, }; #[derive(Debug, Clone, PartialEq, Eq)] @@ -246,6 +246,7 @@ impl TyBuilder<()> { /// - yield type of coroutine ([`Coroutine::Yield`](std::ops::Coroutine::Yield)) /// - return type of coroutine ([`Coroutine::Return`](std::ops::Coroutine::Return)) /// - generic parameters in scope on `parent` + /// /// in this order. /// /// This method prepopulates the builder with placeholder substitution of `parent`, so you diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index 84ac8740ecd5..debae1fe1235 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -20,13 +20,14 @@ use hir_expand::name::name; use crate::{ db::{HirDatabase, InternedCoroutine}, display::HirDisplay, - from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, make_binders, - make_single_type_binders, + from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, + generics::generics, + make_binders, make_single_type_binders, mapping::{from_chalk, ToChalk, TypeAliasAsValue}, method_resolution::{TraitImpls, TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS}, to_assoc_type_id, to_chalk_trait_id, traits::ChalkContext, - utils::{generics, ClosureSubst}, + utils::ClosureSubst, wrap_empty_binders, AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, Interner, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, WhereClause, @@ -603,7 +604,6 @@ pub(crate) fn associated_ty_data_query( // Lower bounds -- we could/should maybe move this to a separate query in `lower` let type_alias_data = db.type_alias_data(type_alias); let generic_params = generics(db.upcast(), type_alias.into()); - // let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST); let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast()); let ctx = crate::TyLoweringContext::new(db, &resolver, type_alias.into()) .with_type_param_mode(crate::lower::ParamLoweringMode::Variable); @@ -806,7 +806,7 @@ pub(crate) fn impl_datum_query( krate: CrateId, impl_id: ImplId, ) -> Arc { - let _p = tracing::span!(tracing::Level::INFO, "impl_datum_query").entered(); + let _p = tracing::info_span!("impl_datum_query").entered(); debug!("impl_datum {:?}", impl_id); let impl_: hir_def::ImplId = from_chalk(db, impl_id); impl_def_datum(db, krate, impl_id, impl_) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs index d99ef6679e51..4279c756519c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs @@ -12,12 +12,10 @@ use hir_def::{ }; use crate::{ - db::HirDatabase, - from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx, - to_chalk_trait_id, - utils::{generics, ClosureSubst}, - AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, - ClosureId, DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy, + db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, + from_placeholder_idx, generics::generics, to_chalk_trait_id, utils::ClosureSubst, AdtId, + AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, ClosureId, + DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyKind, TypeFlags, WhereClause, }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs index f09277a92e66..8b6cde975f63 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -15,10 +15,9 @@ use stdx::never; use triomphe::Arc; use crate::{ - db::HirDatabase, infer::InferenceContext, lower::ParamLoweringMode, - mir::monomorphize_mir_body_bad, to_placeholder_idx, utils::Generics, Const, ConstData, - ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution, TraitEnvironment, Ty, - TyBuilder, + db::HirDatabase, generics::Generics, infer::InferenceContext, lower::ParamLoweringMode, + mir::monomorphize_mir_body_bad, to_placeholder_idx, Const, ConstData, ConstScalar, ConstValue, + GenericArg, Interner, MemoryMap, Substitution, TraitEnvironment, Ty, TyBuilder, }; use super::mir::{interpret_mir, lower_to_mir, pad16, MirEvalError, MirLowerError}; @@ -72,12 +71,12 @@ impl From for ConstEvalError { } } -pub(crate) fn path_to_const( +pub(crate) fn path_to_const<'g>( db: &dyn HirDatabase, resolver: &Resolver, path: &Path, mode: ParamLoweringMode, - args: impl FnOnce() -> Option, + args: impl FnOnce() -> Option<&'g Generics>, debruijn: DebruijnIndex, expected_ty: Ty, ) -> Option { @@ -90,7 +89,7 @@ pub(crate) fn path_to_const( } ParamLoweringMode::Variable => { let args = args(); - match args.as_ref().and_then(|args| args.type_or_const_param_idx(p.into())) { + match args.and_then(|args| args.type_or_const_param_idx(p.into())) { Some(it) => ConstValue::BoundVar(BoundVar::new(debruijn, it)), None => { never!( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs index d1ffd5046c3f..1b4584a18d76 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs @@ -73,7 +73,7 @@ fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8], &MemoryMap)) { Ok(t) => t, Err(e) => { let err = pretty_print_err(e, db); - panic!("Error in evaluating goal: {}", err); + panic!("Error in evaluating goal: {err}"); } }; match &r.data(Interner).value { @@ -81,7 +81,7 @@ fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8], &MemoryMap)) { ConstScalar::Bytes(b, mm) => { check(b, mm); } - x => panic!("Expected number but found {:?}", x), + x => panic!("Expected number but found {x:?}"), }, _ => panic!("result of const eval wasn't a concrete const"), } @@ -89,7 +89,7 @@ fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8], &MemoryMap)) { fn pretty_print_err(e: ConstEvalError, db: TestDB) -> String { let mut err = String::new(); - let span_formatter = |file, range| format!("{:?} {:?}", file, range); + let span_formatter = |file, range| format!("{file:?} {range:?}"); match e { ConstEvalError::MirLowerError(e) => e.pretty_print(&mut err, &db, span_formatter), ConstEvalError::MirEvalError(e) => e.pretty_print(&mut err, &db, span_formatter), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 90bf46b5056c..e951048021de 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -5,7 +5,7 @@ use std::sync; use base_db::{ impl_intern_key, - salsa::{self, impl_intern_value_trivial}, + salsa::{self, InternValueTrivial}, CrateId, Upcast, }; use hir_def::{ @@ -21,11 +21,12 @@ use crate::{ chalk_db, consteval::ConstEvalError, layout::{Layout, LayoutError}, + lower::{GenericDefaults, GenericPredicates}, method_resolution::{InherentImpls, TraitImpls, TyFingerprint}, mir::{BorrowckResult, MirBody, MirLowerError}, - Binders, CallableDefId, ClosureId, Const, FnDefId, GenericArg, ImplTraitId, ImplTraits, - InferenceResult, Interner, PolyFnSig, QuantifiedWhereClause, Substitution, TraitEnvironment, - TraitRef, Ty, TyDefId, ValueTyDefId, + Binders, CallableDefId, ClosureId, Const, FnDefId, ImplTraitId, ImplTraits, InferenceResult, + Interner, PolyFnSig, QuantifiedWhereClause, Substitution, TraitEnvironment, TraitRef, Ty, + TyDefId, ValueTyDefId, }; use hir_expand::name::Name; @@ -147,7 +148,7 @@ pub trait HirDatabase: DefDatabase + Upcast { ) -> Arc<[Binders]>; #[salsa::invoke(crate::lower::generic_predicates_query)] - fn generic_predicates(&self, def: GenericDefId) -> Arc<[Binders]>; + fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates; #[salsa::invoke(crate::lower::trait_environment_for_body_query)] #[salsa::transparent] @@ -158,7 +159,7 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::invoke(crate::lower::generic_defaults_query)] #[salsa::cycle(crate::lower::generic_defaults_recover)] - fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders]>; + fn generic_defaults(&self, def: GenericDefId) -> GenericDefaults; #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)] fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc; @@ -298,7 +299,8 @@ impl_intern_key!(InternedClosureId); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct InternedClosure(pub DefWithBodyId, pub ExprId); -impl_intern_value_trivial!(InternedClosure); + +impl InternValueTrivial for InternedClosure {} #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct InternedCoroutineId(salsa::InternId); @@ -306,7 +308,7 @@ impl_intern_key!(InternedCoroutineId); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct InternedCoroutine(pub DefWithBodyId, pub ExprId); -impl_intern_value_trivial!(InternedCoroutine); +impl InternValueTrivial for InternedCoroutine {} /// This exists just for Chalk, because Chalk just has a single `FnDefId` where /// we have different IDs for struct and enum variant constructors. diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs index ecbb1d4c60e5..15ecf9aafcfc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs @@ -43,7 +43,7 @@ mod allow { } pub fn incorrect_case(db: &dyn HirDatabase, owner: ModuleDefId) -> Vec { - let _p = tracing::span!(tracing::Level::INFO, "incorrect_case").entered(); + let _p = tracing::info_span!("incorrect_case").entered(); let mut validator = DeclValidator::new(db); validator.validate_item(owner); validator.sink diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index a5a42c52af04..ce3fa53f7ad6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -65,8 +65,7 @@ impl BodyValidationDiagnostic { owner: DefWithBodyId, validate_lints: bool, ) -> Vec { - let _p = - tracing::span!(tracing::Level::INFO, "BodyValidationDiagnostic::collect").entered(); + let _p = tracing::info_span!("BodyValidationDiagnostic::collect").entered(); let infer = db.infer(owner); let body = db.body(owner); let mut validator = diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs index 081b4d83a86f..22aa5c69bb03 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -13,7 +13,7 @@ use crate::{ }; pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec { - let _p = tracing::span!(tracing::Level::INFO, "missing_unsafe").entered(); + let _p = tracing::info_span!("missing_unsafe").entered(); let mut res = Vec::new(); let is_unsafe = match def { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 241690d00896..66b5398b88eb 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -4,7 +4,7 @@ use std::{ fmt::{self, Debug}, - mem::size_of, + mem::{self, size_of}, }; use base_db::CrateId; @@ -36,12 +36,13 @@ use crate::{ consteval::try_const_usize, db::{HirDatabase, InternedClosure}, from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, + generics::generics, layout::Layout, lt_from_placeholder_idx, mapping::from_chalk, mir::pad16, primitive, to_assoc_type_id, - utils::{self, detect_variant_from_bytes, generics, ClosureSubst}, + utils::{self, detect_variant_from_bytes, ClosureSubst}, AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, ConcreteConst, Const, ConstScalar, ConstValue, DomainGoal, FnAbi, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, MemoryMap, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt, @@ -74,6 +75,8 @@ pub struct HirFormatter<'a> { /// When rendering something that has a concept of "children" (like fields in a struct), this limits /// how many should be rendered. pub entity_limit: Option, + /// When rendering functions, whether to show the constraint from the container + show_container_bounds: bool, omit_verbose_types: bool, closure_style: ClosureStyle, display_target: DisplayTarget, @@ -101,6 +104,7 @@ pub trait HirDisplay { omit_verbose_types: bool, display_target: DisplayTarget, closure_style: ClosureStyle, + show_container_bounds: bool, ) -> HirDisplayWrapper<'a, Self> where Self: Sized, @@ -117,6 +121,7 @@ pub trait HirDisplay { omit_verbose_types, display_target, closure_style, + show_container_bounds, } } @@ -134,6 +139,7 @@ pub trait HirDisplay { omit_verbose_types: false, closure_style: ClosureStyle::ImplFn, display_target: DisplayTarget::Diagnostics, + show_container_bounds: false, } } @@ -155,6 +161,7 @@ pub trait HirDisplay { omit_verbose_types: true, closure_style: ClosureStyle::ImplFn, display_target: DisplayTarget::Diagnostics, + show_container_bounds: false, } } @@ -176,6 +183,7 @@ pub trait HirDisplay { omit_verbose_types: true, closure_style: ClosureStyle::ImplFn, display_target: DisplayTarget::Diagnostics, + show_container_bounds: false, } } @@ -198,6 +206,7 @@ pub trait HirDisplay { omit_verbose_types: false, closure_style: ClosureStyle::ImplFn, display_target: DisplayTarget::SourceCode { module_id, allow_opaque }, + show_container_bounds: false, }) { Ok(()) => {} Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"), @@ -219,6 +228,29 @@ pub trait HirDisplay { omit_verbose_types: false, closure_style: ClosureStyle::ImplFn, display_target: DisplayTarget::Test, + show_container_bounds: false, + } + } + + /// Returns a String representation of `self` that shows the constraint from + /// the container for functions + fn display_with_container_bounds<'a>( + &'a self, + db: &'a dyn HirDatabase, + show_container_bounds: bool, + ) -> HirDisplayWrapper<'a, Self> + where + Self: Sized, + { + HirDisplayWrapper { + db, + t: self, + max_size: None, + limited_size: None, + omit_verbose_types: false, + closure_style: ClosureStyle::ImplFn, + display_target: DisplayTarget::Diagnostics, + show_container_bounds, } } } @@ -277,6 +309,10 @@ impl HirFormatter<'_> { pub fn omit_verbose_types(&self) -> bool { self.omit_verbose_types } + + pub fn show_container_bounds(&self) -> bool { + self.show_container_bounds + } } #[derive(Clone, Copy)] @@ -336,6 +372,7 @@ pub struct HirDisplayWrapper<'a, T> { omit_verbose_types: bool, closure_style: ClosureStyle, display_target: DisplayTarget, + show_container_bounds: bool, } #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -365,6 +402,7 @@ impl HirDisplayWrapper<'_, T> { omit_verbose_types: self.omit_verbose_types, display_target: self.display_target, closure_style: self.closure_style, + show_container_bounds: self.show_container_bounds, }) } @@ -423,7 +461,7 @@ impl HirDisplay for ProjectionTy { let proj_params_count = self.substitution.len(Interner) - trait_ref.substitution.len(Interner); let proj_params = &self.substitution.as_slice(Interner)[..proj_params_count]; - hir_fmt_generics(f, proj_params, None) + hir_fmt_generics(f, proj_params, None, None) } } @@ -456,7 +494,7 @@ impl HirDisplay for Const { ConstValue::Placeholder(idx) => { let id = from_placeholder_idx(f.db, *idx); let generics = generics(f.db.upcast(), id.parent); - let param_data = &generics.params[id.local_id]; + let param_data = &generics[id.local_id]; write!(f, "{}", param_data.name().unwrap().display(f.db.upcast()))?; Ok(()) } @@ -468,6 +506,7 @@ impl HirDisplay for Const { f, parameters.as_slice(Interner), c.generic_def(f.db.upcast()), + None, )?; Ok(()) } @@ -670,7 +709,7 @@ fn render_const_scalar( TyKind::FnDef(..) => ty.hir_fmt(f), TyKind::Function(_) | TyKind::Raw(_, _) => { let it = u128::from_le_bytes(pad16(b, false)); - write!(f, "{:#X} as ", it)?; + write!(f, "{it:#X} as ")?; ty.hir_fmt(f) } TyKind::Array(ty, len) => { @@ -950,7 +989,7 @@ impl HirDisplay for Ty { if parameters.len(Interner) > 0 { let generics = generics(db.upcast(), def.into()); - let (parent_len, self_, type_, const_, impl_, lifetime) = + let (parent_len, self_param, type_, const_, impl_, lifetime) = generics.provenance_split(); let parameters = parameters.as_slice(Interner); // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self? @@ -958,7 +997,7 @@ impl HirDisplay for Ty { // `parameters` are in the order of fn's params (including impl traits), fn's lifetimes // parent's params (those from enclosing impl or trait, if any). let (fn_params, other) = - parameters.split_at(self_ + type_ + const_ + lifetime); + parameters.split_at(self_param as usize + type_ + const_ + lifetime); let (_impl, parent_params) = other.split_at(impl_); debug_assert_eq!(parent_params.len(), parent_len); @@ -967,11 +1006,11 @@ impl HirDisplay for Ty { let fn_params = generic_args_sans_defaults(f, Some(def.into()), fn_params); write!(f, "<")?; - hir_fmt_generic_arguments(f, parent_params)?; + hir_fmt_generic_arguments(f, parent_params, None)?; if !parent_params.is_empty() && !fn_params.is_empty() { write!(f, ", ")?; } - hir_fmt_generic_arguments(f, fn_params)?; + hir_fmt_generic_arguments(f, fn_params, None)?; write!(f, ">")?; } } @@ -1016,7 +1055,7 @@ impl HirDisplay for Ty { let generic_def = self.as_generic_def(db); - hir_fmt_generics(f, parameters.as_slice(Interner), generic_def)?; + hir_fmt_generics(f, parameters.as_slice(Interner), generic_def, None)?; } TyKind::AssociatedType(assoc_type_id, parameters) => { let type_alias = from_assoc_type_id(*assoc_type_id); @@ -1039,7 +1078,7 @@ impl HirDisplay for Ty { f.end_location_link(); // Note that the generic args for the associated type come before those for the // trait (including the self type). - hir_fmt_generics(f, parameters.as_slice(Interner), None) + hir_fmt_generics(f, parameters.as_slice(Interner), None, None) } else { let projection_ty = ProjectionTy { associated_ty_id: to_assoc_type_id(type_alias), @@ -1141,7 +1180,7 @@ impl HirDisplay for Ty { } ClosureStyle::ClosureWithSubst => { write!(f, "{{closure#{:?}}}", id.0.as_u32())?; - return hir_fmt_generics(f, substs.as_slice(Interner), None); + return hir_fmt_generics(f, substs.as_slice(Interner), None, None); } _ => (), } @@ -1177,7 +1216,7 @@ impl HirDisplay for Ty { TyKind::Placeholder(idx) => { let id = from_placeholder_idx(db, *idx); let generics = generics(db.upcast(), id.parent); - let param_data = &generics.params[id.local_id]; + let param_data = &generics[id.local_id]; match param_data { TypeOrConstParamData::TypeParamData(p) => match p.provenance { TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { @@ -1329,6 +1368,7 @@ fn hir_fmt_generics( f: &mut HirFormatter<'_>, parameters: &[GenericArg], generic_def: Option, + self_: Option<&Ty>, ) -> Result<(), HirDisplayError> { if parameters.is_empty() { return Ok(()); @@ -1348,7 +1388,7 @@ fn hir_fmt_generics( }); if !parameters_to_write.is_empty() && !only_err_lifetimes { write!(f, "<")?; - hir_fmt_generic_arguments(f, parameters_to_write)?; + hir_fmt_generic_arguments(f, parameters_to_write, self_)?; write!(f, ">")?; } @@ -1411,6 +1451,7 @@ fn generic_args_sans_defaults<'ga>( fn hir_fmt_generic_arguments( f: &mut HirFormatter<'_>, parameters: &[GenericArg], + self_: Option<&Ty>, ) -> Result<(), HirDisplayError> { let mut first = true; let lifetime_offset = parameters.iter().position(|arg| arg.lifetime(Interner).is_some()); @@ -1432,11 +1473,13 @@ fn hir_fmt_generic_arguments( continue; } - if !first { + if !mem::take(&mut first) { write!(f, ", ")?; } - first = false; - generic_arg.hir_fmt(f)?; + match self_ { + self_ @ Some(_) if generic_arg.ty(Interner) == self_ => write!(f, "Self")?, + _ => generic_arg.hir_fmt(f)?, + } } Ok(()) } @@ -1559,12 +1602,16 @@ fn write_bounds_like_dyn_trait( write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast()))?; f.end_location_link(); if is_fn_trait { - if let [_self, params @ ..] = trait_ref.substitution.as_slice(Interner) { + if let [self_, params @ ..] = trait_ref.substitution.as_slice(Interner) { if let Some(args) = params.first().and_then(|it| it.assert_ty_ref(Interner).as_tuple()) { write!(f, "(")?; - hir_fmt_generic_arguments(f, args.as_slice(Interner))?; + hir_fmt_generic_arguments( + f, + args.as_slice(Interner), + self_.ty(Interner), + )?; write!(f, ")")?; } } @@ -1574,10 +1621,10 @@ fn write_bounds_like_dyn_trait( Some(trait_.into()), trait_ref.substitution.as_slice(Interner), ); - if let [_self, params @ ..] = params { + if let [self_, params @ ..] = params { if !params.is_empty() { write!(f, "<")?; - hir_fmt_generic_arguments(f, params)?; + hir_fmt_generic_arguments(f, params, self_.ty(Interner))?; // there might be assoc type bindings, so we leave the angle brackets open angle_open = true; } @@ -1635,6 +1682,7 @@ fn write_bounds_like_dyn_trait( hir_fmt_generic_arguments( f, &proj.substitution.as_slice(Interner)[..proj_arg_count], + None, )?; write!(f, ">")?; } @@ -1691,7 +1739,8 @@ fn fmt_trait_ref( f.start_location_link(trait_.into()); write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast()))?; f.end_location_link(); - hir_fmt_generics(f, &tr.substitution.as_slice(Interner)[1..], None) + let substs = tr.substitution.as_slice(Interner); + hir_fmt_generics(f, &substs[1..], None, substs[0].ty(Interner)) } impl HirDisplay for TraitRef { @@ -1749,7 +1798,7 @@ impl HirDisplay for LifetimeData { LifetimeData::Placeholder(idx) => { let id = lt_from_placeholder_idx(f.db, *idx); let generics = generics(f.db.upcast(), id.parent); - let param_data = &generics.params[id.local_id]; + let param_data = &generics[id.local_id]; write!(f, "{}", param_data.name.display(f.db.upcast()))?; Ok(()) } @@ -1943,7 +1992,7 @@ impl HirDisplay for Path { (_, PathKind::Plain) => {} (_, PathKind::Abs) => {} (_, PathKind::Crate) => write!(f, "crate")?, - (_, PathKind::Super(0)) => write!(f, "self")?, + (_, &PathKind::SELF) => write!(f, "self")?, (_, PathKind::Super(n)) => { for i in 0..*n { if i > 0 { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs new file mode 100644 index 000000000000..ea10e6881e7f --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs @@ -0,0 +1,263 @@ +//! Utilities for working with generics. +//! +//! The layout for generics as expected by chalk are as follows: +//! - Optional Self parameter +//! - Type or Const parameters +//! - Lifetime parameters +//! - Parent parameters +//! +//! where parent follows the same scheme. +use std::ops; + +use chalk_ir::{cast::Cast as _, BoundVar, DebruijnIndex}; +use hir_def::{ + db::DefDatabase, + generics::{ + GenericParamDataRef, GenericParams, LifetimeParamData, TypeOrConstParamData, + TypeParamProvenance, + }, + ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId, + LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId, +}; +use intern::Interned; + +use crate::{db::HirDatabase, lt_to_placeholder_idx, to_placeholder_idx, Interner, Substitution}; + +pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { + let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def))); + Generics { def, params: db.generic_params(def), parent_generics } +} +#[derive(Clone, Debug)] +pub(crate) struct Generics { + def: GenericDefId, + params: Interned, + parent_generics: Option>, +} + +impl ops::Index for Generics +where + GenericParams: ops::Index, +{ + type Output = >::Output; + fn index(&self, index: T) -> &Self::Output { + &self.params[index] + } +} + +impl Generics { + pub(crate) fn def(&self) -> GenericDefId { + self.def + } + + pub(crate) fn iter_id(&self) -> impl Iterator + '_ { + self.iter_self_id().chain(self.iter_parent_id()) + } + + pub(crate) fn iter_self_id(&self) -> impl Iterator + '_ { + self.iter_self().map(|(id, _)| id) + } + + fn iter_parent_id(&self) -> impl Iterator + '_ { + self.iter_parent().map(|(id, _)| id) + } + + pub(crate) fn iter_self_type_or_consts( + &self, + ) -> impl DoubleEndedIterator { + self.params.iter_type_or_consts() + } + + /// Iterate over the params followed by the parent params. + pub(crate) fn iter( + &self, + ) -> impl DoubleEndedIterator)> + '_ { + self.iter_self().chain(self.iter_parent()) + } + + /// Iterate over the params without parent params. + pub(crate) fn iter_self( + &self, + ) -> impl DoubleEndedIterator)> + '_ { + self.params + .iter_type_or_consts() + .map(from_toc_id(self)) + .chain(self.params.iter_lt().map(from_lt_id(self))) + } + + /// Iterator over types and const params of parent. + fn iter_parent( + &self, + ) -> impl DoubleEndedIterator)> + '_ { + self.parent_generics().into_iter().flat_map(|it| { + let lt_iter = it.params.iter_lt().map(from_lt_id(it)); + it.params.iter_type_or_consts().map(from_toc_id(it)).chain(lt_iter) + }) + } + + /// Returns total number of generic parameters in scope, including those from parent. + pub(crate) fn len(&self) -> usize { + let parent = self.parent_generics().map_or(0, Generics::len); + let child = self.params.len(); + parent + child + } + + /// Returns numbers of generic parameters excluding those from parent. + pub(crate) fn len_self(&self) -> usize { + self.params.len() + } + + /// (parent total, self param, type params, const params, impl trait list, lifetimes) + pub(crate) fn provenance_split(&self) -> (usize, bool, usize, usize, usize, usize) { + let mut self_param = false; + let mut type_params = 0; + let mut impl_trait_params = 0; + let mut const_params = 0; + self.params.iter_type_or_consts().for_each(|(_, data)| match data { + TypeOrConstParamData::TypeParamData(p) => match p.provenance { + TypeParamProvenance::TypeParamList => type_params += 1, + TypeParamProvenance::TraitSelf => self_param |= true, + TypeParamProvenance::ArgumentImplTrait => impl_trait_params += 1, + }, + TypeOrConstParamData::ConstParamData(_) => const_params += 1, + }); + + let lifetime_params = self.params.iter_lt().count(); + + let parent_len = self.parent_generics().map_or(0, Generics::len); + (parent_len, self_param, type_params, const_params, impl_trait_params, lifetime_params) + } + + pub(crate) fn type_or_const_param_idx(&self, param: TypeOrConstParamId) -> Option { + self.find_type_or_const_param(param) + } + + fn find_type_or_const_param(&self, param: TypeOrConstParamId) -> Option { + if param.parent == self.def { + let idx = param.local_id.into_raw().into_u32() as usize; + debug_assert!(idx <= self.params.type_or_consts.len()); + Some(idx) + } else { + debug_assert_eq!(self.parent_generics().map(|it| it.def), Some(param.parent)); + self.parent_generics() + .and_then(|g| g.find_type_or_const_param(param)) + // Remember that parent parameters come after parameters for self. + .map(|idx| self.len_self() + idx) + } + } + + pub(crate) fn lifetime_idx(&self, lifetime: LifetimeParamId) -> Option { + self.find_lifetime(lifetime) + } + + fn find_lifetime(&self, lifetime: LifetimeParamId) -> Option { + if lifetime.parent == self.def { + let idx = lifetime.local_id.into_raw().into_u32() as usize; + debug_assert!(idx <= self.params.lifetimes.len()); + Some(self.params.type_or_consts.len() + idx) + } else { + debug_assert_eq!(self.parent_generics().map(|it| it.def), Some(lifetime.parent)); + self.parent_generics() + .and_then(|g| g.find_lifetime(lifetime)) + .map(|idx| self.len_self() + idx) + } + } + + pub(crate) fn parent_generics(&self) -> Option<&Generics> { + self.parent_generics.as_deref() + } + + pub(crate) fn parent_or_self(&self) -> &Generics { + self.parent_generics.as_deref().unwrap_or(self) + } + + /// Returns a Substitution that replaces each parameter by a bound variable. + pub(crate) fn bound_vars_subst( + &self, + db: &dyn HirDatabase, + debruijn: DebruijnIndex, + ) -> Substitution { + Substitution::from_iter( + Interner, + self.iter_id().enumerate().map(|(idx, id)| match id { + GenericParamId::ConstParamId(id) => BoundVar::new(debruijn, idx) + .to_const(Interner, db.const_param_ty(id)) + .cast(Interner), + GenericParamId::TypeParamId(_) => { + BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner) + } + GenericParamId::LifetimeParamId(_) => { + BoundVar::new(debruijn, idx).to_lifetime(Interner).cast(Interner) + } + }), + ) + } + + /// Returns a Substitution that replaces each parameter by itself (i.e. `Ty::Param`). + pub(crate) fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution { + Substitution::from_iter( + Interner, + self.iter_id().map(|id| match id { + GenericParamId::TypeParamId(id) => { + to_placeholder_idx(db, id.into()).to_ty(Interner).cast(Interner) + } + GenericParamId::ConstParamId(id) => to_placeholder_idx(db, id.into()) + .to_const(Interner, db.const_param_ty(id)) + .cast(Interner), + GenericParamId::LifetimeParamId(id) => { + lt_to_placeholder_idx(db, id).to_lifetime(Interner).cast(Interner) + } + }), + ) + } +} + +fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option { + let container = match def { + GenericDefId::FunctionId(it) => it.lookup(db).container, + GenericDefId::TypeAliasId(it) => it.lookup(db).container, + GenericDefId::ConstId(it) => it.lookup(db).container, + GenericDefId::EnumVariantId(it) => return Some(it.lookup(db).parent.into()), + GenericDefId::AdtId(_) + | GenericDefId::TraitId(_) + | GenericDefId::ImplId(_) + | GenericDefId::TraitAliasId(_) => return None, + }; + + match container { + ItemContainerId::ImplId(it) => Some(it.into()), + ItemContainerId::TraitId(it) => Some(it.into()), + ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None, + } +} + +fn from_toc_id<'a>( + it: &'a Generics, +) -> impl Fn( + (LocalTypeOrConstParamId, &'a TypeOrConstParamData), +) -> (GenericParamId, GenericParamDataRef<'a>) { + move |(local_id, p): (_, _)| { + let id = TypeOrConstParamId { parent: it.def, local_id }; + match p { + TypeOrConstParamData::TypeParamData(p) => ( + GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)), + GenericParamDataRef::TypeParamData(p), + ), + TypeOrConstParamData::ConstParamData(p) => ( + GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)), + GenericParamDataRef::ConstParamData(p), + ), + } + } +} + +fn from_lt_id<'a>( + it: &'a Generics, +) -> impl Fn((LocalLifetimeParamId, &'a LifetimeParamData)) -> (GenericParamId, GenericParamDataRef<'a>) +{ + move |(local_id, p): (_, _)| { + ( + GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }), + GenericParamDataRef::LifetimeParamData(p), + ) + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 6f2f70dd40a7..96431ba4ce9a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -49,6 +49,7 @@ use hir_def::{ use hir_expand::name::{name, Name}; use indexmap::IndexSet; use la_arena::{ArenaMap, Entry}; +use once_cell::unsync::OnceCell; use rustc_hash::{FxHashMap, FxHashSet}; use stdx::{always, never}; use triomphe::Arc; @@ -56,14 +57,15 @@ use triomphe::Arc; use crate::{ db::HirDatabase, error_lifetime, fold_tys, + generics::Generics, infer::{coerce::CoerceMany, unify::InferenceTable}, lower::ImplTraitLoweringMode, to_assoc_type_id, traits::FnTrait, - utils::{Generics, InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder}, + utils::{InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder}, AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, Goal, ImplTraitId, - ImplTraitIdx, InEnvironment, Interner, Lifetime, OpaqueTyId, ProjectionTy, Substitution, - TraitEnvironment, Ty, TyBuilder, TyExt, + ImplTraitIdx, InEnvironment, Interner, Lifetime, OpaqueTyId, ParamLoweringMode, ProjectionTy, + Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, }; // This lint has a false positive here. See the link below for details. @@ -79,7 +81,7 @@ pub(crate) use closure::{CaptureKind, CapturedItem, CapturedItemWithoutTy}; /// The entry point of type inference. pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc { - let _p = tracing::span!(tracing::Level::INFO, "infer_query").entered(); + let _p = tracing::info_span!("infer_query").entered(); let resolver = def.resolver(db.upcast()); let body = db.body(def); let mut ctx = InferenceContext::new(db, def, &body, resolver); @@ -526,6 +528,7 @@ pub(crate) struct InferenceContext<'a> { pub(crate) owner: DefWithBodyId, pub(crate) body: &'a Body, pub(crate) resolver: Resolver, + generics: OnceCell>, table: unify::InferenceTable<'a>, /// The traits in scope, disregarding block modules. This is used for caching purposes. traits_in_scope: FxHashSet, @@ -611,6 +614,7 @@ impl<'a> InferenceContext<'a> { ) -> Self { let trait_env = db.trait_environment_for_body(owner); InferenceContext { + generics: OnceCell::new(), result: InferenceResult::default(), table: unify::InferenceTable::new(db, trait_env), tuple_field_accesses_rev: Default::default(), @@ -632,8 +636,14 @@ impl<'a> InferenceContext<'a> { } } - pub(crate) fn generics(&self) -> Option { - Some(crate::utils::generics(self.db.upcast(), self.resolver.generic_def()?)) + pub(crate) fn generics(&self) -> Option<&Generics> { + self.generics + .get_or_init(|| { + self.resolver + .generic_def() + .map(|def| crate::generics::generics(self.db.upcast(), def)) + }) + .as_ref() } // FIXME: This function should be private in module. It is currently only used in the consteval, since we need @@ -781,7 +791,8 @@ impl<'a> InferenceContext<'a> { fn collect_fn(&mut self, func: FunctionId) { let data = self.db.function_data(func); - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, func.into()) + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()) + .with_type_param_mode(ParamLoweringMode::Placeholder) .with_impl_trait_mode(ImplTraitLoweringMode::Param); let mut param_tys = data.params.iter().map(|type_ref| ctx.lower_ty(type_ref)).collect::>(); @@ -816,6 +827,7 @@ impl<'a> InferenceContext<'a> { let return_ty = &*data.ret_type; let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()) + .with_type_param_mode(ParamLoweringMode::Placeholder) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); let return_ty = ctx.lower_ty(return_ty); let return_ty = self.insert_type_vars(return_ty); @@ -1263,7 +1275,7 @@ impl<'a> InferenceContext<'a> { forbid_unresolved_segments((ty, Some(var.into())), unresolved) } TypeNs::SelfType(impl_id) => { - let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); + let generics = crate::generics::generics(self.db.upcast(), impl_id.into()); let substs = generics.placeholder_subst(self.db); let mut ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index a25498eff333..b7c7b6654536 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -22,11 +22,13 @@ use stdx::never; use crate::{ db::{HirDatabase, InternedClosure}, - error_lifetime, from_chalk_trait_id, from_placeholder_idx, make_binders, + error_lifetime, from_chalk_trait_id, from_placeholder_idx, + generics::Generics, + make_binders, mir::{BorrowKind, MirSpan, MutBorrowKind, ProjectionElem}, to_chalk_trait_id, traits::FnTrait, - utils::{self, elaborate_clause_supertraits, Generics}, + utils::{self, elaborate_clause_supertraits}, Adjust, Adjustment, AliasEq, AliasTy, Binders, BindingMode, ChalkTraitId, ClosureId, DynTy, DynTyExt, FnAbi, FnPointer, FnSig, Interner, OpaqueTy, ProjectionTyExt, Substitution, Ty, TyExt, WhereClause, @@ -337,7 +339,7 @@ impl CapturedItemWithoutTy { fn replace_placeholder_with_binder(ctx: &mut InferenceContext<'_>, ty: Ty) -> Binders { struct Filler<'a> { db: &'a dyn HirDatabase, - generics: Generics, + generics: &'a Generics, } impl FallibleTypeFolder for Filler<'_> { type Error = (); @@ -380,7 +382,7 @@ impl CapturedItemWithoutTy { }; let filler = &mut Filler { db: ctx.db, generics }; let result = ty.clone().try_fold_with(filler, DebruijnIndex::INNERMOST).unwrap_or(ty); - make_binders(ctx.db, &filler.generics, result) + make_binders(ctx.db, filler.generics, result) } } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 4c12786362f0..95f28531acfe 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -24,6 +24,7 @@ use crate::{ consteval, db::{InternedClosure, InternedCoroutine}, error_lifetime, + generics::{generics, Generics}, infer::{ coerce::{CoerceMany, CoercionCause}, find_continuable, @@ -39,7 +40,6 @@ use crate::{ primitive::{self, UintTy}, static_lifetime, to_chalk_trait_id, traits::FnTrait, - utils::{generics, Generics}, Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, FnAbi, FnPointer, FnSig, FnSubst, Interner, Rawness, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, @@ -1830,13 +1830,13 @@ impl InferenceContext<'_> { ) -> Substitution { let ( parent_params, - self_params, + has_self_param, type_params, const_params, impl_trait_params, lifetime_params, ) = def_generics.provenance_split(); - assert_eq!(self_params, 0); // method shouldn't have another Self param + assert!(!has_self_param); // method shouldn't have another Self param let total_len = parent_params + type_params + const_params + impl_trait_params + lifetime_params; let mut substs = Vec::with_capacity(total_len); @@ -1844,13 +1844,11 @@ impl InferenceContext<'_> { // handle provided arguments if let Some(generic_args) = generic_args { // if args are provided, it should be all of them, but we can't rely on that - for (arg, kind_id) in generic_args - .args - .iter() - .take(type_params + const_params + lifetime_params) - .zip(def_generics.iter_id()) + let self_params = type_params + const_params + lifetime_params; + for (arg, kind_id) in + generic_args.args.iter().zip(def_generics.iter_self_id()).take(self_params) { - if let Some(g) = generic_arg_to_chalk( + let arg = generic_arg_to_chalk( self.db, kind_id, arg, @@ -1869,9 +1867,8 @@ impl InferenceContext<'_> { ) }, |this, lt_ref| this.make_lifetime(lt_ref), - ) { - substs.push(g); - } + ); + substs.push(arg); } }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs index 9a1835b625b3..d876008cd581 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs @@ -12,11 +12,10 @@ use stdx::never; use crate::{ builder::ParamKind, consteval, error_lifetime, + generics::generics, method_resolution::{self, VisibleFromModule}, - to_chalk_trait_id, - utils::generics, - InferenceDiagnostic, Interner, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, - TyKind, ValueTyDefId, + to_chalk_trait_id, InferenceDiagnostic, Interner, Substitution, TraitRef, TraitRefExt, Ty, + TyBuilder, TyExt, TyKind, ValueTyDefId, }; use super::{ExprOrPatId, InferenceContext}; @@ -64,7 +63,7 @@ impl InferenceContext<'_> { it.into() } ValueNs::ImplSelf(impl_id) => { - let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); + let generics = crate::generics::generics(self.db.upcast(), impl_id.into()); let substs = generics.placeholder_subst(self.db); let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs); if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 36e3a458898d..ed4d55d20377 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -613,8 +613,7 @@ impl<'a> InferenceTable<'a> { } pub(crate) fn resolve_obligations_as_possible(&mut self) { - let _span = - tracing::span!(tracing::Level::INFO, "resolve_obligations_as_possible").entered(); + let _span = tracing::info_span!("resolve_obligations_as_possible").entered(); let mut changed = true; let mut obligations = mem::take(&mut self.resolve_obligations_buffer); while mem::take(&mut changed) { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs index 7546369d8d47..f5fb2ffd7817 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs @@ -15,7 +15,7 @@ use crate::{ // FIXME: Turn this into a query, it can be quite slow /// Checks whether a type is visibly uninhabited from a particular module. pub(crate) fn is_ty_uninhabited_from(db: &dyn HirDatabase, ty: &Ty, target_mod: ModuleId) -> bool { - let _p = tracing::span!(tracing::Level::INFO, "is_ty_uninhabited_from", ?ty).entered(); + let _p = tracing::info_span!("is_ty_uninhabited_from", ?ty).entered(); let mut uninhabited_from = UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() }; let inhabitedness = ty.visit_with(&mut uninhabited_from, DebruijnIndex::INNERMOST); @@ -30,7 +30,7 @@ pub(crate) fn is_enum_variant_uninhabited_from( subst: &Substitution, target_mod: ModuleId, ) -> bool { - let _p = tracing::span!(tracing::Level::INFO, "is_enum_variant_uninhabited_from").entered(); + let _p = tracing::info_span!("is_enum_variant_uninhabited_from").entered(); let mut uninhabited_from = UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 26a839f0e9fa..5e33e1285ee5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -22,6 +22,7 @@ extern crate ra_ap_rustc_pattern_analysis as rustc_pattern_analysis; mod builder; mod chalk_db; mod chalk_ext; +mod generics; mod infer; mod inhabitedness; mod interner; @@ -52,7 +53,7 @@ use std::{ hash::{BuildHasherDefault, Hash}, }; -use base_db::salsa::impl_intern_value_trivial; +use base_db::salsa::InternValueTrivial; use chalk_ir::{ fold::{Shift, TypeFoldable}, interner::HasInterner, @@ -67,11 +68,10 @@ use rustc_hash::{FxHashMap, FxHashSet}; use syntax::ast::{make, ConstArg}; use traits::FnTrait; use triomphe::Arc; -use utils::Generics; use crate::{ - consteval::unknown_const, db::HirDatabase, display::HirDisplay, infer::unify::InferenceTable, - utils::generics, + consteval::unknown_const, db::HirDatabase, display::HirDisplay, generics::Generics, + infer::unify::InferenceTable, }; pub use autoderef::autoderef; @@ -289,7 +289,7 @@ impl Hash for ConstScalar { /// Return an index of a parameter in the generic type parameter list by it's id. pub fn param_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option { - generics(db.upcast(), id.parent).type_or_const_param_idx(id) + generics::generics(db.upcast(), id.parent).type_or_const_param_idx(id) } pub(crate) fn wrap_empty_binders(value: T) -> Binders @@ -330,18 +330,15 @@ pub(crate) fn make_single_type_binders>( ) } -pub(crate) fn make_binders_with_count>( +pub(crate) fn make_binders>( db: &dyn HirDatabase, - count: usize, generics: &Generics, value: T, ) -> Binders { - let it = generics.iter_id().take(count); - Binders::new( VariableKinds::from_iter( Interner, - it.map(|x| match x { + generics.iter_id().map(|x| match x { hir_def::GenericParamId::ConstParamId(id) => { chalk_ir::VariableKind::Const(db.const_param_ty(id)) } @@ -355,14 +352,6 @@ pub(crate) fn make_binders_with_count>( ) } -pub(crate) fn make_binders>( - db: &dyn HirDatabase, - generics: &Generics, - value: T, -) -> Binders { - make_binders_with_count(db, usize::MAX, generics, value) -} - // FIXME: get rid of this, just replace it by FnPointer /// A function signature as seen by type inference: Several parameter types and /// one return type. @@ -524,14 +513,16 @@ pub type PolyFnSig = Binders; impl CallableSig { pub fn from_params_and_return( - mut params: Vec, + params: impl ExactSizeIterator, ret: Ty, is_varargs: bool, safety: Safety, abi: FnAbi, ) -> CallableSig { - params.push(ret); - CallableSig { params_and_return: params.into(), is_varargs, safety, abi } + let mut params_and_return = Vec::with_capacity(params.len() + 1); + params_and_return.extend(params); + params_and_return.push(ret); + CallableSig { params_and_return: params_and_return.into(), is_varargs, safety, abi } } pub fn from_def(db: &dyn HirDatabase, def: FnDefId, substs: &Substitution) -> CallableSig { @@ -606,7 +597,7 @@ pub enum ImplTraitId { AssociatedTypeImplTrait(hir_def::TypeAliasId, ImplTraitIdx), AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId), } -impl_intern_value_trivial!(ImplTraitId); +impl InternValueTrivial for ImplTraitId {} #[derive(PartialEq, Eq, Debug, Hash)] pub struct ImplTraits { @@ -946,8 +937,7 @@ pub fn callable_sig_from_fn_trait( .as_tuple()? .iter(Interner) .map(|it| it.assert_ty_ref(Interner)) - .cloned() - .collect(); + .cloned(); return Some(( fn_x, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 04ace3820219..96f545415e23 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -8,10 +8,11 @@ use std::{ cell::{Cell, RefCell, RefMut}, iter, + ops::{self, Not as _}, }; use base_db::{ - salsa::{impl_intern_value_trivial, Cycle}, + salsa::{Cycle, InternValueTrivial}, CrateId, }; use chalk_ir::{ @@ -45,7 +46,9 @@ use hir_def::{ use hir_expand::{name::Name, ExpandResult}; use intern::Interned; use la_arena::{Arena, ArenaMap}; +use once_cell::unsync::OnceCell; use rustc_hash::FxHashSet; +use rustc_pattern_analysis::Captures; use smallvec::SmallVec; use stdx::{impl_from, never}; use syntax::ast; @@ -58,12 +61,13 @@ use crate::{ unknown_const_as_generic, }, db::HirDatabase, - error_lifetime, make_binders, + error_lifetime, + generics::{generics, Generics}, + make_binders, mapping::{from_chalk_trait_id, lt_to_placeholder_idx, ToChalk}, static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, utils::{ - self, all_super_trait_refs, associated_type_by_name_including_super_traits, generics, - Generics, InTypeConstIdMetadata, + all_super_trait_refs, associated_type_by_name_including_super_traits, InTypeConstIdMetadata, }, AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, ConstScalar, DebruijnIndex, DynTy, FnAbi, FnPointer, FnSig, FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime, @@ -121,6 +125,7 @@ impl ImplTraitLoweringState { pub struct TyLoweringContext<'a> { pub db: &'a dyn HirDatabase, resolver: &'a Resolver, + generics: OnceCell>, in_binders: DebruijnIndex, // FIXME: Should not be an `Option` but `Resolver` currently does not return owners in all cases // where expected @@ -152,6 +157,7 @@ impl<'a> TyLoweringContext<'a> { Self { db, resolver, + generics: OnceCell::new(), owner, in_binders, impl_trait_mode, @@ -174,6 +180,7 @@ impl<'a> TyLoweringContext<'a> { impl_trait_mode, expander: RefCell::new(expander), unsized_types: RefCell::new(unsized_types), + generics: self.generics.clone(), ..*self }; let result = f(&new_ctx); @@ -245,8 +252,10 @@ impl<'a> TyLoweringContext<'a> { ) } - fn generics(&self) -> Option { - Some(generics(self.db.upcast(), self.resolver.generic_def()?)) + fn generics(&self) -> Option<&Generics> { + self.generics + .get_or_init(|| self.resolver.generic_def().map(|def| generics(self.db.upcast(), def))) + .as_ref() } pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option) { @@ -374,7 +383,7 @@ impl<'a> TyLoweringContext<'a> { counter.set(idx + count_impl_traits(type_ref) as u16); let ( _parent_params, - self_params, + self_param, type_params, const_params, _impl_trait_params, @@ -385,7 +394,7 @@ impl<'a> TyLoweringContext<'a> { .provenance_split(); TyKind::BoundVar(BoundVar::new( self.in_binders, - idx as usize + self_params + type_params + const_params, + idx as usize + self_param as usize + type_params + const_params, )) .intern(Interner) } @@ -416,9 +425,9 @@ impl<'a> TyLoweringContext<'a> { }; let ty = { let macro_call = macro_call.to_node(self.db.upcast()); - let resolver = |path| { + let resolver = |path: &_| { self.resolver - .resolve_path_as_macro(self.db.upcast(), &path, Some(MacroSubNs::Bang)) + .resolve_path_as_macro(self.db.upcast(), path, Some(MacroSubNs::Bang)) .map(|(it, _)| it) }; match expander.enter_expand::(self.db.upcast(), macro_call, resolver) @@ -705,7 +714,8 @@ impl<'a> TyLoweringContext<'a> { None, ); - let len_self = utils::generics(self.db.upcast(), associated_ty.into()).len_self(); + let len_self = + crate::generics::generics(self.db.upcast(), associated_ty.into()).len_self(); let substs = Substitution::from_iter( Interner, @@ -815,14 +825,14 @@ impl<'a> TyLoweringContext<'a> { let def_generics = generics(self.db.upcast(), def); let ( parent_params, - self_params, + self_param, type_params, const_params, impl_trait_params, lifetime_params, ) = def_generics.provenance_split(); let item_len = - self_params + type_params + const_params + impl_trait_params + lifetime_params; + self_param as usize + type_params + const_params + impl_trait_params + lifetime_params; let total_len = parent_params + item_len; let ty_error = TyKind::Error.intern(Interner).cast(Interner); @@ -830,18 +840,16 @@ impl<'a> TyLoweringContext<'a> { let mut def_generic_iter = def_generics.iter_id(); let fill_self_params = || { - for x in explicit_self_ty - .into_iter() - .map(|x| x.cast(Interner)) - .chain(iter::repeat(ty_error.clone())) - .take(self_params) - { + if self_param { + let self_ty = + explicit_self_ty.map(|x| x.cast(Interner)).unwrap_or_else(|| ty_error.clone()); + if let Some(id) = def_generic_iter.next() { assert!(matches!( id, GenericParamId::TypeParamId(_) | GenericParamId::LifetimeParamId(_) )); - substs.push(x); + substs.push(self_ty); } } }; @@ -852,11 +860,11 @@ impl<'a> TyLoweringContext<'a> { fill_self_params(); } let expected_num = if generic_args.has_self_type { - self_params + type_params + const_params + self_param as usize + type_params + const_params } else { type_params + const_params }; - let skip = if generic_args.has_self_type && self_params == 0 { 1 } else { 0 }; + let skip = if generic_args.has_self_type && !self_param { 1 } else { 0 }; // if args are provided, it should be all of them, but we can't rely on that for arg in generic_args .args @@ -866,7 +874,7 @@ impl<'a> TyLoweringContext<'a> { .take(expected_num) { if let Some(id) = def_generic_iter.next() { - if let Some(x) = generic_arg_to_chalk( + let arg = generic_arg_to_chalk( self.db, id, arg, @@ -874,13 +882,9 @@ impl<'a> TyLoweringContext<'a> { |_, type_ref| self.lower_ty(type_ref), |_, const_ref, ty| self.lower_const(const_ref, ty), |_, lifetime_ref| self.lower_lifetime(lifetime_ref), - ) { - had_explicit_args = true; - substs.push(x); - } else { - // we just filtered them out - never!("Unexpected lifetime argument"); - } + ); + had_explicit_args = true; + substs.push(arg); } } @@ -893,7 +897,7 @@ impl<'a> TyLoweringContext<'a> { // Taking into the fact that def_generic_iter will always have lifetimes at the end // Should have some test cases tho to test this behaviour more properly if let Some(id) = def_generic_iter.next() { - if let Some(x) = generic_arg_to_chalk( + let arg = generic_arg_to_chalk( self.db, id, arg, @@ -901,13 +905,9 @@ impl<'a> TyLoweringContext<'a> { |_, type_ref| self.lower_ty(type_ref), |_, const_ref, ty| self.lower_const(const_ref, ty), |_, lifetime_ref| self.lower_lifetime(lifetime_ref), - ) { - had_explicit_args = true; - substs.push(x); - } else { - // Never return a None explicitly - never!("Unexpected None by generic_arg_to_chalk"); - } + ); + had_explicit_args = true; + substs.push(arg); } } } else { @@ -1176,7 +1176,7 @@ impl<'a> TyLoweringContext<'a> { let ty = if let Some(target_param_idx) = target_param_idx { let mut counter = 0; let generics = self.generics().expect("generics in scope"); - for (idx, data) in generics.params.type_or_consts.iter() { + for (idx, data) in generics.iter_self_type_or_consts() { // Count the number of `impl Trait` things that appear before // the target of our `bound`. // Our counter within `impl_trait_mode` should be that number @@ -1478,7 +1478,7 @@ fn named_associated_type_shorthand_candidates( // Handle `Self::Type` referring to own associated type in trait definitions if let GenericDefId::TraitId(trait_id) = param_id.parent() { let trait_generics = generics(db.upcast(), trait_id.into()); - if trait_generics.params[param_id.local_id()].is_trait_self() { + if trait_generics[param_id.local_id()].is_trait_self() { let def_generics = generics(db.upcast(), def); let starting_idx = match def { GenericDefId::TraitId(_) => 0, @@ -1596,14 +1596,20 @@ pub(crate) fn generic_predicates_for_param_query( .collect(); let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); - let explicitly_unsized_tys = ctx.unsized_types.into_inner(); - if let Some(implicitly_sized_predicates) = - implicitly_sized_clauses(db, param_id.parent, &explicitly_unsized_tys, &subst, &resolver) - { - predicates.extend( - implicitly_sized_predicates - .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))), - ); + if !subst.is_empty(Interner) { + let explicitly_unsized_tys = ctx.unsized_types.into_inner(); + if let Some(implicitly_sized_predicates) = implicitly_sized_clauses( + db, + param_id.parent, + &explicitly_unsized_tys, + &subst, + &resolver, + ) { + predicates.extend( + implicitly_sized_predicates + .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))), + ); + }; } predicates.into() } @@ -1666,14 +1672,17 @@ pub(crate) fn trait_environment_query( } let subst = generics(db.upcast(), def).placeholder_subst(db); - let explicitly_unsized_tys = ctx.unsized_types.into_inner(); - if let Some(implicitly_sized_clauses) = - implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver) - { - clauses.extend( - implicitly_sized_clauses - .map(|pred| pred.cast::(Interner).into_from_env_clause(Interner)), - ); + if !subst.is_empty(Interner) { + let explicitly_unsized_tys = ctx.unsized_types.into_inner(); + if let Some(implicitly_sized_clauses) = + implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver) + { + clauses.extend( + implicitly_sized_clauses.map(|pred| { + pred.cast::(Interner).into_from_env_clause(Interner) + }), + ); + }; } let env = chalk_ir::Environment::new(Interner).add_clauses(Interner, clauses); @@ -1681,20 +1690,32 @@ pub(crate) fn trait_environment_query( TraitEnvironment::new(resolver.krate(), None, traits_in_scope.into_boxed_slice(), env) } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct GenericPredicates(Option]>>); + +impl ops::Deref for GenericPredicates { + type Target = [Binders]; + + fn deref(&self) -> &Self::Target { + self.0.as_deref().unwrap_or(&[]) + } +} + /// Resolve the where clause(s) of an item with generics. pub(crate) fn generic_predicates_query( db: &dyn HirDatabase, def: GenericDefId, -) -> Arc<[Binders]> { +) -> GenericPredicates { let resolver = def.resolver(db.upcast()); - let ctx = if let GenericDefId::FunctionId(_) = def { - TyLoweringContext::new(db, &resolver, def.into()) - .with_impl_trait_mode(ImplTraitLoweringMode::Variable) - .with_type_param_mode(ParamLoweringMode::Variable) - } else { - TyLoweringContext::new(db, &resolver, def.into()) - .with_type_param_mode(ParamLoweringMode::Variable) + let (impl_trait_lowering, param_lowering) = match def { + GenericDefId::FunctionId(_) => { + (ImplTraitLoweringMode::Variable, ParamLoweringMode::Variable) + } + _ => (ImplTraitLoweringMode::Disallowed, ParamLoweringMode::Variable), }; + let ctx = TyLoweringContext::new(db, &resolver, def.into()) + .with_impl_trait_mode(impl_trait_lowering) + .with_type_param_mode(param_lowering); let generics = generics(db.upcast(), def); let mut predicates = resolver @@ -1705,27 +1726,29 @@ pub(crate) fn generic_predicates_query( .collect::>(); let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); - let explicitly_unsized_tys = ctx.unsized_types.into_inner(); - if let Some(implicitly_sized_predicates) = - implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver) - { - predicates.extend( - implicitly_sized_predicates - .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))), - ); + if !subst.is_empty(Interner) { + let explicitly_unsized_tys = ctx.unsized_types.into_inner(); + if let Some(implicitly_sized_predicates) = + implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver) + { + predicates.extend( + implicitly_sized_predicates + .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))), + ); + }; } - predicates.into() + GenericPredicates(predicates.is_empty().not().then(|| predicates.into())) } /// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound. /// Exception is Self of a trait def. -fn implicitly_sized_clauses<'a>( +fn implicitly_sized_clauses<'a, 'subst: 'a>( db: &dyn HirDatabase, def: GenericDefId, explicitly_unsized_tys: &'a FxHashSet, - substitution: &'a Substitution, + substitution: &'subst Substitution, resolver: &Resolver, -) -> Option + 'a> { +) -> Option + Captures<'a> + Captures<'subst>> { let is_trait_def = matches!(def, GenericDefId::TraitId(..)); let generic_args = &substitution.as_slice(Interner)[is_trait_def as usize..]; let sized_trait = db @@ -1746,71 +1769,84 @@ fn implicitly_sized_clauses<'a>( }) } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct GenericDefaults(Option]>>); + +impl ops::Deref for GenericDefaults { + type Target = [Binders]; + + fn deref(&self) -> &Self::Target { + self.0.as_deref().unwrap_or(&[]) + } +} + /// Resolve the default type params from generics -pub(crate) fn generic_defaults_query( - db: &dyn HirDatabase, - def: GenericDefId, -) -> Arc<[Binders]> { - let resolver = def.resolver(db.upcast()); - let ctx = TyLoweringContext::new(db, &resolver, def.into()) - .with_type_param_mode(ParamLoweringMode::Variable); +pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> GenericDefaults { let generic_params = generics(db.upcast(), def); + if generic_params.len() == 0 { + return GenericDefaults(None); + } + let resolver = def.resolver(db.upcast()); let parent_start_idx = generic_params.len_self(); - let defaults = Arc::from_iter(generic_params.iter().enumerate().map(|(idx, (id, p))| { - match p { - GenericParamDataRef::TypeParamData(p) => { - let mut ty = - p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t)); - // Each default can only refer to previous parameters. - // Type variable default referring to parameter coming - // after it is forbidden (FIXME: report diagnostic) - ty = fallback_bound_vars(ty, idx, parent_start_idx); - crate::make_binders(db, &generic_params, ty.cast(Interner)) - } - GenericParamDataRef::ConstParamData(p) => { - let GenericParamId::ConstParamId(id) = id else { - unreachable!("Unexpected lifetime or type argument") - }; + let ctx = TyLoweringContext::new(db, &resolver, def.into()) + .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed) + .with_type_param_mode(ParamLoweringMode::Variable); + GenericDefaults(Some(Arc::from_iter(generic_params.iter().enumerate().map( + |(idx, (id, p))| { + match p { + GenericParamDataRef::TypeParamData(p) => { + let ty = p.default.as_ref().map_or(TyKind::Error.intern(Interner), |ty| { + // Each default can only refer to previous parameters. + // Type variable default referring to parameter coming + // after it is forbidden (FIXME: report diagnostic) + fallback_bound_vars(ctx.lower_ty(ty), idx, parent_start_idx) + }); + crate::make_binders(db, &generic_params, ty.cast(Interner)) + } + GenericParamDataRef::ConstParamData(p) => { + let GenericParamId::ConstParamId(id) = id else { + unreachable!("Unexpected lifetime or type argument") + }; - let mut val = p.default.as_ref().map_or_else( - || unknown_const_as_generic(db.const_param_ty(id)), - |c| { - let c = ctx.lower_const(c, ctx.lower_ty(&p.ty)); - c.cast(Interner) - }, - ); - // Each default can only refer to previous parameters, see above. - val = fallback_bound_vars(val, idx, parent_start_idx); - make_binders(db, &generic_params, val) + let mut val = p.default.as_ref().map_or_else( + || unknown_const_as_generic(db.const_param_ty(id)), + |c| { + let c = ctx.lower_const(c, ctx.lower_ty(&p.ty)); + c.cast(Interner) + }, + ); + // Each default can only refer to previous parameters, see above. + val = fallback_bound_vars(val, idx, parent_start_idx); + make_binders(db, &generic_params, val) + } + GenericParamDataRef::LifetimeParamData(_) => { + make_binders(db, &generic_params, error_lifetime().cast(Interner)) + } } - GenericParamDataRef::LifetimeParamData(_) => { - make_binders(db, &generic_params, error_lifetime().cast(Interner)) - } - } - })); - - defaults + }, + )))) } pub(crate) fn generic_defaults_recover( db: &dyn HirDatabase, _cycle: &Cycle, def: &GenericDefId, -) -> Arc<[Binders]> { +) -> GenericDefaults { let generic_params = generics(db.upcast(), *def); + if generic_params.len() == 0 { + return GenericDefaults(None); + } // FIXME: this code is not covered in tests. // we still need one default per parameter - let defaults = Arc::from_iter(generic_params.iter_id().map(|id| { + GenericDefaults(Some(Arc::from_iter(generic_params.iter_id().map(|id| { let val = match id { GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner), GenericParamId::ConstParamId(id) => unknown_const_as_generic(db.const_param_ty(id)), GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner), }; crate::make_binders(db, &generic_params, val) - })); - - defaults + })))) } fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { @@ -1819,7 +1855,7 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { let ctx_params = TyLoweringContext::new(db, &resolver, def.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Variable) .with_type_param_mode(ParamLoweringMode::Variable); - let params = data.params.iter().map(|tr| ctx_params.lower_ty(tr)).collect::>(); + let params = data.params.iter().map(|tr| ctx_params.lower_ty(tr)); let ctx_ret = TyLoweringContext::new(db, &resolver, def.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) .with_type_param_mode(ParamLoweringMode::Variable); @@ -1873,7 +1909,7 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS let resolver = def.resolver(db.upcast()); let ctx = TyLoweringContext::new(db, &resolver, AdtId::from(def).into()) .with_type_param_mode(ParamLoweringMode::Variable); - let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::>(); + let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)); let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders(); Binders::new( binders, @@ -1905,7 +1941,7 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) let resolver = def.resolver(db.upcast()); let ctx = TyLoweringContext::new(db, &resolver, DefWithBodyId::VariantId(def).into()) .with_type_param_mode(ParamLoweringMode::Variable); - let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::>(); + let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)); let (ret, binders) = type_for_adt(db, def.lookup(db.upcast()).parent.into()).into_value_and_skipped_binders(); Binders::new( @@ -1965,7 +2001,9 @@ pub enum CallableDefId { StructId(StructId), EnumVariantId(EnumVariantId), } -impl_intern_value_trivial!(CallableDefId); + +impl InternValueTrivial for CallableDefId {} + impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId); impl From for ModuleDefId { fn from(def: CallableDefId) -> ModuleDefId { @@ -2166,7 +2204,6 @@ pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mut /// Checks if the provided generic arg matches its expected kind, then lower them via /// provided closures. Use unknown if there was kind mismatch. /// -/// Returns `Some` of the lowered generic arg. `None` if the provided arg is a lifetime. pub(crate) fn generic_arg_to_chalk<'a, T>( db: &dyn HirDatabase, kind_id: GenericParamId, @@ -2175,7 +2212,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a, for_const: impl FnOnce(&mut T, &ConstRef, Ty) -> Const + 'a, for_lifetime: impl FnOnce(&mut T, &LifetimeRef) -> Lifetime + 'a, -) -> Option { +) -> crate::GenericArg { let kind = match kind_id { GenericParamId::TypeParamId(_) => ParamKind::Type, GenericParamId::ConstParamId(id) => { @@ -2184,7 +2221,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( } GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime, }; - Some(match (arg, kind) { + match (arg, kind) { (GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, type_ref).cast(Interner), (GenericArg::Const(c), ParamKind::Const(c_ty)) => for_const(this, c, c_ty).cast(Interner), (GenericArg::Lifetime(lifetime_ref), ParamKind::Lifetime) => { @@ -2197,11 +2234,12 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( // as types. Maybe here is not the best place to do it, but // it works. if let TypeRef::Path(p) = t { - let p = p.mod_path()?; - if p.kind == PathKind::Plain { - if let [n] = p.segments() { - let c = ConstRef::Path(n.clone()); - return Some(for_const(this, &c, c_ty).cast(Interner)); + if let Some(p) = p.mod_path() { + if p.kind == PathKind::Plain { + if let [n] = p.segments() { + let c = ConstRef::Path(n.clone()); + return for_const(this, &c, c_ty).cast(Interner); + } } } } @@ -2210,17 +2248,17 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( (GenericArg::Lifetime(_), ParamKind::Const(c_ty)) => unknown_const_as_generic(c_ty), (GenericArg::Type(_), ParamKind::Lifetime) => error_lifetime().cast(Interner), (GenericArg::Const(_), ParamKind::Lifetime) => error_lifetime().cast(Interner), - }) + } } -pub(crate) fn const_or_path_to_chalk( +pub(crate) fn const_or_path_to_chalk<'g>( db: &dyn HirDatabase, resolver: &Resolver, owner: TypeOwnerId, expected_ty: Ty, value: &ConstRef, mode: ParamLoweringMode, - args: impl FnOnce() -> Option, + args: impl FnOnce() -> Option<&'g Generics>, debruijn: DebruijnIndex, ) -> Const { match value { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index cb56a6f0bfe7..5ce124d6d27f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -144,8 +144,7 @@ pub struct TraitImpls { impl TraitImpls { pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc { - let _p = - tracing::span!(tracing::Level::INFO, "trait_impls_in_crate_query", ?krate).entered(); + let _p = tracing::info_span!("trait_impls_in_crate_query", ?krate).entered(); let mut impls = FxHashMap::default(); Self::collect_def_map(db, &mut impls, &db.crate_def_map(krate)); @@ -157,7 +156,7 @@ impl TraitImpls { db: &dyn HirDatabase, block: BlockId, ) -> Option> { - let _p = tracing::span!(tracing::Level::INFO, "trait_impls_in_block_query").entered(); + let _p = tracing::info_span!("trait_impls_in_block_query").entered(); let mut impls = FxHashMap::default(); Self::collect_def_map(db, &mut impls, &db.block_def_map(block)); @@ -173,8 +172,7 @@ impl TraitImpls { db: &dyn HirDatabase, krate: CrateId, ) -> Arc<[Arc]> { - let _p = - tracing::span!(tracing::Level::INFO, "trait_impls_in_deps_query", ?krate).entered(); + let _p = tracing::info_span!("trait_impls_in_deps_query", ?krate).entered(); let crate_graph = db.crate_graph(); Arc::from_iter( @@ -280,8 +278,7 @@ pub struct InherentImpls { impl InherentImpls { pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc { - let _p = - tracing::span!(tracing::Level::INFO, "inherent_impls_in_crate_query", ?krate).entered(); + let _p = tracing::info_span!("inherent_impls_in_crate_query", ?krate).entered(); let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() }; let crate_def_map = db.crate_def_map(krate); @@ -295,7 +292,7 @@ impl InherentImpls { db: &dyn HirDatabase, block: BlockId, ) -> Option> { - let _p = tracing::span!(tracing::Level::INFO, "inherent_impls_in_block_query").entered(); + let _p = tracing::info_span!("inherent_impls_in_block_query").entered(); let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() }; let block_def_map = db.block_def_map(block); @@ -368,7 +365,7 @@ pub(crate) fn incoherent_inherent_impl_crates( krate: CrateId, fp: TyFingerprint, ) -> SmallVec<[CrateId; 2]> { - let _p = tracing::span!(tracing::Level::INFO, "incoherent_inherent_impl_crates").entered(); + let _p = tracing::info_span!("incoherent_inherent_impl_crates").entered(); let mut res = SmallVec::new(); let crate_graph = db.crate_graph(); @@ -937,8 +934,7 @@ pub fn iterate_method_candidates_dyn( mode: LookupMode, callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>, ) -> ControlFlow<()> { - let _p = tracing::span!( - tracing::Level::INFO, + let _p = tracing::info_span!( "iterate_method_candidates_dyn", ?mode, ?name, @@ -1504,7 +1500,7 @@ fn is_valid_impl_fn_candidate( } } table.run_in_snapshot(|table| { - let _p = tracing::span!(tracing::Level::INFO, "subst_for_def").entered(); + let _p = tracing::info_span!("subst_for_def").entered(); let impl_subst = TyBuilder::subst_for_def(db, impl_id, None).fill_with_inference_vars(table).build(); let expect_self_ty = db.impl_self_ty(impl_id).substitute(Interner, &impl_subst); @@ -1512,7 +1508,7 @@ fn is_valid_impl_fn_candidate( check_that!(table.unify(&expect_self_ty, self_ty)); if let Some(receiver_ty) = receiver_ty { - let _p = tracing::span!(tracing::Level::INFO, "check_receiver_ty").entered(); + let _p = tracing::info_span!("check_receiver_ty").entered(); check_that!(data.has_self_param()); let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst.clone())) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs index d51335503771..2e106877cbc2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs @@ -898,20 +898,19 @@ pub enum Rvalue { Cast(CastKind, Operand, Ty), // FIXME link to `pointer::offset` when it hits stable. - /// * `Offset` has the same semantics as `pointer::offset`, except that the second - /// parameter may be a `usize` as well. - /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats, - /// raw pointers, or function pointers and return a `bool`. The types of the operands must be - /// matching, up to the usual caveat of the lifetimes in function pointers. - /// * Left and right shift operations accept signed or unsigned integers not necessarily of the - /// same type and return a value of the same type as their LHS. Like in Rust, the RHS is - /// truncated as needed. - /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching - /// types and return a value of that type. - /// * The remaining operations accept signed integers, unsigned integers, or floats with - /// matching types and return a value of that type. + // /// * `Offset` has the same semantics as `pointer::offset`, except that the second + // /// parameter may be a `usize` as well. + // /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats, + // /// raw pointers, or function pointers and return a `bool`. The types of the operands must be + // /// matching, up to the usual caveat of the lifetimes in function pointers. + // /// * Left and right shift operations accept signed or unsigned integers not necessarily of the + // /// same type and return a value of the same type as their LHS. Like in Rust, the RHS is + // /// truncated as needed. + // /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching + // /// types and return a value of that type. + // /// * The remaining operations accept signed integers, unsigned integers, or floats with + // /// matching types and return a value of that type. //BinaryOp(BinOp, Box<(Operand, Operand)>), - /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition. /// /// When overflow checking is disabled and we are generating run-time code, the error condition diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs index 8b6936f8bc0f..878d584a4efa 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs @@ -91,7 +91,7 @@ pub fn borrowck_query( db: &dyn HirDatabase, def: DefWithBodyId, ) -> Result, MirLowerError> { - let _p = tracing::span!(tracing::Level::INFO, "borrowck_query").entered(); + let _p = tracing::info_span!("borrowck_query").entered(); let mut res = vec![]; all_mir_bodies(db, def, |body| { res.push(BorrowckResult { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index 2de1aa30c966..4ee96a66a396 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -363,7 +363,7 @@ impl MirEvalError { )?; } Either::Right(closure) => { - writeln!(f, "In {:?}", closure)?; + writeln!(f, "In {closure:?}")?; } } let source_map = db.body_with_source_map(*def).1; @@ -424,7 +424,7 @@ impl MirEvalError { | MirEvalError::StackOverflow | MirEvalError::CoerceUnsizedError(_) | MirEvalError::InternalError(_) - | MirEvalError::InvalidVTableId(_) => writeln!(f, "{:?}", err)?, + | MirEvalError::InvalidVTableId(_) => writeln!(f, "{err:?}")?, } Ok(()) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs index 4abbda56cbb4..c3b35cd553da 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs @@ -77,7 +77,7 @@ fn check_panic(ra_fixture: &str, expected_panic: &str) { let (db, file_ids) = TestDB::with_many_files(ra_fixture); let file_id = *file_ids.last().unwrap(); let e = eval_main(&db, file_id).unwrap_err(); - assert_eq!(e.is_panic().unwrap_or_else(|| panic!("unexpected error: {:?}", e)), expected_panic); + assert_eq!(e.is_panic().unwrap_or_else(|| panic!("unexpected error: {e:?}")), expected_panic); } #[test] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 151f65cfbb8e..09302846f1b3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -28,6 +28,7 @@ use crate::{ db::{HirDatabase, InternedClosure}, display::HirDisplay, error_lifetime, + generics::generics, infer::{CaptureKind, CapturedItem, TypeMismatch}, inhabitedness::is_ty_uninhabited_from, layout::LayoutError, @@ -42,7 +43,7 @@ use crate::{ }, static_lifetime, traits::FnTrait, - utils::{generics, ClosureSubst}, + utils::ClosureSubst, Adjust, Adjustment, AutoBorrow, CallableDefId, TyBuilder, TyExt, }; @@ -213,7 +214,7 @@ impl MirLowerError { | MirLowerError::LangItemNotFound(_) | MirLowerError::MutatingRvalue | MirLowerError::UnresolvedLabel - | MirLowerError::UnresolvedUpvar(_) => writeln!(f, "{:?}", self)?, + | MirLowerError::UnresolvedUpvar(_) => writeln!(f, "{self:?}")?, } Ok(()) } @@ -2133,7 +2134,7 @@ pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result format!("in type const {it:?}"), }; - let _p = tracing::span!(tracing::Level::INFO, "mir_body_query", ?detail).entered(); + let _p = tracing::info_span!("mir_body_query", ?detail).entered(); let body = db.body(def); let infer = db.infer(def); let mut result = lower_to_mir(db, def, &body, &infer, body.body_expr)?; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs index a384c9306eee..43afa6150483 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs @@ -21,8 +21,8 @@ use crate::{ consteval::{intern_const_scalar, unknown_const}, db::{HirDatabase, InternedClosure}, from_placeholder_idx, + generics::{generics, Generics}, infer::normalize, - utils::{generics, Generics}, ClosureId, Const, Interner, ProjectionTy, Substitution, TraitEnvironment, Ty, TyKind, }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index 02f2cd761599..4283a94657b9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -108,7 +108,7 @@ pub(crate) fn trait_solve_query( GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_owned(), _ => "??".to_owned(), }; - let _p = tracing::span!(tracing::Level::INFO, "trait_solve_query", ?detail).entered(); + let _p = tracing::info_span!("trait_solve_query", ?detail).entered(); tracing::info!("trait_solve_query({:?})", goal.value.goal); if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq { @@ -140,7 +140,7 @@ fn solve( block: Option, goal: &chalk_ir::UCanonical>>, ) -> Option> { - let _p = tracing::span!(tracing::Level::INFO, "solve", ?krate, ?block).entered(); + let _p = tracing::info_span!("solve", ?krate, ?block).entered(); let context = ChalkContext { db, krate, block }; tracing::debug!("solve goal: {:?}", goal); let mut solver = create_chalk_solver(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 42c7a8403283..969999cdb844 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -5,25 +5,19 @@ use std::{hash::Hash, iter}; use base_db::CrateId; use chalk_ir::{ - cast::Cast, fold::{FallibleTypeFolder, Shift}, - BoundVar, DebruijnIndex, + DebruijnIndex, }; use hir_def::{ db::DefDatabase, - generics::{ - GenericParamDataRef, GenericParams, LifetimeParamData, TypeOrConstParamData, - TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, - }, + generics::{WherePredicate, WherePredicateTypeTarget}, lang_item::LangItem, resolver::{HasResolver, TypeNs}, type_ref::{TraitBoundModifier, TypeRef}, - ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, GenericParamId, ItemContainerId, - LifetimeParamId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId, TypeOrConstParamId, - TypeParamId, + EnumId, EnumVariantId, FunctionId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId, + TypeOrConstParamId, }; use hir_expand::name::Name; -use intern::Interned; use rustc_abi::TargetDataLayout; use rustc_hash::FxHashSet; use smallvec::{smallvec, SmallVec}; @@ -161,7 +155,7 @@ impl Iterator for ClauseElaborator<'_> { fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) { let resolver = trait_.resolver(db); let generic_params = db.generic_params(trait_.into()); - let trait_self = generic_params.find_trait_self_param(); + let trait_self = generic_params.trait_self_param(); generic_params .where_predicates .iter() @@ -194,7 +188,7 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(Tra fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef, cb: impl FnMut(TraitRef)) { let generic_params = db.generic_params(trait_ref.hir_trait_id().into()); - let trait_self = match generic_params.find_trait_self_param() { + let trait_self = match generic_params.trait_self_param() { Some(p) => TypeOrConstParamId { parent: trait_ref.hir_trait_id().into(), local_id: p }, None => return, }; @@ -226,11 +220,6 @@ pub(super) fn associated_type_by_name_including_super_traits( }) } -pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { - let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def))); - Generics { def, params: db.generic_params(def), parent_generics } -} - /// It is a bit different from the rustc equivalent. Currently it stores: /// - 0: the function signature, encoded as a function pointer type /// - 1..n: generics of the parent @@ -262,278 +251,14 @@ impl<'a> ClosureSubst<'a> { } } -#[derive(Clone, Debug)] -pub(crate) struct Generics { - def: GenericDefId, - pub(crate) params: Interned, - parent_generics: Option>, -} - -impl Generics { - pub(crate) fn iter_id(&self) -> impl Iterator + '_ { - self.iter().map(|(id, _)| id) - } - - pub(crate) fn def(&self) -> GenericDefId { - self.def - } - - /// Iterator over types and const params of self, then parent. - pub(crate) fn iter<'a>( - &'a self, - ) -> impl DoubleEndedIterator)> + 'a { - let from_toc_id = |it: &'a Generics| { - move |(local_id, p): (_, &'a TypeOrConstParamData)| { - let id = TypeOrConstParamId { parent: it.def, local_id }; - match p { - TypeOrConstParamData::TypeParamData(p) => ( - GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)), - GenericParamDataRef::TypeParamData(p), - ), - TypeOrConstParamData::ConstParamData(p) => ( - GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)), - GenericParamDataRef::ConstParamData(p), - ), - } - } - }; - - let from_lt_id = |it: &'a Generics| { - move |(local_id, p): (_, &'a LifetimeParamData)| { - ( - GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }), - GenericParamDataRef::LifetimeParamData(p), - ) - } - }; - - let lt_iter = self.params.iter_lt().map(from_lt_id(self)); - self.params - .iter_type_or_consts() - .map(from_toc_id(self)) - .chain(lt_iter) - .chain(self.iter_parent()) - } - - /// Iterate over types and const params without parent params. - pub(crate) fn iter_self<'a>( - &'a self, - ) -> impl DoubleEndedIterator)> + 'a { - let from_toc_id = |it: &'a Generics| { - move |(local_id, p): (_, &'a TypeOrConstParamData)| { - let id = TypeOrConstParamId { parent: it.def, local_id }; - match p { - TypeOrConstParamData::TypeParamData(p) => ( - GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)), - GenericParamDataRef::TypeParamData(p), - ), - TypeOrConstParamData::ConstParamData(p) => ( - GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)), - GenericParamDataRef::ConstParamData(p), - ), - } - } - }; - - let from_lt_id = |it: &'a Generics| { - move |(local_id, p): (_, &'a LifetimeParamData)| { - ( - GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }), - GenericParamDataRef::LifetimeParamData(p), - ) - } - }; - - self.params - .iter_type_or_consts() - .map(from_toc_id(self)) - .chain(self.params.iter_lt().map(from_lt_id(self))) - } - - /// Iterator over types and const params of parent. - pub(crate) fn iter_parent( - &self, - ) -> impl DoubleEndedIterator)> + '_ { - self.parent_generics().into_iter().flat_map(|it| { - let from_toc_id = move |(local_id, p)| { - let p: &_ = p; - let id = TypeOrConstParamId { parent: it.def, local_id }; - match p { - TypeOrConstParamData::TypeParamData(p) => ( - GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)), - GenericParamDataRef::TypeParamData(p), - ), - TypeOrConstParamData::ConstParamData(p) => ( - GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)), - GenericParamDataRef::ConstParamData(p), - ), - } - }; - - let from_lt_id = move |(local_id, p): (_, _)| { - ( - GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }), - GenericParamDataRef::LifetimeParamData(p), - ) - }; - let lt_iter = it.params.iter_lt().map(from_lt_id); - it.params.iter_type_or_consts().map(from_toc_id).chain(lt_iter) - }) - } - - /// Returns total number of generic parameters in scope, including those from parent. - pub(crate) fn len(&self) -> usize { - let parent = self.parent_generics().map_or(0, Generics::len); - let child = self.params.len(); - parent + child - } - - /// Returns numbers of generic parameters and lifetimes excluding those from parent. - pub(crate) fn len_self(&self) -> usize { - self.params.len() - } - - /// Returns number of generic parameter excluding those from parent - fn len_type_and_const_params(&self) -> usize { - self.params.type_or_consts.len() - } - - /// (parent total, self param, type params, const params, impl trait list, lifetimes) - pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize, usize) { - let mut self_params = 0; - let mut type_params = 0; - let mut impl_trait_params = 0; - let mut const_params = 0; - let mut lifetime_params = 0; - self.params.iter_type_or_consts().for_each(|(_, data)| match data { - TypeOrConstParamData::TypeParamData(p) => match p.provenance { - TypeParamProvenance::TypeParamList => type_params += 1, - TypeParamProvenance::TraitSelf => self_params += 1, - TypeParamProvenance::ArgumentImplTrait => impl_trait_params += 1, - }, - TypeOrConstParamData::ConstParamData(_) => const_params += 1, - }); - - self.params.iter_lt().for_each(|(_, _)| lifetime_params += 1); - - let parent_len = self.parent_generics().map_or(0, Generics::len); - (parent_len, self_params, type_params, const_params, impl_trait_params, lifetime_params) - } - - pub(crate) fn type_or_const_param_idx(&self, param: TypeOrConstParamId) -> Option { - Some(self.find_type_or_const_param(param)?.0) - } - - fn find_type_or_const_param( - &self, - param: TypeOrConstParamId, - ) -> Option<(usize, &TypeOrConstParamData)> { - if param.parent == self.def { - let idx = param.local_id.into_raw().into_u32() as usize; - if idx >= self.params.type_or_consts.len() { - return None; - } - Some((idx, &self.params.type_or_consts[param.local_id])) - } else { - self.parent_generics() - .and_then(|g| g.find_type_or_const_param(param)) - // Remember that parent parameters come after parameters for self. - .map(|(idx, data)| (self.len_self() + idx, data)) - } - } - - pub(crate) fn lifetime_idx(&self, lifetime: LifetimeParamId) -> Option { - Some(self.find_lifetime(lifetime)?.0) - } - - fn find_lifetime(&self, lifetime: LifetimeParamId) -> Option<(usize, &LifetimeParamData)> { - if lifetime.parent == self.def { - let idx = lifetime.local_id.into_raw().into_u32() as usize; - if idx >= self.params.lifetimes.len() { - return None; - } - Some(( - self.len_type_and_const_params() + idx, - &self.params.lifetimes[lifetime.local_id], - )) - } else { - self.parent_generics() - .and_then(|g| g.find_lifetime(lifetime)) - .map(|(idx, data)| (self.len_self() + idx, data)) - } - } - - pub(crate) fn parent_generics(&self) -> Option<&Generics> { - self.parent_generics.as_deref() - } - - pub(crate) fn parent_or_self(&self) -> &Generics { - self.parent_generics.as_deref().unwrap_or(self) - } - - /// Returns a Substitution that replaces each parameter by a bound variable. - pub(crate) fn bound_vars_subst( - &self, - db: &dyn HirDatabase, - debruijn: DebruijnIndex, - ) -> Substitution { - Substitution::from_iter( - Interner, - self.iter_id().enumerate().map(|(idx, id)| match id { - GenericParamId::ConstParamId(id) => BoundVar::new(debruijn, idx) - .to_const(Interner, db.const_param_ty(id)) - .cast(Interner), - GenericParamId::TypeParamId(_) => { - BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner) - } - GenericParamId::LifetimeParamId(_) => { - BoundVar::new(debruijn, idx).to_lifetime(Interner).cast(Interner) - } - }), - ) - } - - /// Returns a Substitution that replaces each parameter by itself (i.e. `Ty::Param`). - pub(crate) fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution { - Substitution::from_iter( - Interner, - self.iter_id().map(|id| match id { - GenericParamId::TypeParamId(id) => { - crate::to_placeholder_idx(db, id.into()).to_ty(Interner).cast(Interner) - } - GenericParamId::ConstParamId(id) => crate::to_placeholder_idx(db, id.into()) - .to_const(Interner, db.const_param_ty(id)) - .cast(Interner), - GenericParamId::LifetimeParamId(id) => { - crate::lt_to_placeholder_idx(db, id).to_lifetime(Interner).cast(Interner) - } - }), - ) - } -} - -fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option { - let container = match def { - GenericDefId::FunctionId(it) => it.lookup(db).container, - GenericDefId::TypeAliasId(it) => it.lookup(db).container, - GenericDefId::ConstId(it) => it.lookup(db).container, - GenericDefId::EnumVariantId(it) => return Some(it.lookup(db).parent.into()), - GenericDefId::AdtId(_) - | GenericDefId::TraitId(_) - | GenericDefId::ImplId(_) - | GenericDefId::TraitAliasId(_) => return None, - }; - - match container { - ItemContainerId::ImplId(it) => Some(it.into()), - ItemContainerId::TraitId(it) => Some(it.into()), - ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None, - } -} - pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool { let data = db.function_data(func); if data.has_unsafe_kw() { + // Functions that are `#[rustc_deprecated_safe_2024]` are safe to call before 2024. + if db.attrs(func.into()).by_key("rustc_deprecated_safe_2024").exists() { + // FIXME: Properly check the caller span and mark it as unsafe after 2024. + return false; + } return true; } diff --git a/src/tools/rust-analyzer/crates/hir/Cargo.toml b/src/tools/rust-analyzer/crates/hir/Cargo.toml index 6d7ecd1e50b6..edf26a07a744 100644 --- a/src/tools/rust-analyzer/crates/hir/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir/Cargo.toml @@ -27,6 +27,7 @@ cfg.workspace = true hir-def.workspace = true hir-expand.workspace = true hir-ty.workspace = true +intern.workspace = true stdx.workspace = true syntax.workspace = true tt.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs index c7502890ef41..7b3ff7b06458 100644 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs @@ -307,7 +307,7 @@ fn doc_modpath_from_str(link: &str) -> Option { let kind = match parts.next()? { "" => PathKind::Abs, "crate" => PathKind::Crate, - "self" => PathKind::Super(0), + "self" => PathKind::SELF, "super" => { let mut deg = 1; for segment in parts.by_ref() { diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index c276e87786dd..79069ed66bf0 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -3,7 +3,8 @@ use either::Either; use hir_def::{ data::adt::{StructKind, VariantData}, generics::{ - TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, + GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate, + WherePredicateTypeTarget, }, lang_item::LangItem, type_ref::{TypeBound, TypeRef}, @@ -16,10 +17,12 @@ use hir_ty::{ }, AliasEq, AliasTy, Interner, ProjectionTyExt, TraitRefExt, TyKind, WhereClause, }; +use intern::Interned; +use itertools::Itertools; use crate::{ Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Enum, ExternCrateDecl, - Field, Function, GenericParam, HasCrate, HasVisibility, LifetimeParam, Macro, Module, + Field, Function, GenericParam, HasCrate, HasVisibility, Impl, LifetimeParam, Macro, Module, SelfParam, Static, Struct, Trait, TraitAlias, TupleField, TyBuilder, Type, TypeAlias, TypeOrConstParam, TypeParam, Union, Variant, }; @@ -30,12 +33,42 @@ impl HirDisplay for Function { let data = db.function_data(self.id); let container = self.as_assoc_item(db).map(|it| it.container(db)); let mut module = self.module(db); + + // Write container (trait or impl) + let container_params = match container { + Some(AssocItemContainer::Trait(trait_)) => { + let params = f.db.generic_params(trait_.id.into()); + if f.show_container_bounds() && !params.is_empty() { + write_trait_header(&trait_, f)?; + f.write_char('\n')?; + has_disaplayable_predicates(¶ms).then_some(params) + } else { + None + } + } + Some(AssocItemContainer::Impl(impl_)) => { + let params = f.db.generic_params(impl_.id.into()); + if f.show_container_bounds() && !params.is_empty() { + write_impl_header(&impl_, f)?; + f.write_char('\n')?; + has_disaplayable_predicates(¶ms).then_some(params) + } else { + None + } + } + None => None, + }; + + // Write signature of the function + + // Block-local impls are "hoisted" to the nearest (non-block) module. if let Some(AssocItemContainer::Impl(_)) = container { - // Block-local impls are "hoisted" to the nearest (non-block) module. module = module.nearest_non_block_module(db); } let module_id = module.id; + write_visibility(module_id, self.visibility(db), f)?; + if data.has_default_kw() { f.write_str("default ")?; } @@ -116,12 +149,41 @@ impl HirDisplay for Function { } } - write_where_clause(GenericDefId::FunctionId(self.id), f)?; - + // Write where clauses + let has_written_where = write_where_clause(GenericDefId::FunctionId(self.id), f)?; + if let Some(container_params) = container_params { + if !has_written_where { + f.write_str("\nwhere")?; + } + let container_name = match container.unwrap() { + AssocItemContainer::Trait(_) => "trait", + AssocItemContainer::Impl(_) => "impl", + }; + write!(f, "\n // Bounds from {container_name}:",)?; + write_where_predicates(&container_params, f)?; + } Ok(()) } } +fn write_impl_header(impl_: &Impl, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { + let db = f.db; + + f.write_str("impl")?; + let def_id = GenericDefId::ImplId(impl_.id); + write_generic_params(def_id, f)?; + + if let Some(trait_) = impl_.trait_(db) { + let trait_data = db.trait_data(trait_.id); + write!(f, " {} for", trait_data.name.display(db.upcast()))?; + } + + f.write_char(' ')?; + impl_.self_ty(db).hir_fmt(f)?; + + Ok(()) +} + impl HirDisplay for SelfParam { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { let data = f.db.function_data(self.func); @@ -188,7 +250,7 @@ impl HirDisplay for Struct { StructKind::Record => { let has_where_clause = write_where_clause(def_id, f)?; if let Some(limit) = f.entity_limit { - display_fields(&self.fields(f.db), has_where_clause, limit, false, f)?; + write_fields(&self.fields(f.db), has_where_clause, limit, false, f)?; } } StructKind::Unit => _ = write_where_clause(def_id, f)?, @@ -208,7 +270,7 @@ impl HirDisplay for Enum { let has_where_clause = write_where_clause(def_id, f)?; if let Some(limit) = f.entity_limit { - display_variants(&self.variants(f.db), has_where_clause, limit, f)?; + write_variants(&self.variants(f.db), has_where_clause, limit, f)?; } Ok(()) @@ -225,13 +287,13 @@ impl HirDisplay for Union { let has_where_clause = write_where_clause(def_id, f)?; if let Some(limit) = f.entity_limit { - display_fields(&self.fields(f.db), has_where_clause, limit, false, f)?; + write_fields(&self.fields(f.db), has_where_clause, limit, false, f)?; } Ok(()) } } -fn display_fields( +fn write_fields( fields: &[Field], has_where_clause: bool, limit: usize, @@ -242,11 +304,7 @@ fn display_fields( let (indent, separator) = if in_line { ("", ' ') } else { (" ", '\n') }; f.write_char(if !has_where_clause { ' ' } else { separator })?; if count == 0 { - if fields.is_empty() { - f.write_str("{}")?; - } else { - f.write_str("{ /* … */ }")?; - } + f.write_str(if fields.is_empty() { "{}" } else { "{ /* … */ }" })?; } else { f.write_char('{')?; @@ -255,14 +313,11 @@ fn display_fields( for field in &fields[..count] { f.write_str(indent)?; field.hir_fmt(f)?; - f.write_char(',')?; - f.write_char(separator)?; + write!(f, ",{separator}")?; } if fields.len() > count { - f.write_str(indent)?; - f.write_str("/* … */")?; - f.write_char(separator)?; + write!(f, "{indent}/* … */{separator}")?; } } @@ -272,7 +327,7 @@ fn display_fields( Ok(()) } -fn display_variants( +fn write_variants( variants: &[Variant], has_where_clause: bool, limit: usize, @@ -281,30 +336,22 @@ fn display_variants( let count = variants.len().min(limit); f.write_char(if !has_where_clause { ' ' } else { '\n' })?; if count == 0 { - if variants.is_empty() { - f.write_str("{}")?; - } else { - f.write_str("{ /* … */ }")?; - } + let variants = if variants.is_empty() { "{}" } else { "{ /* … */ }" }; + f.write_str(variants)?; } else { f.write_str("{\n")?; for variant in &variants[..count] { - f.write_str(" ")?; - write!(f, "{}", variant.name(f.db).display(f.db.upcast()))?; + write!(f, " {}", variant.name(f.db).display(f.db.upcast()))?; match variant.kind(f.db) { StructKind::Tuple => { - if variant.fields(f.db).is_empty() { - f.write_str("()")?; - } else { - f.write_str("( /* … */ )")?; - } + let fields_str = + if variant.fields(f.db).is_empty() { "()" } else { "( /* … */ )" }; + f.write_str(fields_str)?; } StructKind::Record => { - if variant.fields(f.db).is_empty() { - f.write_str(" {}")?; - } else { - f.write_str(" { /* … */ }")?; - } + let fields_str = + if variant.fields(f.db).is_empty() { " {}" } else { " { /* … */ }" }; + f.write_str(fields_str)?; } StructKind::Unit => {} } @@ -357,7 +404,7 @@ impl HirDisplay for Variant { } VariantData::Record(_) => { if let Some(limit) = f.entity_limit { - display_fields(&self.fields(f.db), false, limit, true, f)?; + write_fields(&self.fields(f.db), false, limit, true, f)?; } } } @@ -554,104 +601,98 @@ fn write_where_clause( f: &mut HirFormatter<'_>, ) -> Result { let params = f.db.generic_params(def); - - // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`. - let is_unnamed_type_target = |target: &WherePredicateTypeTarget| match target { - WherePredicateTypeTarget::TypeRef(_) => false, - WherePredicateTypeTarget::TypeOrConstParam(id) => { - params.type_or_consts[*id].name().is_none() - } - }; - - let has_displayable_predicate = params - .where_predicates - .iter() - .any(|pred| { - !matches!(pred, WherePredicate::TypeBound { target, .. } if is_unnamed_type_target(target)) - }); - - if !has_displayable_predicate { + if !has_disaplayable_predicates(¶ms) { return Ok(false); } - let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target { - WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f), - WherePredicateTypeTarget::TypeOrConstParam(id) => { - match ¶ms.type_or_consts[*id].name() { - Some(name) => write!(f, "{}", name.display(f.db.upcast())), - None => f.write_str("{unnamed}"), - } - } - }; - f.write_str("\nwhere")?; - - for (pred_idx, pred) in params.where_predicates.iter().enumerate() { - let prev_pred = - if pred_idx == 0 { None } else { Some(¶ms.where_predicates[pred_idx - 1]) }; - - let new_predicate = |f: &mut HirFormatter<'_>| { - f.write_str(if pred_idx == 0 { "\n " } else { ",\n " }) - }; - - match pred { - WherePredicate::TypeBound { target, .. } if is_unnamed_type_target(target) => {} - WherePredicate::TypeBound { target, bound } => { - if matches!(prev_pred, Some(WherePredicate::TypeBound { target: target_, .. }) if target_ == target) - { - f.write_str(" + ")?; - } else { - new_predicate(f)?; - write_target(target, f)?; - f.write_str(": ")?; - } - bound.hir_fmt(f)?; - } - WherePredicate::Lifetime { target, bound } => { - if matches!(prev_pred, Some(WherePredicate::Lifetime { target: target_, .. }) if target_ == target) - { - write!(f, " + {}", bound.name.display(f.db.upcast()))?; - } else { - new_predicate(f)?; - write!( - f, - "{}: {}", - target.name.display(f.db.upcast()), - bound.name.display(f.db.upcast()) - )?; - } - } - WherePredicate::ForLifetime { lifetimes, target, bound } => { - if matches!( - prev_pred, - Some(WherePredicate::ForLifetime { lifetimes: lifetimes_, target: target_, .. }) - if lifetimes_ == lifetimes && target_ == target, - ) { - f.write_str(" + ")?; - } else { - new_predicate(f)?; - f.write_str("for<")?; - for (idx, lifetime) in lifetimes.iter().enumerate() { - if idx != 0 { - f.write_str(", ")?; - } - write!(f, "{}", lifetime.display(f.db.upcast()))?; - } - f.write_str("> ")?; - write_target(target, f)?; - f.write_str(": ")?; - } - bound.hir_fmt(f)?; - } - } - } - - // End of final predicate. There must be at least one predicate here. - f.write_char(',')?; + write_where_predicates(¶ms, f)?; Ok(true) } +fn has_disaplayable_predicates(params: &Interned) -> bool { + params.where_predicates.iter().any(|pred| { + !matches!( + pred, + WherePredicate::TypeBound { target: WherePredicateTypeTarget::TypeOrConstParam(id), .. } + if params.type_or_consts[*id].name().is_none() + ) + }) +} + +fn write_where_predicates( + params: &Interned, + f: &mut HirFormatter<'_>, +) -> Result<(), HirDisplayError> { + use WherePredicate::*; + + // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`. + let is_unnamed_type_target = + |params: &Interned, target: &WherePredicateTypeTarget| { + matches!(target, + WherePredicateTypeTarget::TypeOrConstParam(id) if params.type_or_consts[*id].name().is_none() + ) + }; + + let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target { + WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f), + WherePredicateTypeTarget::TypeOrConstParam(id) => match params.type_or_consts[*id].name() { + Some(name) => write!(f, "{}", name.display(f.db.upcast())), + None => f.write_str("{unnamed}"), + }, + }; + + let check_same_target = |pred1: &WherePredicate, pred2: &WherePredicate| match (pred1, pred2) { + (TypeBound { target: t1, .. }, TypeBound { target: t2, .. }) => t1 == t2, + (Lifetime { target: t1, .. }, Lifetime { target: t2, .. }) => t1 == t2, + ( + ForLifetime { lifetimes: l1, target: t1, .. }, + ForLifetime { lifetimes: l2, target: t2, .. }, + ) => l1 == l2 && t1 == t2, + _ => false, + }; + + let mut iter = params.where_predicates.iter().peekable(); + while let Some(pred) = iter.next() { + if matches!(pred, TypeBound { target, .. } if is_unnamed_type_target(params, target)) { + continue; + } + + f.write_str("\n ")?; + match pred { + TypeBound { target, bound } => { + write_target(target, f)?; + f.write_str(": ")?; + bound.hir_fmt(f)?; + } + Lifetime { target, bound } => { + let target = target.name.display(f.db.upcast()); + let bound = bound.name.display(f.db.upcast()); + write!(f, "{target}: {bound}")?; + } + ForLifetime { lifetimes, target, bound } => { + let lifetimes = lifetimes.iter().map(|it| it.display(f.db.upcast())).join(", "); + write!(f, "for<{lifetimes}> ")?; + write_target(target, f)?; + f.write_str(": ")?; + bound.hir_fmt(f)?; + } + } + + while let Some(nxt) = iter.next_if(|nxt| check_same_target(pred, nxt)) { + f.write_str(" + ")?; + match nxt { + TypeBound { bound, .. } | ForLifetime { bound, .. } => bound.hir_fmt(f)?, + Lifetime { bound, .. } => write!(f, "{}", bound.name.display(f.db.upcast()))?, + } + } + f.write_str(",")?; + } + + Ok(()) +} + impl HirDisplay for Const { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { let db = f.db; @@ -689,17 +730,8 @@ impl HirDisplay for Static { impl HirDisplay for Trait { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; - let data = f.db.trait_data(self.id); - if data.is_unsafe { - f.write_str("unsafe ")?; - } - if data.is_auto { - f.write_str("auto ")?; - } - write!(f, "trait {}", data.name.display(f.db.upcast()))?; + write_trait_header(self, f)?; let def_id = GenericDefId::TraitId(self.id); - write_generic_params(def_id, f)?; let has_where_clause = write_where_clause(def_id, f)?; if let Some(limit) = f.entity_limit { @@ -735,6 +767,20 @@ impl HirDisplay for Trait { } } +fn write_trait_header(trait_: &Trait, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { + write_visibility(trait_.module(f.db).id, trait_.visibility(f.db), f)?; + let data = f.db.trait_data(trait_.id); + if data.is_unsafe { + f.write_str("unsafe ")?; + } + if data.is_auto { + f.write_str("auto ")?; + } + write!(f, "trait {}", data.name.display(f.db.upcast()))?; + write_generic_params(GenericDefId::TraitId(trait_.id), f)?; + Ok(()) +} + impl HirDisplay for TraitAlias { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; diff --git a/src/tools/rust-analyzer/crates/hir/src/has_source.rs b/src/tools/rust-analyzer/crates/hir/src/has_source.rs index 7cdcdd76d185..929c8b3c09e3 100644 --- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs @@ -8,13 +8,14 @@ use hir_def::{ Lookup, MacroId, VariantId, }; use hir_expand::{HirFileId, InFile}; +use hir_ty::{db::InternedClosure, CallableDefId}; use syntax::ast; use tt::TextRange; use crate::{ - db::HirDatabase, Adt, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl, - LifetimeParam, LocalSource, Macro, Module, Static, Struct, Trait, TraitAlias, TypeAlias, - TypeOrConstParam, Union, Variant, + db::HirDatabase, Adt, Callee, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl, + Label, LifetimeParam, LocalSource, Macro, Module, Param, SelfParam, Static, Struct, Trait, + TraitAlias, TypeAlias, TypeOrConstParam, Union, Variant, }; pub trait HasSource { @@ -25,7 +26,7 @@ pub trait HasSource { /// /// The current some implementations can return `InFile` instead of `Option`. /// But we made this method `Option` to support rlib in the future - /// by https://github.com/rust-lang/rust-analyzer/issues/6913 + /// by fn source(self, db: &dyn HirDatabase) -> Option>; } @@ -202,7 +203,7 @@ impl HasSource for TypeOrConstParam { type Ast = Either; fn source(self, db: &dyn HirDatabase) -> Option> { let child_source = self.id.parent.child_source(db.upcast()); - Some(child_source.map(|it| it[self.id.local_id].clone())) + child_source.map(|it| it.get(self.id.local_id).cloned()).transpose() } } @@ -210,7 +211,7 @@ impl HasSource for LifetimeParam { type Ast = ast::LifetimeParam; fn source(self, db: &dyn HirDatabase) -> Option> { let child_source = self.id.parent.child_source(db.upcast()); - Some(child_source.map(|it| it[self.id.local_id].clone())) + child_source.map(|it| it.get(self.id.local_id).cloned()).transpose() } } @@ -222,6 +223,68 @@ impl HasSource for LocalSource { } } +impl HasSource for Param { + type Ast = Either; + + fn source(self, db: &dyn HirDatabase) -> Option> { + match self.func { + Callee::Def(CallableDefId::FunctionId(func)) => { + let InFile { file_id, value } = Function { id: func }.source(db)?; + let params = value.param_list()?; + if let Some(self_param) = params.self_param() { + if let Some(idx) = self.idx.checked_sub(1) { + params.params().nth(idx).map(Either::Right) + } else { + Some(Either::Left(self_param)) + } + } else { + params.params().nth(self.idx).map(Either::Right) + } + .map(|value| InFile { file_id, value }) + } + Callee::Closure(closure, _) => { + let InternedClosure(owner, expr_id) = db.lookup_intern_closure(closure.into()); + let (_, source_map) = db.body_with_source_map(owner); + let ast @ InFile { file_id, value } = source_map.expr_syntax(expr_id).ok()?; + let root = db.parse_or_expand(file_id); + match value.to_node(&root) { + ast::Expr::ClosureExpr(it) => it + .param_list()? + .params() + .nth(self.idx) + .map(Either::Right) + .map(|value| InFile { file_id: ast.file_id, value }), + _ => None, + } + } + _ => None, + } + } +} + +impl HasSource for SelfParam { + type Ast = ast::SelfParam; + + fn source(self, db: &dyn HirDatabase) -> Option> { + let InFile { file_id, value } = Function::from(self.func).source(db)?; + value + .param_list() + .and_then(|params| params.self_param()) + .map(|value| InFile { file_id, value }) + } +} + +impl HasSource for Label { + type Ast = ast::Label; + + fn source(self, db: &dyn HirDatabase) -> Option> { + let (_body, source_map) = db.body_with_source_map(self.parent); + let src = source_map.label_syntax(self.label_id); + let root = src.file_syntax(db.upcast()); + Some(src.map(|ast| ast.to_node(&root))) + } +} + impl HasSource for ExternCrateDecl { type Ast = ast::ExternCrate; diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 777be711a5e6..c1fe8a8b316f 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -64,7 +64,6 @@ use hir_expand::{ use hir_ty::{ all_super_traits, autoderef, check_orphan_rules, consteval::{try_const_usize, unknown_const_as_generic, ConstExt}, - db::InternedClosure, diagnostics::BodyValidationDiagnostic, error_lifetime, known_const_to_ast, layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding}, @@ -113,7 +112,7 @@ pub use hir_ty::method_resolution::TyFingerprint; pub use { cfg::{CfgAtom, CfgExpr, CfgOptions}, hir_def::{ - attr::{builtin::AttributeTemplate, AttrSourceMap, Attrs, AttrsWithOwner}, + attr::{AttrSourceMap, Attrs, AttrsWithOwner}, data::adt::StructKind, find_path::PrefixKind, import_map, @@ -132,6 +131,7 @@ pub use { attrs::{Attr, AttrId}, change::ChangeWithProcMacros, hygiene::{marks_rev, SyntaxContextExt}, + inert_attr_macro::AttributeTemplate, name::{known, Name}, proc_macro::ProcMacros, tt, ExpandResult, HirFileId, HirFileIdExt, InFile, InMacroFile, InRealFile, MacroFileId, @@ -242,7 +242,7 @@ impl Crate { db: &dyn DefDatabase, query: import_map::Query, ) -> impl Iterator> { - let _p = tracing::span!(tracing::Level::INFO, "query_external_importables").entered(); + let _p = tracing::info_span!("query_external_importables").entered(); import_map::search_dependencies(db, self.into(), &query).into_iter().map(|item| { match ItemInNs::from(item) { ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id), @@ -551,8 +551,7 @@ impl Module { acc: &mut Vec, style_lints: bool, ) { - let _p = tracing::span!(tracing::Level::INFO, "Module::diagnostics", name = ?self.name(db)) - .entered(); + let _p = tracing::info_span!("Module::diagnostics", name = ?self.name(db)).entered(); let def_map = self.id.def_map(db.upcast()); for diag in def_map.diagnostics() { if diag.in_module != self.id.local_id { @@ -1099,6 +1098,35 @@ pub enum FieldSource { Pos(ast::TupleField), } +impl AstNode for FieldSource { + fn can_cast(kind: syntax::SyntaxKind) -> bool + where + Self: Sized, + { + ast::RecordField::can_cast(kind) || ast::TupleField::can_cast(kind) + } + + fn cast(syntax: SyntaxNode) -> Option + where + Self: Sized, + { + if ast::RecordField::can_cast(syntax.kind()) { + ::cast(syntax).map(FieldSource::Named) + } else if ast::TupleField::can_cast(syntax.kind()) { + ::cast(syntax).map(FieldSource::Pos) + } else { + None + } + } + + fn syntax(&self) -> &SyntaxNode { + match self { + FieldSource::Named(it) => it.syntax(), + FieldSource::Pos(it) => it.syntax(), + } + } +} + impl Field { pub fn name(&self, db: &dyn HirDatabase) -> Name { self.parent.variant_data(db).fields()[self.id].name.clone() @@ -1884,6 +1912,14 @@ impl Function { Type::from_value_def(db, self.id) } + pub fn fn_ptr_type(self, db: &dyn HirDatabase) -> Type { + let resolver = self.id.resolver(db.upcast()); + let substs = TyBuilder::placeholder_subst(db, self.id); + let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); + let ty = TyKind::Function(callable_sig.to_fn_ptr()).intern(Interner); + Type::new_with_resolver_inner(db, &resolver, ty) + } + /// Get this function's return type pub fn ret_type(self, db: &dyn HirDatabase) -> Type { let resolver = self.id.resolver(db.upcast()); @@ -2208,47 +2244,9 @@ impl Param { } } - pub fn pattern_source(&self, db: &dyn HirDatabase) -> Option { + pub fn pattern_source(self, db: &dyn HirDatabase) -> Option { self.source(db).and_then(|p| p.value.right()?.pat()) } - - pub fn source( - &self, - db: &dyn HirDatabase, - ) -> Option>> { - match self.func { - Callee::Def(CallableDefId::FunctionId(func)) => { - let InFile { file_id, value } = Function { id: func }.source(db)?; - let params = value.param_list()?; - if let Some(self_param) = params.self_param() { - if let Some(idx) = self.idx.checked_sub(1) { - params.params().nth(idx).map(Either::Right) - } else { - Some(Either::Left(self_param)) - } - } else { - params.params().nth(self.idx).map(Either::Right) - } - .map(|value| InFile { file_id, value }) - } - Callee::Closure(closure, _) => { - let InternedClosure(owner, expr_id) = db.lookup_intern_closure(closure.into()); - let (_, source_map) = db.body_with_source_map(owner); - let ast @ InFile { file_id, value } = source_map.expr_syntax(expr_id).ok()?; - let root = db.parse_or_expand(file_id); - match value.to_node(&root) { - ast::Expr::ClosureExpr(it) => it - .param_list()? - .params() - .nth(self.idx) - .map(Either::Right) - .map(|value| InFile { file_id: ast.file_id, value }), - _ => None, - } - } - _ => None, - } - } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -2272,14 +2270,6 @@ impl SelfParam { .unwrap_or(Access::Owned) } - pub fn source(&self, db: &dyn HirDatabase) -> Option> { - let InFile { file_id, value } = Function::from(self.func).source(db)?; - value - .param_list() - .and_then(|params| params.self_param()) - .map(|value| InFile { file_id, value }) - } - pub fn parent_fn(&self) -> Function { Function::from(self.func) } @@ -2414,9 +2404,9 @@ impl Const { let value_signed = i128::from_le_bytes(mir::pad16(b, matches!(s, Scalar::Int(_)))); if value >= 10 { - return Ok(format!("{} ({:#X})", value_signed, value)); + return Ok(format!("{value_signed} ({value:#X})")); } else { - return Ok(format!("{}", value_signed)); + return Ok(format!("{value_signed}")); } } } @@ -2746,6 +2736,12 @@ impl Macro { } } + pub fn is_asm_or_global_asm(&self, db: &dyn HirDatabase) -> bool { + matches!(self.id, MacroId::Macro2Id(it) if { + matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltIn(m) if m.is_asm()) + }) + } + pub fn is_attr(&self, db: &dyn HirDatabase) -> bool { matches!(self.kind(db), MacroKind::Attr) } @@ -2788,6 +2784,7 @@ impl From for ItemInNs { ModuleDef::Static(_) | ModuleDef::Const(_) | ModuleDef::Function(_) => { ItemInNs::Values(module_def) } + ModuleDef::Macro(it) => ItemInNs::Macros(it), _ => ItemInNs::Types(module_def), } } @@ -3381,7 +3378,7 @@ impl BuiltinAttr { } fn builtin(name: &str) -> Option { - hir_def::attr::builtin::find_builtin_attr_idx(name) + hir_expand::inert_attr_macro::find_builtin_attr_idx(name) .map(|idx| BuiltinAttr { krate: None, idx: idx as u32 }) } @@ -3389,14 +3386,18 @@ impl BuiltinAttr { // FIXME: Return a `Name` here match self.krate { Some(krate) => db.crate_def_map(krate).registered_attrs()[self.idx as usize].clone(), - None => SmolStr::new(hir_def::attr::builtin::INERT_ATTRIBUTES[self.idx as usize].name), + None => { + SmolStr::new(hir_expand::inert_attr_macro::INERT_ATTRIBUTES[self.idx as usize].name) + } } } pub fn template(&self, _: &dyn HirDatabase) -> Option { match self.krate { Some(_) => None, - None => Some(hir_def::attr::builtin::INERT_ATTRIBUTES[self.idx as usize].template), + None => { + Some(hir_expand::inert_attr_macro::INERT_ATTRIBUTES[self.idx as usize].template) + } } } } @@ -3440,13 +3441,6 @@ impl Label { let body = db.body(self.parent); body[self.label_id].name.clone() } - - pub fn source(self, db: &dyn HirDatabase) -> InFile { - let (_body, source_map) = db.body_with_source_map(self.parent); - let src = source_map.label_syntax(self.label_id); - let root = src.file_syntax(db.upcast()); - src.map(|ast| ast.to_node(&root)) - } } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -4612,8 +4606,7 @@ impl Type { name: Option<&Name>, mut callback: impl FnMut(Function) -> Option, ) -> Option { - let _p = - tracing::span!(tracing::Level::INFO, "iterate_method_candidates_with_traits").entered(); + let _p = tracing::info_span!("iterate_method_candidates_with_traits").entered(); let mut slot = None; self.iterate_method_candidates_dyn( @@ -4662,8 +4655,7 @@ impl Type { name: Option<&Name>, callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>, ) { - let _p = tracing::span!( - tracing::Level::INFO, + let _p = tracing::info_span!( "iterate_method_candidates_dyn", with_local_impls = traits_in_scope.len(), traits_in_scope = traits_in_scope.len(), @@ -4701,7 +4693,7 @@ impl Type { name: Option<&Name>, mut callback: impl FnMut(AssocItem) -> Option, ) -> Option { - let _p = tracing::span!(tracing::Level::INFO, "iterate_path_candidates").entered(); + let _p = tracing::info_span!("iterate_path_candidates").entered(); let mut slot = None; self.iterate_path_candidates_dyn( db, @@ -4768,7 +4760,7 @@ impl Type { &'a self, db: &'a dyn HirDatabase, ) -> impl Iterator + 'a { - let _p = tracing::span!(tracing::Level::INFO, "applicable_inherent_traits").entered(); + let _p = tracing::info_span!("applicable_inherent_traits").entered(); self.autoderef_(db) .filter_map(|ty| ty.dyn_trait()) .flat_map(move |dyn_trait_id| hir_ty::all_super_traits(db.upcast(), dyn_trait_id)) @@ -4776,7 +4768,7 @@ impl Type { } pub fn env_traits<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator + 'a { - let _p = tracing::span!(tracing::Level::INFO, "env_traits").entered(); + let _p = tracing::info_span!("env_traits").entered(); self.autoderef_(db) .filter(|ty| matches!(ty.kind(Interner), TyKind::Placeholder(_))) .flat_map(|ty| { diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 43de2a6ee7dc..f6c88edbff74 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -19,7 +19,11 @@ use hir_def::{ AsMacroCall, DefWithBodyId, FunctionId, MacroId, TraitId, VariantId, }; use hir_expand::{ - attrs::collect_attrs, db::ExpandDatabase, files::InRealFile, name::AsName, ExpansionInfo, + attrs::collect_attrs, + builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander}, + db::ExpandDatabase, + files::InRealFile, + name::AsName, InMacroFile, MacroCallId, MacroFileId, MacroFileIdExt, }; use itertools::Itertools; @@ -132,9 +136,6 @@ pub struct SemanticsImpl<'db> { s2d_cache: RefCell, /// Rootnode to HirFileId cache root_to_file_cache: RefCell>, - // These 2 caches are mainly useful for semantic highlighting as nothing else descends a lot of tokens - // So we might wanna move them out into something specific for semantic highlighting - expansion_info_cache: RefCell>, /// MacroCall to its expansion's MacroFileId cache macro_call_cache: RefCell, MacroFileId>>, } @@ -295,7 +296,6 @@ impl<'db> SemanticsImpl<'db> { db, s2d_cache: Default::default(), root_to_file_cache: Default::default(), - expansion_info_cache: Default::default(), macro_call_cache: Default::default(), } } @@ -314,7 +314,58 @@ impl<'db> SemanticsImpl<'db> { pub fn expand(&self, macro_call: &ast::MacroCall) -> Option { let sa = self.analyze_no_infer(macro_call.syntax())?; - let file_id = sa.expand(self.db, InFile::new(sa.file_id, macro_call))?; + + let macro_call = InFile::new(sa.file_id, macro_call); + let file_id = if let Some(call) = + ::to_def(self, macro_call) + { + call.as_macro_file() + } else { + sa.expand(self.db, macro_call)? + }; + + let node = self.parse_or_expand(file_id.into()); + Some(node) + } + + /// Expands the macro if it isn't one of the built-in ones that expand to custom syntax or dummy + /// expansions. + pub fn expand_allowed_builtins(&self, macro_call: &ast::MacroCall) -> Option { + let sa = self.analyze_no_infer(macro_call.syntax())?; + + let macro_call = InFile::new(sa.file_id, macro_call); + let file_id = if let Some(call) = + ::to_def(self, macro_call) + { + call.as_macro_file() + } else { + sa.expand(self.db, macro_call)? + }; + let macro_call = self.db.lookup_intern_macro_call(file_id.macro_call_id); + + let skip = matches!( + macro_call.def.kind, + hir_expand::MacroDefKind::BuiltIn( + _, + BuiltinFnLikeExpander::Column + | BuiltinFnLikeExpander::File + | BuiltinFnLikeExpander::ModulePath + | BuiltinFnLikeExpander::Asm + | BuiltinFnLikeExpander::LlvmAsm + | BuiltinFnLikeExpander::GlobalAsm + | BuiltinFnLikeExpander::LogSyntax + | BuiltinFnLikeExpander::TraceMacros + | BuiltinFnLikeExpander::FormatArgs + | BuiltinFnLikeExpander::FormatArgsNl + | BuiltinFnLikeExpander::ConstFormatArgs, + ) | hir_expand::MacroDefKind::BuiltInEager(_, EagerExpander::CompileError) + ); + if skip { + // these macros expand to custom builtin syntax and/or dummy things, no point in + // showing these to the user + return None; + } + let node = self.parse_or_expand(file_id.into()); Some(node) } @@ -322,7 +373,7 @@ impl<'db> SemanticsImpl<'db> { /// If `item` has an attribute macro attached to it, expands it. pub fn expand_attr_macro(&self, item: &ast::Item) -> Option { let src = self.wrap_node_infile(item.clone()); - let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src))?; + let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src.as_ref()))?; Some(self.parse_or_expand(macro_call_id.as_file())) } @@ -341,9 +392,7 @@ impl<'db> SemanticsImpl<'db> { Some( calls .into_iter() - .map(|call| { - macro_call_to_macro_id(ctx, self.db.upcast(), call?).map(|id| Macro { id }) - }) + .map(|call| macro_call_to_macro_id(ctx, call?).map(|id| Macro { id })) .collect(), ) }) @@ -403,7 +452,7 @@ impl<'db> SemanticsImpl<'db> { pub fn is_attr_macro_call(&self, item: &ast::Item) -> bool { let file_id = self.find_file(item.syntax()).file_id; - let src = InFile::new(file_id, item.clone()); + let src = InFile::new(file_id, item); self.with_ctx(|ctx| ctx.item_to_macro_call(src).is_some()) } @@ -420,7 +469,7 @@ impl<'db> SemanticsImpl<'db> { let macro_call = InFile::new(file_id, actual_macro_call); let krate = resolver.krate(); let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| { - resolver.resolve_path_as_macro_def(self.db.upcast(), &path, Some(MacroSubNs::Bang)) + resolver.resolve_path_as_macro_def(self.db.upcast(), path, Some(MacroSubNs::Bang)) })?; hir_expand::db::expand_speculative( self.db.upcast(), @@ -453,7 +502,7 @@ impl<'db> SemanticsImpl<'db> { token_to_map: SyntaxToken, ) -> Option<(SyntaxNode, SyntaxToken)> { let macro_call = self.wrap_node_infile(actual_macro_call.clone()); - let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(macro_call))?; + let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(macro_call.as_ref()))?; hir_expand::db::expand_speculative( self.db.upcast(), macro_call_id, @@ -705,8 +754,6 @@ impl<'db> SemanticsImpl<'db> { let parent = token.parent()?; let file_id = self.find_file(&parent).file_id.file_id()?; - let mut cache = self.expansion_info_cache.borrow_mut(); - // iterate related crates and find all include! invocations that include_file_id matches for (invoc, _) in self .db @@ -716,18 +763,32 @@ impl<'db> SemanticsImpl<'db> { .filter(|&(_, include_file_id)| include_file_id == file_id) { let macro_file = invoc.as_macro_file(); - let expansion_info = cache.entry(macro_file).or_insert_with(|| { - let exp_info = macro_file.expansion_info(self.db.upcast()); + let expansion_info = { + self.with_ctx(|ctx| { + ctx.cache + .expansion_info_cache + .entry(macro_file) + .or_insert_with(|| { + let exp_info = macro_file.expansion_info(self.db.upcast()); - let InMacroFile { file_id, value } = exp_info.expanded(); - self.cache(value, file_id.into()); + let InMacroFile { file_id, value } = exp_info.expanded(); + if let InFile { file_id, value: Some(value) } = exp_info.arg() { + self.cache(value.ancestors().last().unwrap(), file_id); + } + self.cache(value, file_id.into()); - exp_info - }); + exp_info + }) + .clone() + }) + }; // FIXME: uncached parse // Create the source analyzer for the macro call scope - let Some(sa) = self.analyze_no_infer(&self.parse_or_expand(expansion_info.call_file())) + let Some(sa) = expansion_info + .arg() + .value + .and_then(|it| self.analyze_no_infer(&it.ancestors().last().unwrap())) else { continue; }; @@ -758,7 +819,7 @@ impl<'db> SemanticsImpl<'db> { mut token: SyntaxToken, f: &mut dyn FnMut(InFile) -> ControlFlow<()>, ) { - let _p = tracing::span!(tracing::Level::INFO, "descend_into_macros_impl").entered(); + let _p = tracing::info_span!("descend_into_macros_impl").entered(); let (sa, span, file_id) = match token.parent().and_then(|parent| self.analyze_no_infer(&parent)) { Some(sa) => match sa.file_id.file_id() { @@ -785,23 +846,28 @@ impl<'db> SemanticsImpl<'db> { } }; - let mut cache = self.expansion_info_cache.borrow_mut(); - let mut mcache = self.macro_call_cache.borrow_mut(); + let mut m_cache = self.macro_call_cache.borrow_mut(); let def_map = sa.resolver.def_map(); let mut stack: Vec<(_, SmallVec<[_; 2]>)> = vec![(file_id, smallvec![token])]; - let mut process_expansion_for_token = |stack: &mut Vec<_>, macro_file| { - let exp_info = cache.entry(macro_file).or_insert_with(|| { - let exp_info = macro_file.expansion_info(self.db.upcast()); + let process_expansion_for_token = |stack: &mut Vec<_>, macro_file| { + let InMacroFile { file_id, value: mapped_tokens } = self.with_ctx(|ctx| { + Some( + ctx.cache + .expansion_info_cache + .entry(macro_file) + .or_insert_with(|| { + let exp_info = macro_file.expansion_info(self.db.upcast()); - let InMacroFile { file_id, value } = exp_info.expanded(); - self.cache(value, file_id.into()); + let InMacroFile { file_id, value } = exp_info.expanded(); + self.cache(value, file_id.into()); - exp_info - }); - - let InMacroFile { file_id, value: mapped_tokens } = exp_info.map_range_down(span)?; - let mapped_tokens: SmallVec<[_; 2]> = mapped_tokens.collect(); + exp_info + }) + .map_range_down(span)? + .map(SmallVec::<[_; 2]>::from_iter), + ) + })?; // we have found a mapping for the token if the vec is non-empty let res = mapped_tokens.is_empty().not().then_some(()); @@ -818,10 +884,7 @@ impl<'db> SemanticsImpl<'db> { token.parent_ancestors().filter_map(ast::Item::cast).find_map(|item| { // Don't force populate the dyn cache for items that don't have an attribute anyways item.attrs().next()?; - Some(( - ctx.item_to_macro_call(InFile::new(file_id, item.clone()))?, - item, - )) + Some((ctx.item_to_macro_call(InFile::new(file_id, &item))?, item)) }) }); if let Some((call_id, item)) = containing_attribute_macro_call { @@ -874,13 +937,20 @@ impl<'db> SemanticsImpl<'db> { return None; } let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?; - let mcall: hir_expand::files::InFileWrapper = - InFile::new(file_id, macro_call); - let file_id = match mcache.get(&mcall) { + let mcall = InFile::new(file_id, macro_call); + let file_id = match m_cache.get(&mcall) { Some(&it) => it, None => { - let it = sa.expand(self.db, mcall.as_ref())?; - mcache.insert(mcall, it); + let it = if let Some(call) = + ::to_def( + self, + mcall.as_ref(), + ) { + call.as_macro_file() + } else { + sa.expand(self.db, mcall.as_ref())? + }; + m_cache.insert(mcall, it); it } }; @@ -953,6 +1023,13 @@ impl<'db> SemanticsImpl<'db> { let helpers = def_map.derive_helpers_in_scope(InFile::new(file_id, id))?; + if !helpers.is_empty() { + let text_range = attr.syntax().text_range(); + // remove any other token in this macro input, all their mappings are the + // same as this + tokens.retain(|t| !text_range.contains_range(t.text_range())); + } + let mut res = None; for (.., derive) in helpers.iter().filter(|(helper, ..)| *helper == attr_name) @@ -1056,16 +1133,20 @@ impl<'db> SemanticsImpl<'db> { node: SyntaxNode, ) -> impl Iterator + Clone + '_ { let node = self.find_file(&node); - let db = self.db.upcast(); iter::successors(Some(node.cloned()), move |&InFile { file_id, ref value }| { match value.parent() { Some(parent) => Some(InFile::new(file_id, parent)), None => { - let call_node = file_id.macro_file()?.call_node(db); - // cache the node - // FIXME: uncached parse - self.parse_or_expand(call_node.file_id); - Some(call_node) + let macro_file = file_id.macro_file()?; + + self.with_ctx(|ctx| { + let expansion_info = ctx + .cache + .expansion_info_cache + .entry(macro_file) + .or_insert_with(|| macro_file.expansion_info(self.db.upcast())); + expansion_info.arg().map(|node| node?.parent()).transpose() + }) } } }) @@ -1090,7 +1171,7 @@ impl<'db> SemanticsImpl<'db> { .find(|tp| tp.lifetime().as_ref().map(|lt| lt.text()).as_ref() == Some(&text)) })?; let src = self.wrap_node_infile(lifetime_param); - ToDef::to_def(self, src) + ToDef::to_def(self, src.as_ref()) } pub fn resolve_label(&self, lifetime: &ast::Lifetime) -> Option